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,83 @@
1
+ 'use server'
2
+
3
+ import { revalidatePath } from 'next/cache'
4
+
5
+ import { getAuthSession } from '@/lib/auth'
6
+ import { prisma } from '@/lib/db'
7
+ import { UnwrapPromise } from '@/types/UnwrapPromise'
8
+
9
+ export const getUser = async (id: string) => {
10
+ const session = await getAuthSession()
11
+ if (!session) throw new Error('Unauthorized')
12
+
13
+ return await prisma.user.findUnique({
14
+ where: {
15
+ id
16
+ }
17
+ })
18
+ }
19
+
20
+ export type GetUserFnDataType = UnwrapPromise<ReturnType<typeof getUser>>
21
+
22
+ export const createUser = async ({
23
+ name,
24
+ email
25
+ }: {
26
+ name: string
27
+ email: string
28
+ }) => {
29
+ const session = await getAuthSession()
30
+ if (!session) throw new Error('Unauthorized')
31
+
32
+ const { id } = await prisma.user.create({
33
+ data: {
34
+ name,
35
+ email
36
+ }
37
+ })
38
+
39
+ revalidatePath('/users')
40
+ revalidatePath(`/users/${id}`)
41
+
42
+ return id
43
+ }
44
+
45
+ export const updateUser = async ({
46
+ id,
47
+ name,
48
+ email
49
+ }: {
50
+ id: string
51
+ name: string
52
+ email: string
53
+ }) => {
54
+ const session = await getAuthSession()
55
+ if (!session) throw new Error('Unauthorized')
56
+
57
+ await prisma.user.update({
58
+ where: {
59
+ id
60
+ },
61
+ data: {
62
+ name,
63
+ email
64
+ }
65
+ })
66
+
67
+ revalidatePath('/users')
68
+ revalidatePath(`/users/${id}`)
69
+ }
70
+
71
+ export const deleteUser = async (id: string) => {
72
+ const session = await getAuthSession()
73
+ if (!session) throw new Error('Unauthorized')
74
+
75
+ await prisma.user.delete({
76
+ where: {
77
+ id
78
+ }
79
+ })
80
+
81
+ revalidatePath('/users')
82
+ revalidatePath(`/users/${id}`)
83
+ }
@@ -0,0 +1,32 @@
1
+ import { Metadata } from 'next'
2
+ import { notFound } from 'next/navigation'
3
+
4
+ import { siteConfig } from '@/lib/siteConfig'
5
+ import { GetUserFnDataType, getUser } from './actions'
6
+ import { Render } from './render'
7
+
8
+ export const generateMetadata = async (props: {
9
+ params: { id: string }
10
+ }): Promise<Metadata> => ({
11
+ title: 'User - ' + props.params.id + ' | ' + siteConfig.name
12
+ })
13
+
14
+ const UserPage = async ({
15
+ params: { id }
16
+ }: {
17
+ params: {
18
+ id: string
19
+ }
20
+ }) => {
21
+ let user: GetUserFnDataType | undefined
22
+
23
+ if (id !== 'new') {
24
+ const x = await getUser(id)
25
+ if (!x) return notFound()
26
+ user = x
27
+ }
28
+
29
+ return <Render user={user} />
30
+ }
31
+
32
+ export default UserPage
@@ -0,0 +1,240 @@
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 { z } from 'zod'
9
+
10
+ import { Heading } from '@/components/heading'
11
+ import { Icons } from '@/components/icons'
12
+ import { Shell } from '@/components/shell'
13
+ import { SystemInfo } from '@/components/system-info'
14
+ import {
15
+ AlertDialog,
16
+ AlertDialogAction,
17
+ AlertDialogCancel,
18
+ AlertDialogContent,
19
+ AlertDialogDescription,
20
+ AlertDialogFooter,
21
+ AlertDialogHeader,
22
+ AlertDialogTitle,
23
+ AlertDialogTrigger
24
+ } from '@/components/ui/alert-dialog'
25
+ import { Button } from '@/components/ui/button'
26
+ import {
27
+ Form,
28
+ FormControl,
29
+ FormField,
30
+ FormItem,
31
+ FormLabel,
32
+ FormMessage
33
+ } from '@/components/ui/form'
34
+ import { Input } from '@/components/ui/input'
35
+ import { toast } from '@/components/ui/use-toast'
36
+ import { formatDateTime, timesAgo } from '@/lib/formatDate'
37
+ import {
38
+ GetUserFnDataType,
39
+ createUser,
40
+ deleteUser,
41
+ updateUser
42
+ } from './actions'
43
+
44
+ const UserSchema = z.object({
45
+ name: z.string().nonempty(),
46
+ email: z.string().email()
47
+ })
48
+
49
+ type FormData = z.infer<typeof UserSchema>
50
+
51
+ export const Render: FC<{
52
+ user: GetUserFnDataType | undefined
53
+ }> = ({ user }) => {
54
+ const form = useForm<FormData>({
55
+ resolver: zodResolver(UserSchema),
56
+ defaultValues: {
57
+ name: user?.name ?? '',
58
+ email: user?.email ?? ''
59
+ }
60
+ })
61
+ const router = useRouter()
62
+ const [isSaving, setIsSaving] = useState(false)
63
+ const [isDeleting, setIsDeleting] = useState(false)
64
+
65
+ async function onSubmit(data: FormData) {
66
+ setIsSaving(true)
67
+ try {
68
+ if (!user) {
69
+ const newId = await createUser(data)
70
+ router.replace(`/users/${newId}`)
71
+ } else {
72
+ await updateUser({
73
+ id: user.id,
74
+ ...data
75
+ })
76
+ }
77
+ toast({
78
+ title: 'User saved'
79
+ })
80
+ } catch (err) {
81
+ toast({
82
+ title: 'Error saving user',
83
+ variant: 'destructive'
84
+ })
85
+ }
86
+ setIsSaving(false)
87
+ }
88
+
89
+ return (
90
+ <Shell>
91
+ <Heading
92
+ heading={user ? user.name || user.email || user.id : 'New User'}
93
+ />
94
+ <Form {...form}>
95
+ <form
96
+ className="grid grid-cols-1 gap-3 md:grid-cols-2"
97
+ onSubmit={form.handleSubmit(onSubmit)}
98
+ >
99
+ <div className="col-span-1 mb-1 grid grid-cols-2 gap-2 sm:flex md:col-span-2">
100
+ <Button type="button" onClick={() => router.back()} variant="ghost">
101
+ <Icons.chevronLeft className="mr-2 h-4 w-4" />
102
+ Back
103
+ </Button>
104
+ <Button type="submit" disabled={isSaving || isDeleting}>
105
+ {isSaving ? (
106
+ <Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
107
+ ) : (
108
+ <Icons.save className="mr-2 h-4 w-4" />
109
+ )}
110
+ <span>Save</span>
111
+ </Button>
112
+ {user ? (
113
+ <AlertDialog>
114
+ <AlertDialogTrigger asChild>
115
+ <Button
116
+ type="button"
117
+ variant="destructive"
118
+ disabled={isSaving || isDeleting}
119
+ >
120
+ {isDeleting ? (
121
+ <Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
122
+ ) : (
123
+ <Icons.delete className="mr-2 h-4 w-4" />
124
+ )}
125
+ Delete
126
+ </Button>
127
+ </AlertDialogTrigger>
128
+ <AlertDialogContent>
129
+ <AlertDialogHeader>
130
+ <AlertDialogTitle>
131
+ Are you absolutely sure?
132
+ </AlertDialogTitle>
133
+ <AlertDialogDescription>
134
+ This action cannot be undone.
135
+ </AlertDialogDescription>
136
+ </AlertDialogHeader>
137
+ <AlertDialogFooter>
138
+ <AlertDialogCancel>Cancel</AlertDialogCancel>
139
+ <AlertDialogAction
140
+ onClick={async () => {
141
+ setIsDeleting(true)
142
+ try {
143
+ await deleteUser(user.id)
144
+ toast({
145
+ title: 'User deleted'
146
+ })
147
+ router.push('/users')
148
+ } catch (err) {
149
+ toast({
150
+ title: 'Error deleting user',
151
+ variant: 'destructive'
152
+ })
153
+ }
154
+ setIsDeleting(false)
155
+ }}
156
+ >
157
+ Continue
158
+ </AlertDialogAction>
159
+ </AlertDialogFooter>
160
+ </AlertDialogContent>
161
+ </AlertDialog>
162
+ ) : undefined}
163
+ {user ? (
164
+ <Link href="/users/new">
165
+ <Button
166
+ type="button"
167
+ disabled={isSaving || isDeleting}
168
+ variant="secondary"
169
+ className="w-full"
170
+ >
171
+ <Icons.add className="mr-2 h-4 w-4" />
172
+ New
173
+ </Button>
174
+ </Link>
175
+ ) : undefined}
176
+ </div>
177
+
178
+ <FormField
179
+ control={form.control}
180
+ name="name"
181
+ render={({ field }) => (
182
+ <FormItem>
183
+ <FormLabel>Name</FormLabel>
184
+ <FormControl>
185
+ <Input
186
+ type="text"
187
+ placeholder="Enter a name"
188
+ disabled={isSaving}
189
+ {...field}
190
+ />
191
+ </FormControl>
192
+ <FormMessage />
193
+ </FormItem>
194
+ )}
195
+ />
196
+
197
+ <FormField
198
+ control={form.control}
199
+ name="email"
200
+ render={({ field }) => (
201
+ <FormItem>
202
+ <FormLabel>Email</FormLabel>
203
+ <FormControl>
204
+ <Input
205
+ type="email"
206
+ placeholder="Enter an email"
207
+ autoCapitalize="none"
208
+ autoComplete="email"
209
+ autoCorrect="off"
210
+ disabled={isSaving}
211
+ {...field}
212
+ />
213
+ </FormControl>
214
+ <FormMessage />
215
+ </FormItem>
216
+ )}
217
+ />
218
+ </form>
219
+ </Form>
220
+ {user ? (
221
+ <SystemInfo
222
+ items={[
223
+ {
224
+ label: 'Id',
225
+ value: user.id
226
+ },
227
+ {
228
+ label: 'Created At',
229
+ value: formatDateTime(user.createdAt)
230
+ },
231
+ {
232
+ label: 'Updated At',
233
+ value: timesAgo(user.updatedAt)
234
+ }
235
+ ]}
236
+ />
237
+ ) : undefined}
238
+ </Shell>
239
+ )
240
+ }
@@ -0,0 +1,55 @@
1
+ 'use server'
2
+
3
+ import { User } from '@prisma/client'
4
+
5
+ import { getAuthSession } from '@/lib/auth'
6
+ import { prisma } from '@/lib/db'
7
+ import { UnwrapPromise } from '@/types/UnwrapPromise'
8
+
9
+ export const getUsers = async ({
10
+ page,
11
+ limit,
12
+ sortBy,
13
+ sortOrder,
14
+ name,
15
+ email
16
+ }: {
17
+ page: number
18
+ limit: number
19
+ sortBy?: keyof User
20
+ sortOrder?: 'asc' | 'desc'
21
+ name?: string
22
+ email?: string
23
+ }) => {
24
+ const session = await getAuthSession()
25
+ if (!session) throw new Error('Unauthorized')
26
+
27
+ const where = {
28
+ name: name ? { contains: name, mode: 'insensitive' as const } : undefined,
29
+ email: email ? { contains: email, mode: 'insensitive' as const } : undefined
30
+ }
31
+ const [users, total] = await Promise.all([
32
+ prisma.user.findMany({
33
+ where,
34
+ select: {
35
+ id: true,
36
+ name: true,
37
+ email: true,
38
+ createdAt: true,
39
+ updatedAt: true
40
+ },
41
+ skip: (page - 1) * limit,
42
+ take: limit,
43
+ orderBy: {
44
+ [sortBy || 'createdAt']: sortOrder || 'desc'
45
+ }
46
+ }),
47
+ prisma.user.count({
48
+ where
49
+ })
50
+ ])
51
+
52
+ return { users, total }
53
+ }
54
+
55
+ export type GetUsersFnDataType = UnwrapPromise<ReturnType<typeof getUsers>>
@@ -0,0 +1,49 @@
1
+ import { User } from '@prisma/client'
2
+ import { Metadata } from 'next'
3
+
4
+ import { siteConfig } from '@/lib/siteConfig'
5
+ import { getUsers } from './actions'
6
+ import { Render } from './render'
7
+
8
+ export const metadata: Metadata = {
9
+ title: 'Users' + ' | ' + siteConfig.name
10
+ }
11
+
12
+ const Users = async ({
13
+ searchParams
14
+ }: {
15
+ searchParams: {
16
+ page?: string
17
+ limit?: string
18
+ sort?: string
19
+ name?: string
20
+ email?: string
21
+ }
22
+ }) => {
23
+ const page = searchParams.page ? parseInt(searchParams.page) : 1
24
+ const limit = searchParams.limit ? parseInt(searchParams.limit) : 10
25
+
26
+ const [sortBy, sortOrder] =
27
+ typeof searchParams.sort === 'string'
28
+ ? (searchParams.sort.split('.') as [
29
+ keyof User | undefined,
30
+ 'asc' | 'desc' | undefined
31
+ ])
32
+ : []
33
+
34
+ const name = searchParams.name
35
+ const email = searchParams.email
36
+
37
+ const data = await getUsers({
38
+ page,
39
+ limit,
40
+ sortBy,
41
+ sortOrder,
42
+ name,
43
+ email
44
+ })
45
+
46
+ return <Render data={data} />
47
+ }
48
+
49
+ export default Users
@@ -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
+ import { GetUsersFnDataType } from './actions'
14
+
15
+ export const Render: FC<{
16
+ data: GetUsersFnDataType
17
+ }> = ({ data }) => {
18
+ return (
19
+ <Shell>
20
+ <Heading heading="Users" text="List of all the users">
21
+ <Link href="/users/new">
22
+ <Button>
23
+ <Icons.add className="mr-2 h-4 w-4" />
24
+ New
25
+ </Button>
26
+ </Link>
27
+ </Heading>
28
+ <DataTable
29
+ columns={[
30
+ {
31
+ accessorKey: 'name',
32
+ header: ({ column }) => (
33
+ <DataTableColumnHeader column={column} title="Name" />
34
+ ),
35
+ cell: ({ row }) => (
36
+ <Link
37
+ className="underline underline-offset-4"
38
+ href={`/users/${row.original.id}`}
39
+ >
40
+ {row.original.name}
41
+ </Link>
42
+ )
43
+ },
44
+ {
45
+ accessorKey: 'email',
46
+ header: ({ column }) => (
47
+ <DataTableColumnHeader column={column} title="Email" />
48
+ )
49
+ },
50
+ {
51
+ accessorKey: 'createdAt',
52
+ header: ({ column }) => (
53
+ <DataTableColumnHeader column={column} title="Created At" />
54
+ ),
55
+ cell: ({ row }) => formatDateTime(row.original.createdAt)
56
+ },
57
+ {
58
+ accessorKey: 'updatedAt',
59
+ header: ({ column }) => (
60
+ <DataTableColumnHeader column={column} title="Updated At" />
61
+ ),
62
+ cell: ({ row }) => timesAgo(row.original.updatedAt)
63
+ }
64
+ ]}
65
+ data={data.users}
66
+ total={data.total}
67
+ searchableColumns={[
68
+ {
69
+ id: 'name',
70
+ title: 'Name'
71
+ },
72
+ {
73
+ id: 'email',
74
+ title: 'Email'
75
+ }
76
+ ]}
77
+ />
78
+ </Shell>
79
+ )
80
+ }
@@ -0,0 +1,20 @@
1
+ import { redirect } from 'next/navigation'
2
+ import { ReactNode } from 'react'
3
+
4
+ import { SiteFooter } from '@/components/site-footer'
5
+ import { getAuthSession } from '@/lib/auth'
6
+
7
+ const AuthLayout = async ({ children }: { children: ReactNode }) => {
8
+ const session = await getAuthSession()
9
+
10
+ if (session?.user) return redirect('/dashboard')
11
+
12
+ return (
13
+ <div className="flex min-h-screen flex-col justify-between">
14
+ <main>{children}</main>
15
+ <SiteFooter />
16
+ </div>
17
+ )
18
+ }
19
+
20
+ export default AuthLayout
@@ -0,0 +1,49 @@
1
+ import Link from 'next/link'
2
+
3
+ import { Icons } from '@/components/icons'
4
+ import { Button } from '@/components/ui/button'
5
+ import { UserAuthForm } from './user-auth-form'
6
+
7
+ const LoginPage = () => {
8
+ return (
9
+ <div className="container flex h-[90vh] w-screen flex-col items-center justify-center">
10
+ <Link href="/" className="absolute left-4 top-4">
11
+ <Button variant="ghost">
12
+ <Icons.chevronLeft className="mr-2 h-4 w-4" />
13
+ Back
14
+ </Button>
15
+ </Link>
16
+ <div className="mx-auto flex w-full flex-col justify-center space-y-6 sm:w-80">
17
+ <div className="flex flex-col space-y-2 text-center">
18
+ <Icons.logo className="mx-auto h-6 w-6" />
19
+ <h1 className="text-2xl font-semibold tracking-tight">
20
+ Welcome back
21
+ </h1>
22
+ <p className="text-sm text-muted-foreground">
23
+ Enter your email to sign in to your account
24
+ </p>
25
+ </div>
26
+ <UserAuthForm />
27
+ <p className="px-8 text-center text-sm text-muted-foreground">
28
+ By clicking continue, you agree to our{' '}
29
+ <Link
30
+ href="/terms"
31
+ className="underline underline-offset-4 hover:text-primary"
32
+ >
33
+ Terms of Service
34
+ </Link>{' '}
35
+ and{' '}
36
+ <Link
37
+ href="/privacy"
38
+ className="underline underline-offset-4 hover:text-primary"
39
+ >
40
+ Privacy Policy
41
+ </Link>
42
+ .
43
+ </p>
44
+ </div>
45
+ </div>
46
+ )
47
+ }
48
+
49
+ export default LoginPage
@@ -0,0 +1,42 @@
1
+ import { ReactNode } from 'react'
2
+
3
+ import { Icons } from '@/components/icons'
4
+ import { MainNav } from '@/components/main-nav'
5
+ import { SiteFooter } from '@/components/site-footer'
6
+ import { Button } from '@/components/ui/button'
7
+ import { getAuthSession } from '@/lib/auth'
8
+ import Link from 'next/link'
9
+
10
+ const Layout = async ({ children }: { children: ReactNode }) => {
11
+ const session = await getAuthSession()
12
+
13
+ return (
14
+ <div className="flex min-h-screen flex-col space-y-4">
15
+ <header className="sticky top-0 z-40 border-b bg-background">
16
+ <div className="container flex h-16 items-center justify-between py-4">
17
+ <MainNav />
18
+ <div className="flex items-center justify-center space-x-4">
19
+ {session?.user ? (
20
+ <Link href="/dashboard">
21
+ <Button size="sm" variant="secondary">
22
+ Dashboard
23
+ </Button>
24
+ </Link>
25
+ ) : (
26
+ <Link href="/login">
27
+ <Button size="sm" variant="secondary">
28
+ <Icons.login className="mr-2 h-4 w-4" />
29
+ Sign In
30
+ </Button>
31
+ </Link>
32
+ )}
33
+ </div>
34
+ </div>
35
+ </header>
36
+ <main className="flex-1">{children}</main>
37
+ <SiteFooter className="border-t" />
38
+ </div>
39
+ )
40
+ }
41
+
42
+ export default Layout