create-ej-app 3.2.0 → 5.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 (316) hide show
  1. package/LICENSE +1 -1
  2. package/cli.js +5 -1
  3. package/cli.ts +40 -33
  4. package/package.json +4 -4
  5. package/template/base/.env.example +10 -9
  6. package/template/base/.eslintrc.cjs +17 -15
  7. package/template/base/components.json +1 -1
  8. package/template/base/drizzle.config.ts +11 -0
  9. package/template/base/next.config.mjs +1 -12
  10. package/template/base/package.json +63 -56
  11. package/template/base/postcss.config.mjs +8 -0
  12. package/template/base/prettier.config.mjs +11 -0
  13. package/template/base/public/vercel.svg +1 -0
  14. package/template/base/src/app/(app)/dashboard/layout.tsx +14 -0
  15. package/template/base/src/app/(app)/dashboard/page.tsx +0 -7
  16. package/template/base/src/app/(app)/layout.tsx +55 -20
  17. package/template/base/src/app/(app)/roles/[id]/actions.ts +59 -0
  18. package/template/base/src/app/(app)/roles/[id]/page.tsx +46 -0
  19. package/template/base/src/app/(app)/roles/[id]/render.tsx +264 -0
  20. package/template/base/src/app/(app)/roles/[id]/validation.ts +22 -0
  21. package/template/base/src/app/(app)/roles/actions.ts +33 -0
  22. package/template/base/src/app/(app)/roles/page.tsx +52 -0
  23. package/template/base/src/app/(app)/roles/render.tsx +80 -0
  24. package/template/base/src/app/(app)/settings/actions.ts +11 -12
  25. package/template/base/src/app/(app)/settings/layout.tsx +14 -0
  26. package/template/base/src/app/(app)/settings/page.tsx +1 -10
  27. package/template/base/src/app/(app)/settings/render.tsx +11 -17
  28. package/template/base/src/app/(app)/settings/validation.ts +5 -0
  29. package/template/base/src/app/(app)/tasks/[id]/actions.ts +69 -124
  30. package/template/base/src/app/(app)/tasks/[id]/page.tsx +37 -3
  31. package/template/base/src/app/(app)/tasks/[id]/render.tsx +162 -93
  32. package/template/base/src/app/(app)/tasks/[id]/validation.ts +18 -0
  33. package/template/base/src/app/(app)/tasks/actions.ts +34 -64
  34. package/template/base/src/app/(app)/tasks/page.tsx +15 -9
  35. package/template/base/src/app/(app)/tasks/render.tsx +28 -6
  36. package/template/base/src/app/(app)/tasks/statusEnum.ts +3 -0
  37. package/template/base/src/app/(app)/users/[id]/actions.ts +47 -62
  38. package/template/base/src/app/(app)/users/[id]/page.tsx +15 -8
  39. package/template/base/src/app/(app)/users/[id]/render.tsx +119 -34
  40. package/template/base/src/app/(app)/users/[id]/validation.ts +18 -0
  41. package/template/base/src/app/(app)/users/actions.ts +28 -49
  42. package/template/base/src/app/(app)/users/page.tsx +22 -9
  43. package/template/base/src/app/(app)/users/render.tsx +47 -3
  44. package/template/base/src/app/(auth)/layout.tsx +7 -0
  45. package/template/base/src/app/(auth)/login/page.tsx +2 -2
  46. package/template/base/src/app/(auth)/login/render.tsx +146 -0
  47. package/template/base/src/app/(marketing)/layout.tsx +1 -1
  48. package/template/base/src/app/(marketing)/page.tsx +8 -7
  49. package/template/base/src/app/favicon.ico +0 -0
  50. package/template/base/src/app/layout.tsx +14 -17
  51. package/template/base/src/components/app-nav-command.tsx +18 -0
  52. package/template/base/src/components/data-table/data-table-column-header.tsx +2 -2
  53. package/template/base/src/components/icons.tsx +21 -5
  54. package/template/base/src/components/ui/alert-dialog.tsx +1 -1
  55. package/template/base/src/components/ui/command.tsx +1 -1
  56. package/template/base/src/components/ui/dialog.tsx +1 -1
  57. package/template/base/src/components/ui/sonner.tsx +31 -0
  58. package/template/base/src/components/user-avatar.tsx +4 -2
  59. package/template/base/src/data-access/resource.ts +85 -0
  60. package/template/base/src/data-access/role-permission.ts +45 -0
  61. package/template/base/src/data-access/role.ts +105 -0
  62. package/template/base/src/data-access/task.ts +141 -0
  63. package/template/base/src/data-access/user.ts +141 -0
  64. package/template/base/src/db/index.ts +14 -0
  65. package/template/base/src/db/schema.ts +287 -0
  66. package/template/base/src/env.mjs +10 -30
  67. package/template/base/src/hooks/use-lock-body.tsx +2 -1
  68. package/template/base/src/lib/auth.ts +32 -23
  69. package/template/base/src/lib/currentUser.ts +8 -0
  70. package/template/base/src/lib/s3Client.ts +156 -0
  71. package/template/base/src/lib/safe-action.ts +19 -0
  72. package/template/base/src/lib/sortOrderEnum.ts +2 -0
  73. package/template/base/src/use-case/role-permission.ts +19 -0
  74. package/template/base/src/use-case/role.ts +110 -0
  75. package/template/base/src/use-case/task.ts +166 -0
  76. package/template/base/src/use-case/user.ts +121 -0
  77. package/template/base/tailwind.config.ts +5 -4
  78. package/template/base/tsconfig.json +3 -2
  79. package/template/new/.env.example +13 -0
  80. package/template/new/components.json +22 -0
  81. package/template/new/drizzle.config.ts +10 -0
  82. package/template/new/eslint.config.mjs +18 -0
  83. package/template/new/next.config.ts +14 -0
  84. package/template/new/package.json +81 -0
  85. package/template/new/postcss.config.mjs +5 -0
  86. package/template/new/prettier.config.mjs +11 -0
  87. package/template/new/public/placeholder.svg +1 -0
  88. package/template/new/src/app/(auth)/login/email-login-form.tsx +97 -0
  89. package/template/new/src/app/(auth)/login/page.tsx +72 -0
  90. package/template/new/src/app/(auth)/login/social-login-buttons.tsx +69 -0
  91. package/template/new/src/app/api/auth/[...all]/route.ts +4 -0
  92. package/template/new/src/app/favicon.ico +0 -0
  93. package/template/new/src/app/globals.css +128 -0
  94. package/template/new/src/app/layout.tsx +50 -0
  95. package/template/new/src/app/page.tsx +3 -0
  96. package/template/new/src/components/loader.tsx +25 -0
  97. package/template/new/src/components/react-query-provider.tsx +12 -0
  98. package/template/new/src/components/screen-size.tsx +40 -0
  99. package/template/new/src/components/theme-toggle.tsx +22 -0
  100. package/template/new/src/components/ui/button.tsx +60 -0
  101. package/template/new/src/components/ui/card.tsx +92 -0
  102. package/template/new/src/components/ui/form.tsx +167 -0
  103. package/template/new/src/components/ui/input.tsx +21 -0
  104. package/template/new/src/components/ui/label.tsx +24 -0
  105. package/template/new/src/components/ui/separator.tsx +28 -0
  106. package/template/new/src/components/ui/sonner.tsx +40 -0
  107. package/template/new/src/db/index.ts +7 -0
  108. package/template/new/src/db/schema.ts +74 -0
  109. package/template/new/src/env.ts +42 -0
  110. package/template/new/src/lib/auth-client.ts +18 -0
  111. package/template/new/src/lib/auth.ts +67 -0
  112. package/template/new/src/lib/safe-action.ts +15 -0
  113. package/template/new/src/lib/toast-message.ts +15 -0
  114. package/template/new/tsconfig.json +49 -0
  115. package/template/prisma/.env.example +16 -0
  116. package/template/prisma/.eslintrc.cjs +24 -0
  117. package/template/prisma/components.json +17 -0
  118. package/template/prisma/next.config.mjs +15 -0
  119. package/template/prisma/package.json +80 -0
  120. package/template/prisma/public/next.svg +1 -0
  121. package/template/prisma/src/app/(app)/dashboard/page.tsx +19 -0
  122. package/template/prisma/src/app/(app)/layout.tsx +90 -0
  123. package/template/prisma/src/app/(app)/settings/actions.ts +18 -0
  124. package/template/prisma/src/app/(app)/settings/loading.tsx +28 -0
  125. package/template/prisma/src/app/(app)/settings/page.tsx +28 -0
  126. package/template/prisma/src/app/(app)/settings/render.tsx +113 -0
  127. package/template/prisma/src/app/(app)/tasks/[id]/actions.ts +147 -0
  128. package/template/prisma/src/app/(app)/tasks/[id]/page.tsx +25 -0
  129. package/template/prisma/src/app/(app)/tasks/[id]/render.tsx +413 -0
  130. package/template/prisma/src/app/(app)/tasks/actions.ts +69 -0
  131. package/template/prisma/src/app/(app)/tasks/page.tsx +53 -0
  132. package/template/prisma/src/app/(app)/tasks/render.tsx +107 -0
  133. package/template/prisma/src/app/(app)/users/[id]/actions.ts +83 -0
  134. package/template/prisma/src/app/(app)/users/[id]/page.tsx +32 -0
  135. package/template/prisma/src/app/(app)/users/[id]/render.tsx +240 -0
  136. package/template/prisma/src/app/(app)/users/actions.ts +55 -0
  137. package/template/prisma/src/app/(app)/users/page.tsx +49 -0
  138. package/template/prisma/src/app/(app)/users/render.tsx +80 -0
  139. package/template/prisma/src/app/(auth)/layout.tsx +20 -0
  140. package/template/prisma/src/app/(auth)/login/page.tsx +49 -0
  141. package/template/prisma/src/app/(marketing)/layout.tsx +42 -0
  142. package/template/prisma/src/app/(marketing)/page.tsx +96 -0
  143. package/template/prisma/src/app/api/auth/[...nextauth]/route.ts +7 -0
  144. package/template/prisma/src/app/favicon.ico +0 -0
  145. package/template/prisma/src/app/layout.tsx +34 -0
  146. package/template/prisma/src/components/app-nav-command.tsx +160 -0
  147. package/template/prisma/src/components/dark-mode-toggle.tsx +43 -0
  148. package/template/prisma/src/components/data-table/data-table-column-header.tsx +91 -0
  149. package/template/prisma/src/components/data-table/data-table-faceted-filter.tsx +149 -0
  150. package/template/prisma/src/components/data-table/data-table-loading.tsx +77 -0
  151. package/template/prisma/src/components/data-table/data-table-pagination.tsx +94 -0
  152. package/template/prisma/src/components/data-table/data-table-toolbar.tsx +78 -0
  153. package/template/prisma/src/components/data-table/data-table-types.ts +17 -0
  154. package/template/prisma/src/components/data-table/data-table-view-options.tsx +59 -0
  155. package/template/prisma/src/components/data-table/data-table.tsx +301 -0
  156. package/template/prisma/src/components/data-table/simple-data-table.tsx +109 -0
  157. package/template/prisma/src/components/empty-placeholder.tsx +78 -0
  158. package/template/prisma/src/components/heading.tsx +17 -0
  159. package/template/prisma/src/components/icons.tsx +85 -0
  160. package/template/prisma/src/components/main-nav.tsx +64 -0
  161. package/template/prisma/src/components/shell.tsx +13 -0
  162. package/template/prisma/src/components/side-nav.tsx +51 -0
  163. package/template/prisma/src/components/site-footer.tsx +31 -0
  164. package/template/prisma/src/components/system-info.tsx +36 -0
  165. package/template/prisma/src/components/ui/alert-dialog.tsx +141 -0
  166. package/template/prisma/src/components/ui/avatar.tsx +50 -0
  167. package/template/prisma/src/components/ui/badge.tsx +36 -0
  168. package/template/prisma/src/components/ui/button.tsx +56 -0
  169. package/template/prisma/src/components/ui/card.tsx +79 -0
  170. package/template/prisma/src/components/ui/checkbox.tsx +30 -0
  171. package/template/prisma/src/components/ui/command.tsx +155 -0
  172. package/template/prisma/src/components/ui/dialog.tsx +122 -0
  173. package/template/prisma/src/components/ui/dropdown-menu.tsx +200 -0
  174. package/template/prisma/src/components/ui/form.tsx +176 -0
  175. package/template/prisma/src/components/ui/input.tsx +25 -0
  176. package/template/prisma/src/components/ui/label.tsx +26 -0
  177. package/template/prisma/src/components/ui/popover.tsx +31 -0
  178. package/template/prisma/src/components/ui/select.tsx +160 -0
  179. package/template/prisma/src/components/ui/separator.tsx +31 -0
  180. package/template/prisma/src/components/ui/skeleton.tsx +15 -0
  181. package/template/prisma/src/components/ui/table.tsx +117 -0
  182. package/template/prisma/src/components/user-account-nav.tsx +60 -0
  183. package/template/prisma/src/components/user-avatar.tsx +25 -0
  184. package/template/prisma/src/env.mjs +78 -0
  185. package/template/prisma/src/hooks/use-debounce.ts +17 -0
  186. package/template/prisma/src/hooks/use-lock-body.tsx +12 -0
  187. package/template/prisma/src/lib/auth.ts +80 -0
  188. package/template/prisma/src/lib/cn.ts +4 -0
  189. package/template/prisma/src/lib/delay.ts +2 -0
  190. package/template/prisma/src/lib/formatDate.ts +11 -0
  191. package/template/prisma/src/lib/generateLabel.ts +5 -0
  192. package/template/prisma/src/lib/siteConfig.ts +4 -0
  193. package/template/prisma/src/styles/globals.css +76 -0
  194. package/template/prisma/tailwind.config.ts +80 -0
  195. package/template/prisma/tsconfig.json +46 -0
  196. package/template/prisma-advanced/src/lib/cn.ts +4 -0
  197. package/template/prisma-advanced/src/lib/delay.ts +2 -0
  198. package/template/prisma-advanced/src/lib/siteConfig.ts +4 -0
  199. /package/template/{advanced/src/styles → base/src/app}/globals.css +0 -0
  200. /package/template/{advanced/src/hooks/use-debounce.ts → base/src/hooks/use-debounce.tsx} +0 -0
  201. /package/template/{advanced → new}/src/lib/cn.ts +0 -0
  202. /package/template/{advanced → new}/src/lib/delay.ts +0 -0
  203. /package/template/{advanced → new}/src/lib/siteConfig.ts +0 -0
  204. /package/template/{base → prisma}/postcss.config.cjs +0 -0
  205. /package/template/{base → prisma}/prettier.config.ts +0 -0
  206. /package/template/{base → prisma}/prisma/schema.prisma +0 -0
  207. /package/template/{base → prisma}/src/app/(auth)/login/user-auth-form.tsx +0 -0
  208. /package/template/{base → prisma}/src/app/api/upload/route.ts +0 -0
  209. /package/template/{advanced → prisma}/src/components/mobile-nav.tsx +0 -0
  210. /package/template/{base → prisma}/src/components/theme-provider.tsx +0 -0
  211. /package/template/{base → prisma}/src/components/ui/textarea.tsx +0 -0
  212. /package/template/{base → prisma}/src/components/ui/toast.tsx +0 -0
  213. /package/template/{base → prisma}/src/components/ui/toaster.tsx +0 -0
  214. /package/template/{base → prisma}/src/components/ui/use-toast.ts +0 -0
  215. /package/template/{base → prisma}/src/lib/db.ts +0 -0
  216. /package/template/{base → prisma}/src/lib/storageClient.ts +0 -0
  217. /package/template/{base → prisma}/src/styles/editor.css +0 -0
  218. /package/template/{base → prisma}/src/types/UnwrapPromise.ts +0 -0
  219. /package/template/{advanced → prisma-advanced}/.env.example +0 -0
  220. /package/template/{advanced → prisma-advanced}/.eslintrc.cjs +0 -0
  221. /package/template/{advanced → prisma-advanced}/components.json +0 -0
  222. /package/template/{advanced → prisma-advanced}/next.config.mjs +0 -0
  223. /package/template/{advanced → prisma-advanced}/package.json +0 -0
  224. /package/template/{advanced → prisma-advanced}/postcss.config.cjs +0 -0
  225. /package/template/{advanced → prisma-advanced}/prettier.config.ts +0 -0
  226. /package/template/{advanced → prisma-advanced}/prisma/schema.prisma +0 -0
  227. /package/template/{advanced → prisma-advanced}/public/next.svg +0 -0
  228. /package/template/{advanced → prisma-advanced}/src/app/(app)/dashboard/page.tsx +0 -0
  229. /package/template/{advanced → prisma-advanced}/src/app/(app)/layout.tsx +0 -0
  230. /package/template/{advanced → prisma-advanced}/src/app/(app)/roles/[id]/actions.ts +0 -0
  231. /package/template/{advanced → prisma-advanced}/src/app/(app)/roles/[id]/page.tsx +0 -0
  232. /package/template/{advanced → prisma-advanced}/src/app/(app)/roles/[id]/render.tsx +0 -0
  233. /package/template/{advanced → prisma-advanced}/src/app/(app)/roles/actions.ts +0 -0
  234. /package/template/{advanced → prisma-advanced}/src/app/(app)/roles/page.tsx +0 -0
  235. /package/template/{advanced → prisma-advanced}/src/app/(app)/roles/render.tsx +0 -0
  236. /package/template/{advanced → prisma-advanced}/src/app/(app)/settings/actions.ts +0 -0
  237. /package/template/{advanced → prisma-advanced}/src/app/(app)/settings/loading.tsx +0 -0
  238. /package/template/{advanced → prisma-advanced}/src/app/(app)/settings/page.tsx +0 -0
  239. /package/template/{advanced → prisma-advanced}/src/app/(app)/settings/render.tsx +0 -0
  240. /package/template/{advanced → prisma-advanced}/src/app/(app)/tasks/[id]/actions.ts +0 -0
  241. /package/template/{advanced → prisma-advanced}/src/app/(app)/tasks/[id]/page.tsx +0 -0
  242. /package/template/{advanced → prisma-advanced}/src/app/(app)/tasks/[id]/render.tsx +0 -0
  243. /package/template/{advanced → prisma-advanced}/src/app/(app)/tasks/actions.ts +0 -0
  244. /package/template/{advanced → prisma-advanced}/src/app/(app)/tasks/page.tsx +0 -0
  245. /package/template/{advanced → prisma-advanced}/src/app/(app)/tasks/render.tsx +0 -0
  246. /package/template/{advanced → prisma-advanced}/src/app/(app)/users/[id]/actions.ts +0 -0
  247. /package/template/{advanced → prisma-advanced}/src/app/(app)/users/[id]/page.tsx +0 -0
  248. /package/template/{advanced → prisma-advanced}/src/app/(app)/users/[id]/render.tsx +0 -0
  249. /package/template/{advanced → prisma-advanced}/src/app/(app)/users/actions.ts +0 -0
  250. /package/template/{advanced → prisma-advanced}/src/app/(app)/users/page.tsx +0 -0
  251. /package/template/{advanced → prisma-advanced}/src/app/(app)/users/render.tsx +0 -0
  252. /package/template/{advanced → prisma-advanced}/src/app/(auth)/layout.tsx +0 -0
  253. /package/template/{advanced → prisma-advanced}/src/app/(auth)/login/page.tsx +0 -0
  254. /package/template/{advanced → prisma-advanced}/src/app/(auth)/login/user-auth-form.tsx +0 -0
  255. /package/template/{advanced → prisma-advanced}/src/app/(marketing)/layout.tsx +0 -0
  256. /package/template/{advanced → prisma-advanced}/src/app/(marketing)/page.tsx +0 -0
  257. /package/template/{advanced → prisma-advanced}/src/app/api/auth/[...nextauth]/route.ts +0 -0
  258. /package/template/{advanced → prisma-advanced}/src/app/api/upload/route.ts +0 -0
  259. /package/template/{advanced → prisma-advanced}/src/app/favicon.ico +0 -0
  260. /package/template/{advanced → prisma-advanced}/src/app/layout.tsx +0 -0
  261. /package/template/{advanced → prisma-advanced}/src/components/app-nav-command.tsx +0 -0
  262. /package/template/{advanced → prisma-advanced}/src/components/dark-mode-toggle.tsx +0 -0
  263. /package/template/{advanced → prisma-advanced}/src/components/data-table/data-table-column-header.tsx +0 -0
  264. /package/template/{advanced → prisma-advanced}/src/components/data-table/data-table-faceted-filter.tsx +0 -0
  265. /package/template/{advanced → prisma-advanced}/src/components/data-table/data-table-loading.tsx +0 -0
  266. /package/template/{advanced → prisma-advanced}/src/components/data-table/data-table-pagination.tsx +0 -0
  267. /package/template/{advanced → prisma-advanced}/src/components/data-table/data-table-toolbar.tsx +0 -0
  268. /package/template/{advanced → prisma-advanced}/src/components/data-table/data-table-types.ts +0 -0
  269. /package/template/{advanced → prisma-advanced}/src/components/data-table/data-table-view-options.tsx +0 -0
  270. /package/template/{advanced → prisma-advanced}/src/components/data-table/data-table.tsx +0 -0
  271. /package/template/{advanced → prisma-advanced}/src/components/data-table/simple-data-table.tsx +0 -0
  272. /package/template/{advanced → prisma-advanced}/src/components/empty-placeholder.tsx +0 -0
  273. /package/template/{advanced → prisma-advanced}/src/components/heading.tsx +0 -0
  274. /package/template/{advanced → prisma-advanced}/src/components/icons.tsx +0 -0
  275. /package/template/{advanced → prisma-advanced}/src/components/main-nav.tsx +0 -0
  276. /package/template/{advanced → prisma-advanced}/src/components/shell.tsx +0 -0
  277. /package/template/{advanced → prisma-advanced}/src/components/side-nav.tsx +0 -0
  278. /package/template/{advanced → prisma-advanced}/src/components/site-footer.tsx +0 -0
  279. /package/template/{advanced → prisma-advanced}/src/components/system-info.tsx +0 -0
  280. /package/template/{advanced → prisma-advanced}/src/components/theme-provider.tsx +0 -0
  281. /package/template/{advanced → prisma-advanced}/src/components/ui/alert-dialog.tsx +0 -0
  282. /package/template/{advanced → prisma-advanced}/src/components/ui/avatar.tsx +0 -0
  283. /package/template/{advanced → prisma-advanced}/src/components/ui/badge.tsx +0 -0
  284. /package/template/{advanced → prisma-advanced}/src/components/ui/button.tsx +0 -0
  285. /package/template/{advanced → prisma-advanced}/src/components/ui/card.tsx +0 -0
  286. /package/template/{advanced → prisma-advanced}/src/components/ui/checkbox.tsx +0 -0
  287. /package/template/{advanced → prisma-advanced}/src/components/ui/command.tsx +0 -0
  288. /package/template/{advanced → prisma-advanced}/src/components/ui/dialog.tsx +0 -0
  289. /package/template/{advanced → prisma-advanced}/src/components/ui/dropdown-menu.tsx +0 -0
  290. /package/template/{advanced → prisma-advanced}/src/components/ui/form.tsx +0 -0
  291. /package/template/{advanced → prisma-advanced}/src/components/ui/input.tsx +0 -0
  292. /package/template/{advanced → prisma-advanced}/src/components/ui/label.tsx +0 -0
  293. /package/template/{advanced → prisma-advanced}/src/components/ui/popover.tsx +0 -0
  294. /package/template/{advanced → prisma-advanced}/src/components/ui/select.tsx +0 -0
  295. /package/template/{advanced → prisma-advanced}/src/components/ui/separator.tsx +0 -0
  296. /package/template/{advanced → prisma-advanced}/src/components/ui/skeleton.tsx +0 -0
  297. /package/template/{advanced → prisma-advanced}/src/components/ui/table.tsx +0 -0
  298. /package/template/{advanced → prisma-advanced}/src/components/ui/textarea.tsx +0 -0
  299. /package/template/{advanced → prisma-advanced}/src/components/ui/toast.tsx +0 -0
  300. /package/template/{advanced → prisma-advanced}/src/components/ui/toaster.tsx +0 -0
  301. /package/template/{advanced → prisma-advanced}/src/components/ui/use-toast.ts +0 -0
  302. /package/template/{advanced → prisma-advanced}/src/components/user-account-nav.tsx +0 -0
  303. /package/template/{advanced → prisma-advanced}/src/components/user-avatar.tsx +0 -0
  304. /package/template/{advanced → prisma-advanced}/src/env.mjs +0 -0
  305. /package/template/{base → prisma-advanced}/src/hooks/use-debounce.ts +0 -0
  306. /package/template/{advanced → prisma-advanced}/src/hooks/use-lock-body.tsx +0 -0
  307. /package/template/{advanced → prisma-advanced}/src/lib/auth.ts +0 -0
  308. /package/template/{advanced → prisma-advanced}/src/lib/db.ts +0 -0
  309. /package/template/{advanced → prisma-advanced}/src/lib/formatDate.ts +0 -0
  310. /package/template/{advanced → prisma-advanced}/src/lib/generateLabel.ts +0 -0
  311. /package/template/{advanced → prisma-advanced}/src/lib/storageClient.ts +0 -0
  312. /package/template/{advanced → prisma-advanced}/src/styles/editor.css +0 -0
  313. /package/template/{base → prisma-advanced}/src/styles/globals.css +0 -0
  314. /package/template/{advanced → prisma-advanced}/src/types/UnwrapPromise.ts +0 -0
  315. /package/template/{advanced → prisma-advanced}/tailwind.config.ts +0 -0
  316. /package/template/{advanced → prisma-advanced}/tsconfig.json +0 -0
