create-ej-app 12.0.0 → 14.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/cli.js +5 -4
  2. package/cli.ts +9 -4
  3. package/package.json +1 -1
  4. package/template/base/package.json +9 -15
  5. package/template/base/terraform/artifact-registry.tf +5 -0
  6. package/template/base/terraform/backend-service.tf +13 -0
  7. package/template/base/terraform/cleanup.sh +9 -0
  8. package/template/base/terraform/cloudbuild.tf +70 -0
  9. package/template/base/terraform/cloudrun.tf +68 -0
  10. package/template/base/terraform/database.tf +60 -0
  11. package/template/base/terraform/forwarding-rule.tf +43 -0
  12. package/template/base/terraform/ip-address.tf +11 -0
  13. package/template/base/terraform/network-endpoint-group.tf +11 -0
  14. package/template/base/terraform/network.tf +21 -0
  15. package/template/base/terraform/pre.sh +3 -0
  16. package/template/base/terraform/providers.tf +18 -0
  17. package/template/base/terraform/secret.txt +11 -0
  18. package/template/base/terraform/setup.sh +25 -0
  19. package/template/base/terraform/ssl-certs.tf +32 -0
  20. package/template/base/terraform/target-https-proxy copy.tf +14 -0
  21. package/template/base/terraform/target-https-proxy.tf +14 -0
  22. package/template/base/terraform/terraform.tfvars +4 -0
  23. package/template/base/terraform/url-map.tf +23 -0
  24. package/template/base/terraform/variables.tf +21 -0
  25. package/template/old/.env.example +0 -17
  26. package/template/old/.eslintrc.cjs +0 -26
  27. package/template/old/components.json +0 -17
  28. package/template/old/drizzle.config.ts +0 -11
  29. package/template/old/next.config.mjs +0 -4
  30. package/template/old/package.json +0 -87
  31. package/template/old/postcss.config.mjs +0 -8
  32. package/template/old/prettier.config.mjs +0 -11
  33. package/template/old/public/next.svg +0 -1
  34. package/template/old/public/vercel.svg +0 -1
  35. package/template/old/src/app/(app)/dashboard/layout.tsx +0 -14
  36. package/template/old/src/app/(app)/dashboard/page.tsx +0 -12
  37. package/template/old/src/app/(app)/layout.tsx +0 -125
  38. package/template/old/src/app/(app)/roles/[id]/actions.ts +0 -59
  39. package/template/old/src/app/(app)/roles/[id]/page.tsx +0 -46
  40. package/template/old/src/app/(app)/roles/[id]/render.tsx +0 -264
  41. package/template/old/src/app/(app)/roles/[id]/validation.ts +0 -22
  42. package/template/old/src/app/(app)/roles/actions.ts +0 -33
  43. package/template/old/src/app/(app)/roles/page.tsx +0 -52
  44. package/template/old/src/app/(app)/roles/render.tsx +0 -80
  45. package/template/old/src/app/(app)/settings/actions.ts +0 -17
  46. package/template/old/src/app/(app)/settings/layout.tsx +0 -14
  47. package/template/old/src/app/(app)/settings/loading.tsx +0 -28
  48. package/template/old/src/app/(app)/settings/page.tsx +0 -19
  49. package/template/old/src/app/(app)/settings/render.tsx +0 -107
  50. package/template/old/src/app/(app)/settings/validation.ts +0 -5
  51. package/template/old/src/app/(app)/tasks/[id]/actions.ts +0 -92
  52. package/template/old/src/app/(app)/tasks/[id]/page.tsx +0 -59
  53. package/template/old/src/app/(app)/tasks/[id]/render.tsx +0 -482
  54. package/template/old/src/app/(app)/tasks/[id]/validation.ts +0 -18
  55. package/template/old/src/app/(app)/tasks/actions.ts +0 -39
  56. package/template/old/src/app/(app)/tasks/page.tsx +0 -59
  57. package/template/old/src/app/(app)/tasks/render.tsx +0 -129
  58. package/template/old/src/app/(app)/tasks/statusEnum.ts +0 -3
  59. package/template/old/src/app/(app)/users/[id]/actions.ts +0 -68
  60. package/template/old/src/app/(app)/users/[id]/page.tsx +0 -39
  61. package/template/old/src/app/(app)/users/[id]/render.tsx +0 -325
  62. package/template/old/src/app/(app)/users/[id]/validation.ts +0 -18
  63. package/template/old/src/app/(app)/users/actions.ts +0 -34
  64. package/template/old/src/app/(app)/users/page.tsx +0 -62
  65. package/template/old/src/app/(app)/users/render.tsx +0 -124
  66. package/template/old/src/app/(auth)/layout.tsx +0 -27
  67. package/template/old/src/app/(auth)/login/page.tsx +0 -49
  68. package/template/old/src/app/(auth)/login/render.tsx +0 -146
  69. package/template/old/src/app/(marketing)/layout.tsx +0 -42
  70. package/template/old/src/app/(marketing)/page.tsx +0 -97
  71. package/template/old/src/app/api/auth/[...nextauth]/route.ts +0 -7
  72. package/template/old/src/app/favicon.ico +0 -0
  73. package/template/old/src/app/globals.css +0 -76
  74. package/template/old/src/app/layout.tsx +0 -31
  75. package/template/old/src/components/app-nav-command.tsx +0 -178
  76. package/template/old/src/components/dark-mode-toggle.tsx +0 -43
  77. package/template/old/src/components/data-table/data-table-column-header.tsx +0 -91
  78. package/template/old/src/components/data-table/data-table-faceted-filter.tsx +0 -149
  79. package/template/old/src/components/data-table/data-table-loading.tsx +0 -77
  80. package/template/old/src/components/data-table/data-table-pagination.tsx +0 -94
  81. package/template/old/src/components/data-table/data-table-toolbar.tsx +0 -78
  82. package/template/old/src/components/data-table/data-table-types.ts +0 -17
  83. package/template/old/src/components/data-table/data-table-view-options.tsx +0 -59
  84. package/template/old/src/components/data-table/data-table.tsx +0 -301
  85. package/template/old/src/components/data-table/simple-data-table.tsx +0 -109
  86. package/template/old/src/components/empty-placeholder.tsx +0 -78
  87. package/template/old/src/components/heading.tsx +0 -17
  88. package/template/old/src/components/icons.tsx +0 -101
  89. package/template/old/src/components/main-nav.tsx +0 -64
  90. package/template/old/src/components/mobile-nav.tsx +0 -50
  91. package/template/old/src/components/shell.tsx +0 -13
  92. package/template/old/src/components/side-nav.tsx +0 -51
  93. package/template/old/src/components/site-footer.tsx +0 -31
  94. package/template/old/src/components/system-info.tsx +0 -36
  95. package/template/old/src/components/ui/alert-dialog.tsx +0 -141
  96. package/template/old/src/components/ui/avatar.tsx +0 -50
  97. package/template/old/src/components/ui/badge.tsx +0 -36
  98. package/template/old/src/components/ui/button.tsx +0 -56
  99. package/template/old/src/components/ui/card.tsx +0 -79
  100. package/template/old/src/components/ui/checkbox.tsx +0 -30
  101. package/template/old/src/components/ui/command.tsx +0 -155
  102. package/template/old/src/components/ui/dialog.tsx +0 -122
  103. package/template/old/src/components/ui/dropdown-menu.tsx +0 -200
  104. package/template/old/src/components/ui/form.tsx +0 -176
  105. package/template/old/src/components/ui/input.tsx +0 -25
  106. package/template/old/src/components/ui/label.tsx +0 -26
  107. package/template/old/src/components/ui/popover.tsx +0 -31
  108. package/template/old/src/components/ui/select.tsx +0 -160
  109. package/template/old/src/components/ui/separator.tsx +0 -31
  110. package/template/old/src/components/ui/skeleton.tsx +0 -15
  111. package/template/old/src/components/ui/sonner.tsx +0 -31
  112. package/template/old/src/components/ui/table.tsx +0 -117
  113. package/template/old/src/components/user-account-nav.tsx +0 -60
  114. package/template/old/src/components/user-avatar.tsx +0 -27
  115. package/template/old/src/data-access/resource.ts +0 -85
  116. package/template/old/src/data-access/role-permission.ts +0 -45
  117. package/template/old/src/data-access/role.ts +0 -105
  118. package/template/old/src/data-access/task.ts +0 -141
  119. package/template/old/src/data-access/user.ts +0 -141
  120. package/template/old/src/db/index.ts +0 -14
  121. package/template/old/src/db/schema.ts +0 -287
  122. package/template/old/src/env.mjs +0 -58
  123. package/template/old/src/hooks/use-debounce.tsx +0 -17
  124. package/template/old/src/hooks/use-lock-body.tsx +0 -13
  125. package/template/old/src/lib/auth.ts +0 -89
  126. package/template/old/src/lib/cn.ts +0 -4
  127. package/template/old/src/lib/currentUser.ts +0 -8
  128. package/template/old/src/lib/delay.ts +0 -2
  129. package/template/old/src/lib/formatDate.ts +0 -11
  130. package/template/old/src/lib/generateLabel.ts +0 -5
  131. package/template/old/src/lib/s3Client.ts +0 -156
  132. package/template/old/src/lib/safe-action.ts +0 -19
  133. package/template/old/src/lib/siteConfig.ts +0 -4
  134. package/template/old/src/lib/sortOrderEnum.ts +0 -2
  135. package/template/old/src/use-case/role-permission.ts +0 -19
  136. package/template/old/src/use-case/role.ts +0 -110
  137. package/template/old/src/use-case/task.ts +0 -166
  138. package/template/old/src/use-case/user.ts +0 -121
  139. package/template/old/tailwind.config.ts +0 -81
  140. package/template/old/tsconfig.json +0 -47
