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,287 @@
1
+ import { createId } from '@paralleldrive/cuid2'
2
+ import { relations, sql } from 'drizzle-orm'
3
+ import {
4
+ bigint,
5
+ boolean,
6
+ index,
7
+ integer,
8
+ pgEnum,
9
+ pgTable,
10
+ primaryKey,
11
+ text,
12
+ timestamp,
13
+ unique,
14
+ varchar
15
+ } from 'drizzle-orm/pg-core'
16
+
17
+ export const Account = pgTable(
18
+ 'Accounts',
19
+ {
20
+ id: text('id')
21
+ .notNull()
22
+ .primaryKey()
23
+ .$defaultFn(() => createId()),
24
+ userId: text('userId')
25
+ .notNull()
26
+ .references(() => User.id),
27
+ type: varchar('type', { length: 255 }).notNull(),
28
+ provider: varchar('provider', { length: 255 }).notNull(),
29
+ providerAccountId: varchar('providerAccountId', { length: 255 }).notNull(),
30
+ refresh_token: text('refresh_token'),
31
+ access_token: text('access_token'),
32
+ expires_at: integer('expires_at'),
33
+ token_type: varchar('token_type', { length: 255 }),
34
+ scope: varchar('scope', { length: 255 }),
35
+ id_token: text('id_token'),
36
+ session_state: varchar('session_state', { length: 255 })
37
+ },
38
+ account => ({
39
+ userIdIdx: index('Accounts_idx_userId').on(account.userId),
40
+ uniqueProviderAccount: unique('Accounts_uq_provider_providerAccountId').on(
41
+ account.provider,
42
+ account.providerAccountId
43
+ )
44
+ })
45
+ )
46
+
47
+ export const AccountRelations = relations(Account, ({ one }) => ({
48
+ user: one(User, { fields: [Account.userId], references: [User.id] })
49
+ }))
50
+
51
+ export const Session = pgTable(
52
+ 'Sessions',
53
+ {
54
+ id: text('id')
55
+ .notNull()
56
+ .primaryKey()
57
+ .$defaultFn(() => createId()),
58
+ sessionToken: varchar('sessionToken', { length: 255 }).notNull().unique(),
59
+ userId: text('userId')
60
+ .notNull()
61
+ .references(() => User.id),
62
+ expires: timestamp('expires', {
63
+ mode: 'date',
64
+ withTimezone: true
65
+ }).notNull(),
66
+ createdAt: timestamp('createdAt', {
67
+ mode: 'date',
68
+ withTimezone: true
69
+ })
70
+ .default(sql`CURRENT_TIMESTAMP`)
71
+ .notNull(),
72
+ updatedAt: timestamp('updatedAt', {
73
+ mode: 'date',
74
+ withTimezone: true
75
+ })
76
+ },
77
+ session => ({
78
+ userIdIdx: index('Sessions_idx_userId').on(session.userId)
79
+ })
80
+ )
81
+
82
+ export const SessionRelations = relations(Session, ({ one }) => ({
83
+ user: one(User, { fields: [Session.userId], references: [User.id] })
84
+ }))
85
+
86
+ export const Role = pgTable('Roles', {
87
+ id: text('id')
88
+ .notNull()
89
+ .primaryKey()
90
+ .$defaultFn(() => createId()),
91
+ name: varchar('name', { length: 255 }).notNull().unique(),
92
+ createdAt: timestamp('createdAt', {
93
+ mode: 'date',
94
+ withTimezone: true
95
+ })
96
+ .default(sql`CURRENT_TIMESTAMP`)
97
+ .notNull(),
98
+ updatedAt: timestamp('updatedAt', {
99
+ mode: 'date',
100
+ withTimezone: true
101
+ })
102
+ })
103
+
104
+ export const RoleRelations = relations(Role, ({ many }) => ({
105
+ permissions: many(RolePermission),
106
+ users: many(User)
107
+ }))
108
+
109
+ export const PermissionEnum = pgEnum('PermissionEnum', [
110
+ 'TaskList',
111
+ 'TaskView',
112
+ 'TaskCreate',
113
+ 'TaskUpdate',
114
+ 'TaskDelete'
115
+ ])
116
+
117
+ export const RolePermission = pgTable(
118
+ 'RolePermissions',
119
+ {
120
+ id: text('id')
121
+ .notNull()
122
+ .primaryKey()
123
+ .$defaultFn(() => createId()),
124
+ roleId: text('roleId')
125
+ .notNull()
126
+ .references(() => Role.id, {
127
+ onDelete: 'cascade'
128
+ }),
129
+ permission: PermissionEnum('permission').notNull()
130
+ },
131
+ rp => ({
132
+ roleIdIdx: index('RolePermissions_idx_roleId').on(rp.roleId),
133
+ uniqueRolePermission: unique('RolePermissions_uq_roleId_permission').on(
134
+ rp.roleId,
135
+ rp.permission
136
+ )
137
+ })
138
+ )
139
+
140
+ export const RolePermissionRelations = relations(RolePermission, ({ one }) => ({
141
+ role: one(Role, { fields: [RolePermission.roleId], references: [Role.id] })
142
+ }))
143
+
144
+ export const UserTypeEnum = pgEnum('UserTypeEnum', ['Root', 'Normal'])
145
+
146
+ export const User = pgTable('Users', {
147
+ id: text('id')
148
+ .notNull()
149
+ .primaryKey()
150
+ .$defaultFn(() => createId()),
151
+ name: varchar('name', { length: 255 }),
152
+ email: varchar('email', { length: 255 }).notNull().unique(),
153
+ emailVerified: timestamp('emailVerified', {
154
+ mode: 'date',
155
+ withTimezone: true
156
+ }),
157
+ image: varchar('image', { length: 255 }),
158
+ type: UserTypeEnum('type').notNull().default('Normal'),
159
+ roleId: text('roleId').references(() => Role.id),
160
+ createdAt: timestamp('createdAt', {
161
+ mode: 'date',
162
+ withTimezone: true
163
+ })
164
+ .default(sql`CURRENT_TIMESTAMP`)
165
+ .notNull(),
166
+ updatedAt: timestamp('updatedAt', {
167
+ mode: 'date',
168
+ withTimezone: true
169
+ })
170
+ })
171
+
172
+ export const UserRelations = relations(User, ({ many, one }) => ({
173
+ accounts: many(Account),
174
+ sessions: many(Session),
175
+ role: one(Role, {
176
+ fields: [User.roleId],
177
+ references: [Role.id]
178
+ })
179
+ }))
180
+
181
+ export const VerificationToken = pgTable(
182
+ 'VerificationTokens',
183
+ {
184
+ identifier: varchar('identifier', { length: 255 }).notNull(),
185
+ token: varchar('token', { length: 255 }).notNull(),
186
+ expires: timestamp('expires', {
187
+ mode: 'date',
188
+ withTimezone: true
189
+ }).notNull()
190
+ },
191
+ vt => ({
192
+ pk: primaryKey({ columns: [vt.identifier, vt.token] })
193
+ })
194
+ )
195
+
196
+ export const TaskStatusEnum = pgEnum('TaskStatusEnum', [
197
+ 'Backlog',
198
+ 'Todo',
199
+ 'In Progress',
200
+ 'Done',
201
+ 'Cancelled'
202
+ ])
203
+
204
+ export const Task = pgTable('Tasks', {
205
+ id: text('id')
206
+ .notNull()
207
+ .primaryKey()
208
+ .$defaultFn(() => createId()),
209
+ title: varchar('title', { length: 255 }).notNull(),
210
+ status: TaskStatusEnum('status').notNull().default('Todo'),
211
+ description: text('description'),
212
+ createdAt: timestamp('createdAt', {
213
+ mode: 'date',
214
+ withTimezone: true
215
+ })
216
+ .default(sql`CURRENT_TIMESTAMP`)
217
+ .notNull(),
218
+ updatedAt: timestamp('updatedAt', {
219
+ mode: 'date',
220
+ withTimezone: true
221
+ }),
222
+ createdById: text('createdById')
223
+ .notNull()
224
+ .references(() => User.id),
225
+ updatedById: text('updatedById').references(() => User.id)
226
+ })
227
+
228
+ export const TaskRelations = relations(Task, ({ one, many }) => ({
229
+ createdBy: one(User, {
230
+ fields: [Task.createdById],
231
+ references: [User.id]
232
+ }),
233
+ updatedBy: one(User, {
234
+ fields: [Task.updatedById],
235
+ references: [User.id]
236
+ }),
237
+ images: many(Resource)
238
+ }))
239
+
240
+ export const Resource = pgTable(
241
+ 'Resources',
242
+ {
243
+ id: text('id')
244
+ .notNull()
245
+ .primaryKey()
246
+ .$defaultFn(() => createId()),
247
+ filename: varchar('filename', { length: 255 }).notNull(),
248
+ key: varchar('key', { length: 255 }).notNull().unique(),
249
+ isTemp: boolean('isTemp').notNull().default(false),
250
+ url: varchar('url', { length: 255 }).notNull().unique(),
251
+ size: bigint('size', { mode: 'number' }).notNull(),
252
+ contentType: varchar('contentType', { length: 255 }).notNull(),
253
+
254
+ taskId: text('taskId').references(() => Task.id),
255
+
256
+ createdAt: timestamp('createdAt', {
257
+ mode: 'date',
258
+ withTimezone: true
259
+ })
260
+ .default(sql`CURRENT_TIMESTAMP`)
261
+ .notNull(),
262
+ updatedAt: timestamp('updatedAt', {
263
+ mode: 'date',
264
+ withTimezone: true
265
+ }),
266
+ createdById: text('createdById').references(() => User.id),
267
+ updatedById: text('updatedById').references(() => User.id)
268
+ },
269
+ resource => ({
270
+ taskIdIdx: index('Resources_idx_taskId').on(resource.taskId)
271
+ })
272
+ )
273
+
274
+ export const ResourceRelations = relations(Resource, ({ one }) => ({
275
+ task: one(Task, {
276
+ fields: [Resource.taskId],
277
+ references: [Task.id]
278
+ }),
279
+ createdBy: one(User, {
280
+ fields: [Resource.createdById],
281
+ references: [User.id]
282
+ }),
283
+ updatedBy: one(User, {
284
+ fields: [Resource.updatedById],
285
+ references: [User.id]
286
+ })
287
+ }))
@@ -2,22 +2,15 @@ import { createEnv } from '@t3-oss/env-nextjs'
2
2
  import { z } from 'zod'