@@ -0,0 +1,46 @@
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 { getRoleAction } from './actions'
7
+ import { Render } from './render'
8
+
9
+ export const generateMetadata = async (props: {
10
+ params: { id: string }
11
+ }): Promise<Metadata> => ({
12
+ title: 'Role - ' + props.params.id + ' | ' + siteConfig.name
13
+ })
14
+
15
+ const RolePage = 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
+ if (id == 'new') return <Render />
29
+
30
+ const role = await getRoleAction(id)
31
+ if (!role?.data) return notFound()
32
+
33
+ return (
34
+ <Render
35
+ role={{
36
+ id: role.data.id,
37
+ name: role.data.name,
38
+ permissions: role.data.permissions.map(p => p.permission),
39
+ createdAt: role.data.createdAt,
40
+ updatedAt: role.data.updatedAt
41
+ }}
42
+ />
43
+ )
44
+ }
45
+
46
+ export default RolePage
@@ -0,0 +1,264 @@
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 { Checkbox } from '@/components/ui/checkbox'
28
+ import {
29
+ Form,
30
+ FormControl,
31
+ FormField,
32
+ FormItem,
33
+ FormLabel,
34
+ FormMessage
35
+ } from '@/components/ui/form'
36
+ import { Input } from '@/components/ui/input'
37
+ import { type RolePermissionType } from '@/data-access/role-permission'
38
+ import { formatDateTime, timesAgo } from '@/lib/formatDate'
39
+ import { createRoleAction, deleteRoleAction, updateRoleAction } from './actions'
40
+ import { RoleCreateUpdateSchema, defaultPermissions } from './validation'
41
+
42
+ type FormData = z.infer<typeof RoleCreateUpdateSchema>
43
+
44
+ export const Render: FC<{
45
+ role?: {
46
+ id: string
47
+ name: string
48
+ permissions: RolePermissionType['permission'][]
49
+ createdAt: Date
50
+ updatedAt?: Date | null
51
+ } | null
52
+ }> = ({ role }) => {
53
+ const form = useForm<FormData>({
54
+ resolver: zodResolver(RoleCreateUpdateSchema),
55
+ defaultValues: {
56
+ name: role?.name ?? '',
57
+ permissions: role?.permissions ?? []
58
+ }
59
+ })
60
+
61
+ const router = useRouter()
62
+
63
+ const [isSaving, setIsSaving] = useState(false)
64
+ const [isDeleting, setIsDeleting] = useState(false)
65
+
66
+ async function onSubmit(data: FormData) {
67
+ setIsSaving(true)
68
+ try {
69
+ if (!role) {
70
+ const res = await createRoleAction(data)
71
+ if (!res?.data?.success)
72
+ throw new Error(res?.serverError || 'No success returned from server')
73
+ if (!res?.data?.id) throw new Error('No id returned from server')
74
+ router.replace(`/roles/${res.data.id}`)
75
+ } else {
76
+ const res = await updateRoleAction({
77
+ id: role.id,
78
+ ...data
79
+ })
80
+ if (!res?.data?.success)
81
+ throw new Error(res?.serverError || 'No success returned from server')
82
+ }
83
+ toast('Role saved')
84
+ } catch (err) {
85
+ toast('Error saving role', {
86
+ description: (err as any).message || undefined
87
+ })
88
+ }
89
+ setIsSaving(false)
90
+ }
91
+
92
+ return (
93
+ <Shell>
94
+ <Heading heading={role ? role.name : 'New Role'} />
95
+ <Form {...form}>
96
+ <form
97
+ className="grid grid-cols-1 gap-3 md:grid-cols-2"
98
+ onSubmit={form.handleSubmit(onSubmit)}
99
+ >
100
+ <div className="col-span-1 mb-1 grid grid-cols-2 gap-2 sm:flex md:col-span-2">
101
+ <Button type="button" onClick={() => router.back()} variant="ghost">
102
+ <Icons.chevronLeft className="mr-2 h-4 w-4" />
103
+ Back
104
+ </Button>
105
+ <Button type="submit" disabled={isSaving || isDeleting}>
106
+ {isSaving ? (
107
+ <Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
108
+ ) : (
109
+ <Icons.save className="mr-2 h-4 w-4" />
110
+ )}
111
+ <span>Save</span>
112
+ </Button>
113
+ {role ? (
114
+ <AlertDialog>
115
+ <AlertDialogTrigger asChild>
116
+ <Button
117
+ type="button"
118
+ variant="destructive"
119
+ disabled={isSaving || isDeleting}
120
+ >
121
+ {isDeleting ? (
122
+ <Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
123
+ ) : (
124
+ <Icons.delete className="mr-2 h-4 w-4" />
125
+ )}
126
+ Delete
127
+ </Button>
128
+ </AlertDialogTrigger>
129
+ <AlertDialogContent>
130
+ <AlertDialogHeader>
131
+ <AlertDialogTitle>
132
+ Are you absolutely sure?
133
+ </AlertDialogTitle>
134
+ <AlertDialogDescription>
135
+ This action cannot be undone.
136
+ </AlertDialogDescription>
137
+ </AlertDialogHeader>
138
+ <AlertDialogFooter>
139
+ <AlertDialogCancel>Cancel</AlertDialogCancel>
140
+ <AlertDialogAction
141
+ onClick={async () => {
142
+ setIsDeleting(true)
143
+ try {
144
+ const res = await deleteRoleAction(role.id)
145
+ if (!res?.data?.success)
146
+ throw new Error(
147
+ res?.serverError ||
148
+ 'No success returned from server'
149
+ )
150
+ toast('Role deleted')
151
+ router.replace('/roles')
152
+ } catch (err) {
153
+ toast('Error deleting role', {
154
+ description:
155
+ (err as any).message || 'Something went wrong'
156
+ })
157
+ }
158
+ setIsDeleting(false)
159
+ }}
160
+ >
161
+ Continue
162
+ </AlertDialogAction>
163
+ </AlertDialogFooter>
164
+ </AlertDialogContent>
165
+ </AlertDialog>
166
+ ) : undefined}
167
+ {role ? (
168
+ <Link href="/roles/new">
169
+ <Button
170
+ type="button"
171
+ disabled={isSaving || isDeleting}
172
+ variant="secondary"
173
+ className="w-full"
174
+ >
175
+ <Icons.add className="mr-2 h-4 w-4" />
176
+ New
177
+ </Button>
178
+ </Link>
179
+ ) : undefined}
180
+ </div>
181
+
182
+ <FormField
183
+ control={form.control}
184
+ name="name"
185
+ render={({ field }) => (
186
+ <FormItem>
187
+ <FormLabel>Name</FormLabel>
188
+ <FormControl>
189
+ <Input
190
+ type="text"
191
+ placeholder="Enter a name"
192
+ disabled={isSaving}
193
+ {...field}
194
+ />
195
+ </FormControl>
196
+ <FormMessage />
197
+ </FormItem>
198
+ )}
199
+ />
200
+
201
+ <div></div>
202
+
203
+ <FormField
204
+ control={form.control}
205
+ name="permissions"
206
+ render={() => (
207
+ <FormItem>
208
+ <FormLabel className="text-base">Permissions</FormLabel>
209
+ {defaultPermissions.map(item => (
210
+ <FormField
211
+ key={item.value}
212
+ control={form.control}
213
+ name="permissions"
214
+ render={({ field }) => (
215
+ <FormItem
216
+ key={item.value}
217
+ className="flex flex-row items-start space-x-3 space-y-0"
218
+ >
219
+ <FormControl>
220
+ <Checkbox
221
+ checked={field.value?.includes(item.value)}
222
+ onCheckedChange={checked => {
223
+ return checked
224
+ ? field.onChange([...field.value, item.value])
225
+ : field.onChange(
226
+ field.value?.filter(
227
+ value => value !== item.value
228
+ )
229
+ )
230
+ }}
231
+ />
232
+ </FormControl>
233
+ <FormLabel>{item.label}</FormLabel>
234
+ </FormItem>
235
+ )}
236
+ />
237
+ ))}
238
+ <FormMessage />
239
+ </FormItem>
240
+ )}
241
+ />
242
+ </form>
243
+ </Form>
244
+ {role ? (
245
+ <SystemInfo
246
+ items={[
247
+ {
248
+ label: 'Id',
249
+ value: role.id
250
+ },
251
+ {
252
+ label: 'Created At',
253
+ value: formatDateTime(role.createdAt)
254
+ },
255
+ {
256
+ label: 'Updated At',
257
+ value: role.updatedAt ? timesAgo(role.updatedAt) : '-'
258
+ }
259
+ ]}
260
+ />
261
+ ) : undefined}
262
+ </Shell>
263
+ )
264
+ }
@@ -0,0 +1,22 @@
1
+ import { z } from 'zod'
2
+
3
+ import { RolePermission } from '@/db/schema'
4
+ import { generateLabel } from '@/lib/generateLabel'
5
+
6
+ const RolePermissionsEnumArr = RolePermission.permission.enumValues
7
+
8
+ export const RoleCreateUpdateSchema = z.object({
9
+ name: z.string().min(1).trim(),
10
+ permissions: z.array(z.enum(RolePermissionsEnumArr))
11
+ })
12
+
13
+ export const defaultPermissions = RolePermissionsEnumArr.map(x => ({
14
+ label: generateLabel(x),
15
+ value: x
16
+ }))
17
+
18
+ export const RoleUpdateServerSchema = RoleCreateUpdateSchema.merge(
19
+ z.object({
20
+ id: z.string().min(1)
21
+ })
22
+ )
@@ -0,0 +1,33 @@
1
+ 'use server'
2
+
3
+ import { z } from 'zod'
4
+
5
+ import { authActionClient } from '@/lib/safe-action'
6
+ import { SortOrderEnum } from '@/lib/sortOrderEnum'
7
+ import { getRolesUseCase } from '@/use-case/role'
8
+
9
+ export const getRolesAction = authActionClient
10
+ .schema(
11
+ z.object({
12
+ page: z.number().gte(1),
13
+ limit: z.number().gte(1).lte(1000),
14
+ sortBy: z.enum(['id', 'name', 'createdAt', 'updatedAt']).optional(),
15
+ sortOrder: z.enum(SortOrderEnum).optional(),
16
+ name: z.string().optional()
17
+ })
18
+ )
19
+ .action(
20
+ async ({ parsedInput: { page, limit, sortBy, sortOrder, name }, ctx }) => {
21
+ return await getRolesUseCase(ctx.user.type, {
22
+ page,
23
+ limit,
24
+ sortBy,
25
+ sortOrder,
26
+ filters: name
27
+ ? {
28
+ name
29
+ }
30
+ : undefined
31
+ })
32
+ }
33
+ )
@@ -0,0 +1,52 @@
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 { getRolesAction } from './actions'
7
+ import { Render } from './render'
8
+
9
+ export const metadata: Metadata = {
10
+ title: 'Roles' + ' | ' + siteConfig.name
11
+ }
12
+
13
+ const RolesPage = async ({
14
+ searchParams
15
+ }: {
16
+ searchParams: {
17
+ page?: string
18
+ limit?: string
19
+ sort?: string
20
+ name?: string
21
+ }
22
+ }) => {
23
+ const session = await getAuthSession()
24
+ if (!session) return notFound()
25
+
26
+ const g = await authGuard(session)
27
+ if (!g) return notFound()
28
+
29
+ const page = searchParams.page ? parseInt(searchParams.page) : 1
30
+ const limit = searchParams.limit ? parseInt(searchParams.limit) : 10
31
+
32
+ const [sortBy, sortOrder] =
33
+ typeof searchParams.sort === 'string'
34
+ ? (searchParams.sort.split('.') as [any, 'asc' | 'desc' | undefined])
35
+ : []
36
+
37
+ const name = searchParams.name
38
+
39
+ const data = await getRolesAction({
40
+ page,
41
+ limit,
42
+ sortBy,
43
+ sortOrder,
44
+ name
45
+ })
46
+
47
+ if (!data?.data) throw new Error('Roles data not found')
48
+
49
+ return <Render data={data.data} />
50
+ }
51
+
52
+ export default RolesPage
@@ -0,0 +1,80 @@
1
+ 'use client'
2
+
3
+ import Link from 'next/link'
4
+ import { FC } from 'react'
5
+
6
+ import { DataTable } from '@/components/data-table/data-table'
7
+ import { DataTableColumnHeader } from '@/components/data-table/data-table-column-header'
8
+ import { Heading } from '@/components/heading'
9
+ import { Icons } from '@/components/icons'
10
+ import { Shell } from '@/components/shell'
11
+ import { Button } from '@/components/ui/button'
12
+ import { formatDateTime, timesAgo } from '@/lib/formatDate'
13
+
14
+ export const Render: FC<{
15
+ data: {
16
+ roles: {
17
+ id: string
18
+ name: string
19
+ createdAt: Date
20
+ updatedAt?: Date | null
21
+ }[]
22
+ total: number
23
+ }
24
+ }> = ({ data }) => {
25
+ return (
26
+ <Shell>
27
+ <Heading heading="Roles" text="List of all the roles">
28
+ <Link href="/roles/new">
29
+ <Button>
30
+ <Icons.add className="mr-2 h-4 w-4" />
31
+ New
32
+ </Button>
33
+ </Link>
34
+ </Heading>
35
+ <DataTable
36
+ columns={[
37
+ {
38
+ accessorKey: 'name',
39
+ header: ({ column }) => (
40
+ <DataTableColumnHeader column={column} title="Name" />
41
+ ),
42
+ cell: ({ row }) => (
43
+ <Link
44
+ className="underline underline-offset-4"
45
+ href={`/roles/${row.original.id}`}
46
+ >
47
+ {row.original.name}
48
+ </Link>
49
+ )
50
+ },
51
+ {
52
+ accessorKey: 'createdAt',
53
+ header: ({ column }) => (
54
+ <DataTableColumnHeader column={column} title="Created At" />
55
+ ),
56
+ cell: ({ row }) => formatDateTime(row.original.createdAt)
57
+ },
58
+ {
59
+ accessorKey: 'updatedAt',
60
+ header: ({ column }) => (
61
+ <DataTableColumnHeader column={column} title="Updated At" />
62
+ ),
63
+ cell: ({ row }) =>
64
+ row.original.updatedAt
65
+ ? timesAgo(row.original.updatedAt)
66
+ : undefined
67
+ }
68
+ ]}
69
+ data={data.roles}
70
+ total={data.total}
71
+ searchableColumns={[
72
+ {
73
+ id: 'name',
74
+ title: 'Name'
75
+ }
76
+ ]}
77
+ />
78
+ </Shell>
79
+ )
80
+ }
@@ -1,18 +1,17 @@
1
1
  'use server'