@@ -1,129 +0,0 @@
1
- 'use client'
2
-
3
- import { InferSelectModel } from 'drizzle-orm'
4
- import Link from 'next/link'
5
- import { FC } from 'react'
6
-
7
- import { DataTable } from '@/components/data-table/data-table'
8
- import { DataTableColumnHeader } from '@/components/data-table/data-table-column-header'
9
- import { Heading } from '@/components/heading'
10
- import { Icons } from '@/components/icons'
11
- import { Shell } from '@/components/shell'
12
- import { Button } from '@/components/ui/button'
13
- import { Task } from '@/db/schema'
14
- import { formatDateTime, timesAgo } from '@/lib/formatDate'
15
- import { generateLabel } from '@/lib/generateLabel'
16
- import { TaskStatusEnumArr } from './statusEnum'
17
-
18
- const statuses = TaskStatusEnumArr.map(x => ({
19
- label: generateLabel(x),
20
- value: x
21
- }))
22
-
23
- export const Render: FC<{
24
- data: {
25
- tasks: {
26
- id: string
27
- title: string
28
- status: InferSelectModel<typeof Task>['status']
29
- createdBy: {
30
- id: string
31
- name?: string | null
32
- }
33
- updatedBy?: {
34
- id: string
35
- name?: string | null
36
- } | null
37
- createdAt: Date
38
- updatedAt?: Date | null
39
- }[]
40
- total: number
41
- }
42
- }> = ({ data }) => {
43
- return (
44
- <Shell>
45
- <Heading heading="Tasks" text="List of all the tasks">
46
- <Link href="/tasks/new">
47
- <Button>
48
- <Icons.add className="mr-2 h-4 w-4" />
49
- New
50
- </Button>
51
- </Link>
52
- </Heading>
53
- <DataTable
54
- columns={[
55
- {
56
- accessorKey: 'title',
57
- header: ({ column }) => (
58
- <DataTableColumnHeader column={column} title="Title" />
59
- ),
60
- cell: ({ row }) => (
61
- <Link
62
- className="underline underline-offset-4"
63
- href={`/tasks/${row.original.id}`}
64
- >
65
- {row.original.title}
66
- </Link>
67
- )
68
- },
69
- {
70
- accessorKey: 'status',
71
- header: ({ column }) => (
72
- <DataTableColumnHeader column={column} title="Status" />
73
- ),
74
- cell: ({ row }) => row.original.status.replace('_', ' ')
75
- },
76
- {
77
- accessorKey: 'createdBy',
78
- header: ({ column }) => (
79
- <DataTableColumnHeader column={column} title="Created By" />
80
- ),
81
- cell: ({ row }) => row.original.createdBy.name,
82
- enableSorting: false
83
- },
84
- {
85
- accessorKey: 'updatedBy',
86
- header: ({ column }) => (
87
- <DataTableColumnHeader column={column} title="Updated By" />
88
- ),
89
- cell: ({ row }) =>
90
- row.original.updatedBy ? row.original.updatedBy.name : undefined,
91
- enableSorting: false
92
- },
93
- {
94
- accessorKey: 'createdAt',
95
- header: ({ column }) => (
96
- <DataTableColumnHeader column={column} title="Created At" />
97
- ),
98
- cell: ({ row }) => formatDateTime(row.original.createdAt)
99
- },
100
- {
101
- accessorKey: 'updatedAt',
102
- header: ({ column }) => (
103
- <DataTableColumnHeader column={column} title="Updated At" />
104
- ),
105
- cell: ({ row }) =>
106
- row.original.updatedAt
107
- ? timesAgo(row.original.updatedAt)
108
- : undefined
109
- }
110
- ]}
111
- data={data.tasks}
112
- total={data.total}
113
- searchableColumns={[
114
- {
115
- id: 'title',
116
- title: 'Title'
117
- }
118
- ]}
119
- filterableColumns={[
120
- {
121
- id: 'status',
122
- title: 'Status',
123
- options: statuses
124
- }
125
- ]}
126
- />
127
- </Shell>
128
- )
129
- }
@@ -1,3 +0,0 @@
1
- import { Task } from '@/db/schema'
2
-
3
- export const TaskStatusEnumArr = Task.status.enumValues
@@ -1,68 +0,0 @@
1
- 'use server'
2
-
3
- import { revalidatePath } from 'next/cache'
4
- import { z } from 'zod'
5
-
6
- import { authActionClient } from '@/lib/safe-action'
7
- import { getRolesMiniUseCase } from '@/use-case/role'
8
- import {
9
- createUserUseCase,
10
- deleteUserUseCase,
11
- getUserByIdUseCase,
12
- updateUserUseCase
13
- } from '@/use-case/user'
14
- import { UserCreateUpdateSchema, UserUpdateServerSchema } from './validation'
15
-
16
- export const getUserAction = authActionClient
17
- .schema(z.string())
18
- .action(async ({ parsedInput: id, ctx }) => {
19
- return await getUserByIdUseCase(ctx.user.type, id)
20
- })
21
-
22
- export const createUserAction = authActionClient
23
- .schema(UserCreateUpdateSchema)
24
- .action(async ({ parsedInput, ctx }) => {
25
- const id = await createUserUseCase(ctx.user.type, parsedInput)
26
-
27
- revalidatePath('/users')
28
- revalidatePath(`/users/${id}`)
29
-
30
- return {
31
- success: true,
32
- id
33
- }
34
- })
35
-
36
- export const updateUserAction = authActionClient
37
- .schema(UserUpdateServerSchema)
38
- .action(async ({ parsedInput: { id, name, type, roleId }, ctx }) => {
39
- await updateUserUseCase(ctx.user.type, id, {
40
- name,
41
- type,
42
- roleId
43
- })
44
-
45
- revalidatePath('/users')
46
- revalidatePath(`/users/${id}`)
47
-
48
- return {
49
- success: true
50
- }
51
- })
52
-
53
- export const deleteUserAction = authActionClient
54
- .schema(z.string())
55
- .action(async ({ parsedInput: id, ctx }) => {
56
- await deleteUserUseCase(ctx.user.type, id)
57
-
58
- revalidatePath('/users')
59
- revalidatePath(`/users/${id}`)
60
-
61
- return { success: true }
62
- })
63
-
64
- export const getRolesMiniAction = authActionClient
65
- .schema(z.undefined())
66
- .action(async ({ ctx }) => {
67
- return await getRolesMiniUseCase(ctx.user.type)
68
- })
@@ -1,39 +0,0 @@
1
- import { Metadata } from 'next'
2
- import { notFound } from 'next/navigation'
3
-
4
- import { authGuard, getAuthSession } from '@/lib/auth'
5
- import { siteConfig } from '@/lib/siteConfig'
6
- import { getRolesMiniAction, getUserAction } from './actions'
7
- import { Render } from './render'
8
-
9
- export const generateMetadata = async (props: {
10
- params: { id: string }
11
- }): Promise<Metadata> => ({
12
- title: 'User - ' + props.params.id + ' | ' + siteConfig.name
13
- })
14
-
15
- const UserPage = async ({
16
- params: { id }
17
- }: {
18
- params: {
19
- id: string
20
- }
21
- }) => {
22
- const session = await getAuthSession()
23
- if (!session) return notFound()
24
-
25
- const g = await authGuard(session)
26
- if (!g) return notFound()
27
-
28
- const roles = await getRolesMiniAction(undefined)
29
- if (!roles?.data) return notFound()
30
-
31
- if (id === 'new') return <Render roles={roles.data} />
32
-
33
- const user = await getUserAction(id)
34
- if (!user?.data) return notFound()
35
-
36
- return <Render user={user.data} roles={roles.data} />
37
- }
38
-
39
- export default UserPage
@@ -1,325 +0,0 @@
1
- 'use client'
2
-
3
- import { zodResolver } from '@hookform/resolvers/zod'
4
- import Link from 'next/link'
5
- import { useRouter } from 'next/navigation'
6
- import { FC, useState } from 'react'
7
- import { useForm } from 'react-hook-form'
8
- import { toast } from 'sonner'
9
- import { z } from 'zod'
10
-
11
- import { Heading } from '@/components/heading'
12
- import { Icons } from '@/components/icons'
13
- import { Shell } from '@/components/shell'
14
- import { SystemInfo } from '@/components/system-info'
15
- import {
16
- AlertDialog,
17
- AlertDialogAction,
18
- AlertDialogCancel,
19
- AlertDialogContent,
20
- AlertDialogDescription,
21
- AlertDialogFooter,
22
- AlertDialogHeader,
23
- AlertDialogTitle,
24
- AlertDialogTrigger
25
- } from '@/components/ui/alert-dialog'
26
- import { Button } from '@/components/ui/button'
27
- import {
28
- Form,
29
- FormControl,
30
- FormField,
31
- FormItem,
32
- FormLabel,
33
- FormMessage
34
- } from '@/components/ui/form'
35
- import { Input } from '@/components/ui/input'
36
- import {
37
- Select,
38
- SelectContent,
39
- SelectItem,
40
- SelectTrigger,
41
- SelectValue
42
- } from '@/components/ui/select'
43
- import { User } from '@/db/schema'
44
- import { formatDateTime, timesAgo } from '@/lib/formatDate'
45
- import { generateLabel } from '@/lib/generateLabel'
46
- import { InferSelectModel } from 'drizzle-orm'
47
- import { createUserAction, deleteUserAction, updateUserAction } from './actions'
48
- import { UserCreateUpdateSchema, UserTypeEnumArr } from './validation'
49
-
50
- type FormData = z.infer<typeof UserCreateUpdateSchema>
51
-
52
- const types = UserTypeEnumArr.map(x => ({
53
- label: generateLabel(x),
54
- value: x
55
- }))
56
-
57
- export const Render: FC<{
58
- user?: {
59
- id: string
60
- name?: string | null
61
- email: string
62
- type: InferSelectModel<typeof User>['type']
63
- roleId?: string | null
64
- createdAt: Date
65
- updatedAt?: Date | null
66
- } | null
67
- roles: {
68
- id: string
69
- name: string
70
- }[]
71
- }> = ({ user, roles }) => {
72
- const form = useForm<FormData>({
73
- resolver: zodResolver(UserCreateUpdateSchema),
74
- defaultValues: {
75
- name: user?.name ?? '',
76
- email: user?.email ?? '',
77
- type: user?.type ?? 'Normal',
78
- roleId: user?.roleId
79
- }
80
- })
81
- const router = useRouter()
82
- const [isSaving, setIsSaving] = useState(false)
83
- const [isDeleting, setIsDeleting] = useState(false)
84
-
85
- async function onSubmit(data: FormData) {
86
- setIsSaving(true)
87
- try {
88
- if (!user) {
89
- const res = await createUserAction(data)
90
- if (!res?.data?.success)
91
- throw new Error(res?.serverError || 'No success returned from server')
92
- if (!res?.data?.id) throw new Error('No id returned from server')
93
- router.replace(`/users/${res.data.id}`)
94
- } else {
95
- const res = await updateUserAction({
96
- id: user.id,
97
- ...data
98
- })
99
- if (!res?.data?.success)
100
- throw new Error(res?.serverError || 'No success returned from server')
101
- }
102
- toast('User saved')
103
- } catch (err) {
104
- toast('Error saving user', {
105
- description: (err as any).message || undefined
106
- })
107
- }
108
- setIsSaving(false)
109
- }
110
-
111
- return (
112
- <Shell>
113
- <Heading
114
- heading={user ? user.name || user.email || user.id : 'New User'}
115
- />
116
- <Form {...form}>
117
- <form
118
- className="grid grid-cols-1 gap-3 md:grid-cols-2"
119
- onSubmit={form.handleSubmit(onSubmit)}
120
- >
121
- <div className="col-span-1 mb-1 grid grid-cols-2 gap-2 sm:flex md:col-span-2">
122
- <Button type="button" onClick={() => router.back()} variant="ghost">
123
- <Icons.chevronLeft className="mr-2 h-4 w-4" />
124
- Back
125
- </Button>
126
- <Button type="submit" disabled={isSaving || isDeleting}>
127
- {isSaving ? (
128
- <Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
129
- ) : (
130
- <Icons.save className="mr-2 h-4 w-4" />
131
- )}
132
- <span>Save</span>
133
- </Button>
134
- {user ? (
135
- <AlertDialog>
136
- <AlertDialogTrigger asChild>
137
- <Button
138
- type="button"
139
- variant="destructive"
140
- disabled={isSaving || isDeleting}
141
- >
142
- {isDeleting ? (
143
- <Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
144
- ) : (
145
- <Icons.delete className="mr-2 h-4 w-4" />
146
- )}
147
- Delete
148
- </Button>
149
- </AlertDialogTrigger>
150
- <AlertDialogContent>
151
- <AlertDialogHeader>
152
- <AlertDialogTitle>
153
- Are you absolutely sure?
154
- </AlertDialogTitle>
155
- <AlertDialogDescription>
156
- This action cannot be undone.
157
- </AlertDialogDescription>
158
- </AlertDialogHeader>
159
- <AlertDialogFooter>
160
- <AlertDialogCancel>Cancel</AlertDialogCancel>
161
- <AlertDialogAction
162
- onClick={async () => {
163
- setIsDeleting(true)
164
- try {
165
- const res = await deleteUserAction(user.id)
166
- if (!res?.data?.success)
167
- throw new Error(
168
- res?.serverError ||
169
- 'No success returned from server'
170
- )
171
- toast('User deleted')
172
- router.replace('/users')
173
- } catch (err) {
174
- toast('Error deleting user', {
175
- description:
176
- (err as any).message || 'Something went wrong'
177
- })
178
- }
179
- setIsDeleting(false)
180
- }}
181
- >
182
- Continue
183
- </AlertDialogAction>
184
- </AlertDialogFooter>
185
- </AlertDialogContent>
186
- </AlertDialog>
187
- ) : undefined}
188
- {user ? (
189
- <Link href="/users/new">
190
- <Button
191
- type="button"
192
- disabled={isSaving || isDeleting}
193
- variant="secondary"
194
- className="w-full"
195
- >
196
- <Icons.add className="mr-2 h-4 w-4" />
197
- New
198
- </Button>
199
- </Link>
200
- ) : undefined}
201
- </div>
202
-
203
- <FormField
204
- control={form.control}
205
- name="name"
206
- render={({ field }) => (
207
- <FormItem>
208
- <FormLabel>Name</FormLabel>
209
- <FormControl>
210
- <Input
211
- type="text"
212
- placeholder="Enter a name"
213
- disabled={isSaving}
214
- {...field}
215
- />
216
- </FormControl>
217
- <FormMessage />
218
- </FormItem>
219
- )}
220
- />
221
-
222
- <FormField
223
- control={form.control}
224
- name="email"
225
- render={({ field }) => (
226
- <FormItem>
227
- <FormLabel>Email</FormLabel>
228
- <FormControl>
229
- <Input
230
- type="email"
231
- placeholder="Enter an email"
232
- autoCapitalize="none"
233
- autoComplete="email"
234
- autoCorrect="off"
235
- disabled={isSaving}
236
- {...field}
237
- />
238
- </FormControl>
239
- <FormMessage />
240
- </FormItem>
241
- )}
242
- />
243
-
244
- <FormField
245
- control={form.control}
246
- name="type"
247
- render={({ field }) => (
248
- <FormItem>
249
- <FormLabel>Type</FormLabel>
250
- <Select
251
- onValueChange={field.onChange}
252
- defaultValue={field.value}
253
- disabled={isSaving}
254
- >
255
- <FormControl>
256
- <SelectTrigger>
257
- <SelectValue placeholder="Select type" />
258
- </SelectTrigger>
259
- </FormControl>
260
- <SelectContent>
261
- {types.map(({ label, value }) => (
262
- <SelectItem key={value} value={value}>
263
- {label}
264
- </SelectItem>
265
- ))}
266
- </SelectContent>
267
- </Select>
268
- <FormMessage />
269
- </FormItem>
270
- )}
271
- />
272
-
273
- {form.getValues('type') === 'Normal' ? (
274
- <FormField
275
- control={form.control}
276
- name="roleId"
277
- render={({ field }) => (
278
- <FormItem>
279
- <FormLabel>Role</FormLabel>
280
- <Select
281
- onValueChange={field.onChange}
282
- defaultValue={field.value || undefined}
283
- disabled={isSaving}
284
- >
285
- <FormControl>
286
- <SelectTrigger>
287
- <SelectValue placeholder="Select role" />
288
- </SelectTrigger>
289
- </FormControl>
290
- <SelectContent>
291
- {roles.map(({ id, name }) => (
292
- <SelectItem key={id} value={id}>
293
- {name}
294
- </SelectItem>
295
- ))}
296
- </SelectContent>
297
- </Select>
298
- <FormMessage />
299
- </FormItem>
300
- )}
301
- />
302
- ) : undefined}
303
- </form>
304
- </Form>
305
- {user ? (
306
- <SystemInfo
307
- items={[
308
- {
309
- label: 'Id',
310
- value: user.id
311
- },
312
- {
313
- label: 'Created At',
314
- value: formatDateTime(user.createdAt)
315
- },
316
- {
317
- label: 'Updated At',
318
- value: user.updatedAt ? timesAgo(user.updatedAt) : '-'
319
- }
320
- ]}
321
- />
322
- ) : undefined}
323
- </Shell>
324
- )
325
- }
@@ -1,18 +0,0 @@
1
- import { z } from 'zod'
2
-
3
- import { User } from '@/db/schema'
4
-
5
- export const UserTypeEnumArr = User.type.enumValues
6
-
7
- export const UserCreateUpdateSchema = z.object({
8
- name: z.string().min(1).trim(),
9
- email: z.string().email().toLowerCase().trim(),
10
- type: z.enum(UserTypeEnumArr),
11
- roleId: z.string().optional().nullable()
12
- })
13
-
14
- export const UserUpdateServerSchema = UserCreateUpdateSchema.merge(
15
- z.object({
16
- id: z.string().min(1)
17
- })
18
- )
@@ -1,34 +0,0 @@
1
- 'use server'
2
-
3
- import { z } from 'zod'
4
-
5
- import { User } from '@/db/schema'
6
- import { authActionClient } from '@/lib/safe-action'
7
- import { SortOrderEnum } from '@/lib/sortOrderEnum'
8
- import { getUsersWithRoleUseCase } from '@/use-case/user'
9
-
10
- export const getUsersAction = authActionClient
11
- .schema(
12
- z.object({
13
- page: z.number().gte(1),
14
- limit: z.number().gte(1).lte(1000),
15
- sortBy: z.enum(['name']).optional(),
16
- sortOrder: z.enum(SortOrderEnum).optional(),
17
- name: z.string().optional(),
18
- email: z.string().optional(),
19
- type: z.array(z.enum(User.type.enumValues)).optional()
20
- })
21
- )
22
- .action(async ({ ctx, parsedInput }) => {
23
- return await getUsersWithRoleUseCase(ctx.user.type, {
24
- page: parsedInput.page,
25
- limit: parsedInput.limit,
26
- sortBy: parsedInput.sortBy,
27
- sortOrder: parsedInput.sortOrder,
28
- filters: {
29
- name: parsedInput.name,
30
- email: parsedInput.email,
31
- type: parsedInput.type
32
- }
33
- })
34
- })
@@ -1,62 +0,0 @@
1
- import { Metadata } from 'next'
2
- import { notFound } from 'next/navigation'
3
-
4
- import { authGuard, getAuthSession } from '@/lib/auth'
5
- import { siteConfig } from '@/lib/siteConfig'
6
- import { getUsersAction } from './actions'
7
- import { Render } from './render'
8
-
9
- export const metadata: Metadata = {
10
- title: 'Users' + ' | ' + siteConfig.name
11
- }
12
-
13
- const Users = async ({
14
- searchParams
15
- }: {
16
- searchParams: {
17
- page?: string
18
- limit?: string
19
- sort?: string
20
- name?: string
21
- email?: string
22
- type?: string
23
- }
24
- }) => {
25
- const session = await getAuthSession()
26
- if (!session) return notFound()
27
-
28
- const g = await authGuard(session)
29
- if (!g) return notFound()
30
-
31
- const page = searchParams.page ? parseInt(searchParams.page) : 1
32
- const limit = searchParams.limit ? parseInt(searchParams.limit) : 10
33
-
34
- const [sortBy, sortOrder] =
35
- typeof searchParams.sort === 'string'
36
- ? (searchParams.sort.split('.') as [any, 'asc' | 'desc' | undefined])
37
- : []
38
-
39
- const name = searchParams.name
40
- const email = searchParams.email
41
-
42
- const type =
43
- typeof searchParams.type === 'string'
44
- ? (searchParams.type.split('.') as any[])
45
- : undefined
46
-
47
- const data = await getUsersAction({
48
- page,
49
- limit,
50
- sortBy,
51
- sortOrder,
52
- name,
53
- email,
54
- type
55
- })
56
-
57
- if (!data?.data) throw new Error('Users data not found')
58
-
59
- return <Render data={data.data} />
60
- }
61
-
62
- export default Users