3
3
 
4
4
  export const env = createEnv({
5
- /**
6
- * Specify your server-side environment variables schema here. This way you can ensure the app
7
- * isn't built with invalid env vars.
8
- */
9
5
  server: {
10
- NODE_ENV: z.enum(['development', 'test', 'production']),
6
+ NODE_ENV: z.enum(['development', 'production']),
11
7
  DATABASE_URL: z.string().url(),
12
8
  NEXTAUTH_SECRET:
13
9
  process.env.NODE_ENV === 'production'
14
10
  ? z.string().min(1)
15
11
  : z.string().min(1).optional(),
16
12
  NEXTAUTH_URL: z.preprocess(
17
- // This makes Vercel deployments not fail if you don't set NEXTAUTH_URL
18
- // Since NextAuth.js automatically uses the VERCEL_URL if present.
19
13
  str => process.env.VERCEL_URL ?? str,
20
- // VERCEL_URL doesn't include `https` so it cant be validated as a URL
21
14
  process.env.VERCEL ? z.string().min(1) : z.string().url()
22
15
  ),
23
16
  EMAIL_SERVER_HOST: z.string().min(1),
@@ -29,25 +22,16 @@ export const env = createEnv({
29
22
  GOOGLE_SECRET: z.string().min(1),
30
23
  GITHUB_ID: z.string().min(1),
31
24
  GITHUB_SECRET: z.string().min(1),
32
- FIREBASE_PROJECT_ID: z.string().min(1),
33
- FIREBASE_PRIVATE_KEY: z.string().min(1),
34
- FIREBASE_CLIENT_EMAIL: z.string().min(1),
35
- FIREBASE_STORAGE_BUCKET: z.string().min(1)
25
+ S3_REGION: z.string().min(1),
26
+ S3_BUCKET: z.string().min(1),
27
+ S3_ACCESS_KEY: z.string().min(1),
28
+ S3_SECRET_KEY: z.string().min(1)
36
29
  },
37
30
 
38
- /**
39
- * Specify your client-side environment variables schema here. This way you can ensure the app
40
- * isn't built with invalid env vars. To expose them to the client, prefix them with
41
- * `NEXT_PUBLIC_`.
42
- */
43
31
  client: {
44
32
  // NEXT_PUBLIC_CLIENTVAR: z.string().min(1),
45
33
  },
46
34
 
47
- /**
48
- * You can't destruct `process.env` as a regular object in the Next.js edge runtimes (e.g.
49
- * middlewares) or client-side so we need to destruct manually.
50
- */
51
35
  runtimeEnv: {
52
36
  NODE_ENV: process.env.NODE_ENV,
53
37
  DATABASE_URL: process.env.DATABASE_URL,
@@ -62,17 +46,13 @@ export const env = createEnv({
62
46
  GOOGLE_SECRET: process.env.GOOGLE_SECRET,
63
47
  GITHUB_ID: process.env.GITHUB_ID,
64
48
  GITHUB_SECRET: process.env.GITHUB_SECRET,
65
- FIREBASE_PROJECT_ID: process.env.FIREBASE_PROJECT_ID,
66
- FIREBASE_PRIVATE_KEY: process.env.FIREBASE_PRIVATE_KEY,
67
- FIREBASE_CLIENT_EMAIL: process.env.FIREBASE_CLIENT_EMAIL,
68
- FIREBASE_STORAGE_BUCKET: process.env.FIREBASE_STORAGE_BUCKET
49
+ S3_REGION: process.env.S3_REGION,
50
+ S3_BUCKET: process.env.S3_BUCKET,
51
+ S3_ACCESS_KEY: process.env.S3_ACCESS_KEY,
52
+ S3_SECRET_KEY: process.env.S3_SECRET_KEY
69
53
  },
70
- /**
71
- * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation.
72
- * This is especially useful for Docker builds.
73
- */
54
+
74
55
  skipValidation: !!process.env.SKIP_ENV_VALIDATION,
75
56
 
76
- // This makes empty strings be treated as undefined
77
57
  emptyStringAsUndefined: true
78
58
  })
@@ -1,6 +1,7 @@
1
+ 'use client'
2
+
1
3
  import { useLayoutEffect } from 'react'
2
4
 
3
- // @see https://usehooks.com/useLockBodyScroll.
4
5
  export function useLockBody() {
5
6
  useLayoutEffect((): (() => void) => {
6
7
  const originalStyle: string = window.getComputedStyle(
@@ -1,38 +1,36 @@
1
- import { PrismaAdapter } from '@next-auth/prisma-adapter'
2
- import { User as PrismaUser } from '@prisma/client'
1
+ import { DrizzleAdapter } from '@auth/drizzle-adapter'
2
+ import { InferSelectModel } from 'drizzle-orm'
3
3
  import {
4
+ Session as NextAuthSession,
4
5
  getServerSession,
5
6
  type DefaultSession,
6
7
  type NextAuthOptions
7
8
  } from 'next-auth'
9
+ import { Adapter } from 'next-auth/adapters'
8
10
  import EmailProvider from 'next-auth/providers/email'
9
11
  import GitHubProvider from 'next-auth/providers/github'
10
12
  import GoogleProvider from 'next-auth/providers/google'
13
+ import { cache } from 'react'
11
14
 
15
+ import type { RolePermissionType } from '@/data-access/role-permission'
16
+ import type { UserType } from '@/data-access/user'
17
+ import { db } from '@/db'
18
+ import { Account, Session, User, VerificationToken } from '@/db/schema'
12
19
  import { env } from '@/env.mjs'
13
- import { prisma } from '@/lib/db'
20
+ import { checkForRolePermissionUseCase } from '@/use-case/role-permission'
14
21
 
15
- /**
16
- * Module augmentation for `next-auth` types. Allows us to add custom properties to the `session`
17
- * object and keep type safety.
18
- *
19
- * @see https://next-auth.js.org/getting-started/typescript#module-augmentation
20
- */
21
22
  declare module 'next-auth' {
22
23
  interface Session extends DefaultSession {
23
24
  user: {
24
25
  id: string
26
+ type: UserType['type']
27
+ roleId?: string | null
25
28
  } & DefaultSession['user']
26
29
  }
27
30
 
28
- interface User extends PrismaUser {}
31
+ interface User extends InferSelectModel<typeof User> {}
29
32
  }
30
33
 
31
- /**
32
- * Options for NextAuth.js used to configure adapters, providers, callbacks, etc.
33
- *
34
- * @see https://next-auth.js.org/configuration/options
35
- */
36
34
  export const authOptions: NextAuthOptions = {
37
35
  pages: {
38
36
  signIn: '/login'
@@ -43,12 +41,19 @@ export const authOptions: NextAuthOptions = {
43
41
  ...session,
44
42
  user: {
45
43
  ...session.user,
46
- id: user.id
44
+ id: user.id,
45
+ type: user.type,
46
+ roleId: user.roleId
47
47
  }
48
48
  }
49
49
  }
50
50
  },
51
- adapter: PrismaAdapter(prisma),
51
+ adapter: DrizzleAdapter(db, {
52
+ usersTable: User,
53
+ accountsTable: Account,
54
+ sessionsTable: Session,
55
+ verificationTokensTable: VerificationToken
56
+ }) as Adapter,
52
57
  providers: [
53
58
  EmailProvider({
54
59
  server: {
@@ -72,9 +77,13 @@ export const authOptions: NextAuthOptions = {
72
77
  ]
73
78
  }
74
79
 
75
- /**
76
- * Wrapper for `getServerSession` so that you don't need to import the `authOptions` in every file.
77
- *
78
- * @see https://next-auth.js.org/configuration/nextjs
79
- */
80
- export const getAuthSession = () => getServerSession(authOptions)
80
+ export const getAuthSession = cache(() => getServerSession(authOptions))
81
+
82
+ export const authGuard = cache(
83
+ (session: NextAuthSession, permission?: RolePermissionType['permission']) =>
84
+ checkForRolePermissionUseCase(
85
+ session.user.type,
86
+ session.user.roleId,
87
+ permission
88
+ )
89
+ )
@@ -0,0 +1,8 @@
1
+ import { User } from '@/db/schema'
2
+ import { InferSelectModel } from 'drizzle-orm'
3
+
4
+ export type CurrentUser = {
5
+ id: string
6
+ type: InferSelectModel<typeof User>['type']
7
+ roleId?: string | null
8
+ }
@@ -0,0 +1,156 @@
1
+ import {
2
+ DeleteObjectCommand,
3
+ HeadObjectCommand,
4
+ HeadObjectCommandOutput,
5
+ S3Client
6
+ } from '@aws-sdk/client-s3'
7
+ import { createPresignedPost } from '@aws-sdk/s3-presigned-post'
8
+ import { createId } from '@paralleldrive/cuid2'
9
+ import { extname } from 'path'
10
+
11
+ import {
12
+ createResource,
13
+ deleteResource,
14
+ getResourceById,
15
+ updateResourceById
16
+ } from '@/data-access/resource'
17
+ import { env } from '@/env.mjs'
18
+ import { CurrentUser } from './currentUser'
19
+
20
+ export const S3_HOST = `https://${env.S3_BUCKET}.s3.${env.S3_REGION}.amazonaws.com`
21
+
22
+ export const s3Client = new S3Client({
23
+ region: env.S3_REGION,
24
+ credentials: {
25
+ accessKeyId: env.S3_ACCESS_KEY,
26
+ secretAccessKey: env.S3_SECRET_KEY
27
+ }
28
+ })
29
+
30
+ export const getUrl = (key: string) => `${S3_HOST}/${key}`
31
+
32
+ const uploadLimit = 1024 * 1024 * 10 // 10 MB
33
+
34
+ export const getPresignedUrl = async ({
35
+ filename,
36
+ contentType,
37
+ contentTypeStartsWith,
38
+ isPublic,
39
+ createdById
40
+ }: {
41
+ filename: string
42
+ contentType: string
43
+ contentTypeStartsWith?: string
44
+ isPublic?: boolean
45
+ createdById?: string | null
46
+ }) => {
47
+ const id = createId()
48
+
49
+ const extension = extname(filename)
50
+
51
+ const key = `${id}${extension}`
52
+
53
+ const url = getUrl(key)
54
+
55
+ await createResource({
56
+ id,
57
+ filename,
58
+ key,
59
+ isTemp: true,
60
+ url,
61
+ createdById,
62
+ size: 0,
63
+ contentType
64
+ })
65
+
66
+ const Conditions: any[] = [
67
+ ['content-length-range', 1024, uploadLimit],
68
+ { bucket: env.S3_BUCKET },
69
+ { key },
70
+ ['eq', '$Content-Type', contentType],
71
+ ['eq', '$x-amz-meta-filename', filename],
72
+ ['eq', '$x-amz-meta-extension', extension]
73
+ ]
74
+
75
+ if (isPublic) Conditions.push({ acl: 'public-read' })
76
+ if (contentTypeStartsWith)
77
+ Conditions.push(['starts-with', '$Content-Type', contentTypeStartsWith])
78
+ if (createdById)
79
+ Conditions.push(['eq', '$x-amz-meta-createdById', createdById])
80
+
81
+ const presigned = await createPresignedPost(s3Client, {
82
+ Bucket: env.S3_BUCKET,
83
+ Key: key,
84
+ Expires: 300,
85
+ Conditions,
86
+ Fields: {
87
+ ...(isPublic
88
+ ? {
89
+ acl: 'public-read'
90
+ }
91
+ : {}),
92
+
93
+ ...(createdById
94
+ ? {
95
+ 'X-Amz-Meta-createdById': createdById
96
+ }
97
+ : {}),
98
+
99
+ 'X-Amz-Meta-filename': filename,
100
+ 'X-Amz-Meta-extension': extension,
101
+ 'Content-Type': contentType,
102
+ 'Content-Disposition': `inline; filename="${encodeURIComponent(filename)}"`
103
+ }
104
+ })
105
+
106
+ return {
107
+ id,
108
+ key,
109
+ url,
110
+ presigned
111
+ }
112
+ }
113
+
114
+ export const markFileUploaded = async (
115
+ currentUser: CurrentUser,
116
+ id: string
117
+ ) => {
118
+ const resource = await getResourceById(id)
119
+
120
+ if (!resource) throw new Error('Resource not found')
121
+
122
+ let response: HeadObjectCommandOutput
123
+ try {
124
+ response = await s3Client.send(
125
+ new HeadObjectCommand({
126
+ Bucket: env.S3_BUCKET,
127
+ Key: resource.key
128
+ })
129
+ )
130
+ } catch (err) {
131
+ throw new Error('File not found')
132
+ }
133
+
134
+ await updateResourceById({
135
+ id: resource.id,
136
+ isTemp: false,
137
+ contentType: response.ContentType,
138
+ size: response.ContentLength,
139
+ updatedById: currentUser.id
140
+ })
141
+ }
142
+
143
+ export const deleteFile = async (id: string) => {
144
+ const resource = await getResourceById(id)
145
+
146
+ if (!resource) throw new Error('Resource not found')
147
+
148
+ await s3Client.send(
149
+ new DeleteObjectCommand({
150
+ Bucket: env.S3_BUCKET,
151
+ Key: resource.key
152
+ })
153
+ )
154
+
155
+ await deleteResource(id)
156
+ }
@@ -0,0 +1,19 @@
1
+ import { createSafeActionClient } from 'next-safe-action'
2
+
3
+ import { getAuthSession } from './auth'
4
+
5
+ const actionClient = createSafeActionClient()
6
+
7
+ export const authActionClient = actionClient.use(async ({ next }) => {
8
+ const session = await getAuthSession()
9
+
10
+ if (!session?.user) {
11
+ throw new Error('Unauthorized')
12
+ }
13
+
14
+ return next({
15
+ ctx: {
16
+ user: session.user
17
+ }
18
+ })
19
+ })
@@ -0,0 +1,2 @@
1
+ export const SortOrderEnum = ['asc', 'desc'] as const
2
+ export type SortOrderEnum = (typeof SortOrderEnum)[number]
@@ -0,0 +1,19 @@
1
+ import {
2
+ checkForRolePermission,
3
+ type RolePermissionType
4
+ } from '@/data-access/role-permission'
5
+ import { type UserType } from '@/data-access/user'
6
+
7
+ export const checkForRolePermissionUseCase = async (
8
+ userType: UserType['type'],
9
+ roleId?: string | null,
10
+ permission?: RolePermissionType['permission']
11
+ ) => {
12
+ if (userType === 'Root') return true
13
+
14
+ if (!roleId) return false
15
+
16
+ if (!permission) return true
17
+
18
+ return await checkForRolePermission(roleId, permission)
19
+ }