2
2
 
3
- import { getAuthSession } from '@/lib/auth'
4
- import { prisma } from '@/lib/db'
3
+ import { authActionClient } from '@/lib/safe-action'
4
+ import { updateCurrentUserNameUseCase } from '@/use-case/user'
5
+ import { userSchema } from './validation'
5
6
 
6
- export const updateName = async ({ name }: { name: string }) => {
7
- const session = await getAuthSession()
8
- if (!session?.user) throw new Error('Unauthorized')
9
-
10
- await prisma.user.update({
11
- where: {
12
- id: session.user.id
13
- },
14
- data: {
7
+ export const updateNameAction = authActionClient
8
+ .schema(userSchema)
9
+ .action(async ({ parsedInput: { name }, ctx: { user } }) => {
10
+ await updateCurrentUserNameUseCase(user.id, {
15
11
  name
12
+ })
13
+
14
+ return {
15
+ success: true
16
16
  }
17
17
  })
18
- }
@@ -0,0 +1,14 @@
1
+ import { Metadata } from 'next'
2
+ import { ReactNode } from 'react'
3
+
4
+ import { siteConfig } from '@/lib/siteConfig'
5
+
6
+ export const metadata: Metadata = {
7
+ title: 'Settings' + ' | ' + siteConfig.name
8
+ }
9
+
10
+ const Layout = ({ children }: { children: ReactNode }) => {
11
+ return <>{children}</>
12
+ }
13
+
14
+ export default Layout
@@ -1,25 +1,16 @@
1
- import { Metadata } from 'next'
2
-
3
1
  import { Heading } from '@/components/heading'
4
2
  import { Shell } from '@/components/shell'
5
3
  import { getAuthSession } from '@/lib/auth'
6
- import { siteConfig } from '@/lib/siteConfig'
7
4
  import { Render } from './render'
8
5
 
9
- export const metadata: Metadata = {
10
- title: 'Settings' + ' | ' + siteConfig.name
11
- }
12
-
13
6
  const SettingsPage = async () => {
14
7
  const session = await getAuthSession()
15
8
 
16
- if (!session?.user) return
17
-
18
9
  return (
19
10
  <Shell>
20
11
  <Heading heading="Settings" text="Manage account and profile settings." />
21
12
  <div className="grid gap-10">
22
- <Render name={session.user.name || ''} />
13
+ <Render name={session?.user.name || ''} />
23
14
  </div>
24
15
  </Shell>
25
16
  )
@@ -4,6 +4,7 @@ import { zodResolver } from '@hookform/resolvers/zod'
4
4
  import { useRouter } from 'next/navigation'
5
5
  import { FC, useState } from 'react'
6
6
  import { useForm } from 'react-hook-form'
7
+ import { toast } from 'sonner'
7
8
  import { z } from 'zod'
8
9
 
9
10
  import { Icons } from '@/components/icons'
@@ -24,12 +25,8 @@ import {
24
25
  FormMessage
25
26
  } from '@/components/ui/form'
26
27
  import { Input } from '@/components/ui/input'
27
- import { toast } from '@/components/ui/use-toast'
28
- import { updateName } from './actions'
29
-
30
- const userSchema = z.object({
31
- name: z.string().nonempty()
32
- })
28
+ import { updateNameAction } from './actions'
29
+ import { userSchema } from './validation'
33
30
 
34
31
  type FormData = z.infer<typeof userSchema>
35
32
 
@@ -46,18 +43,15 @@ export const Render: FC<{ name: string }> = ({ name }) => {
46
43
  async function onSubmit(data: FormData) {
47
44
  setIsSaving(true)
48
45
 
49
- try {
50
- await updateName({
51
- ...data
52
- })
53
- toast({
54
- title: 'Your name has been updated.'
55
- })
46
+ const res = await updateNameAction({
47
+ ...data
48
+ })
49
+
50
+ if (res?.data) {
51
+ toast('Your name has been updated.')
56
52
  router.refresh()
57
- } catch (err) {
58
- toast({
59
- title: 'Internal Server Error',
60
- variant: 'destructive',
53
+ } else {
54
+ toast('Internal Server Error', {
61
55
  description: 'Please try again later.'
62
56
  })
63
57
  }
@@ -0,0 +1,5 @@
1
+ import { z } from 'zod'
2
+
3
+ export const userSchema = z.object({
4
+ name: z.string().min(1)
5
+ })