create-mithaq 0.1.1 → 0.2.1

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 (348) hide show
  1. package/LICENSES/openstatus-time-picker.txt +21 -0
  2. package/index.js +457 -63
  3. package/package.json +1 -1
  4. package/template/apps/{asas-platform → asas-backoffice}/package.json +5 -3
  5. package/template/apps/{asas-platform → asas-backoffice}/src/api.ts +1 -1
  6. package/template/apps/{asas-platform → asas-backoffice}/src/auth-frame.tsx +12 -12
  7. package/template/apps/asas-backoffice/src/components.ts +35 -0
  8. package/template/apps/asas-backoffice/src/first-user.ts +14 -0
  9. package/template/apps/{asas-platform → asas-backoffice}/src/links.ts +1 -1
  10. package/template/apps/{asas-platform → asas-backoffice}/src/locale-switch.tsx +7 -5
  11. package/template/apps/asas-backoffice/src/no-organization.tsx +5 -0
  12. package/template/apps/asas-backoffice/src/redirect.ts +1 -0
  13. package/template/apps/{asas-platform → asas-backoffice}/src/request-headers.ts +1 -1
  14. package/template/apps/asas-backoffice/src/routeTree.gen.ts +206 -0
  15. package/template/apps/asas-backoffice/src/router.tsx +18 -0
  16. package/template/apps/asas-backoffice/src/routes/(screens)/backoffice/files.ts +10 -0
  17. package/template/apps/{asas-platform/src/routes/(screens)/platform → asas-backoffice/src/routes/(screens)/backoffice}/screen.json +426 -64
  18. package/template/apps/{asas-platform/src/routes/(screens)/platform → asas-backoffice/src/routes/(screens)/backoffice}/types.ts +18 -0
  19. package/template/apps/{asas-platform/src/routes/(screens)/platform.$.tsx → asas-backoffice/src/routes/(screens)/backoffice.$.tsx} +4 -4
  20. package/template/apps/{asas-platform/src/routes/(screens)/platform.index.tsx → asas-backoffice/src/routes/(screens)/backoffice.index.tsx} +3 -3
  21. package/template/apps/{asas-platform/src/routes/(screens)/platform.tsx → asas-backoffice/src/routes/(screens)/backoffice.tsx} +3 -3
  22. package/template/apps/{asas-platform → asas-backoffice}/src/routes/__root.tsx +2 -2
  23. package/template/apps/asas-backoffice/src/routes/api/$.ts +34 -0
  24. package/template/apps/asas-backoffice/src/routes/auth.create-first-user.tsx +113 -0
  25. package/template/apps/{asas-platform → asas-backoffice}/src/routes/auth.sign-in.tsx +9 -4
  26. package/template/apps/{asas-platform → asas-backoffice}/src/routes/unauthorized.tsx +24 -12
  27. package/template/apps/{asas-platform → asas-backoffice}/src/screen-form.tsx +5 -3
  28. package/template/apps/{asas-platform → asas-backoffice}/src/screen-list.tsx +6 -5
  29. package/template/apps/{asas-platform → asas-backoffice}/src/screen-names.ts +1 -1
  30. package/template/apps/{asas-platform → asas-backoffice}/src/screens.tsx +46 -26
  31. package/template/apps/asas-backoffice/src/server.ts +30 -0
  32. package/template/apps/{asas-platform → asas-backoffice}/src/slide.ts +1 -1
  33. package/template/apps/{asas-platform → asas-backoffice}/src/start.ts +1 -1
  34. package/template/apps/{asas-platform → asas-backoffice}/src/styles.css +9 -7
  35. package/template/apps/{asas-platform → asas-backoffice}/tsconfig.json +2 -2
  36. package/template/apps/{asas-platform → asas-backoffice}/vite.config.ts +7 -1
  37. package/template/apps/asas-tanstack/package.json +4 -2
  38. package/template/apps/asas-tanstack/src/api.ts +1 -1
  39. package/template/apps/asas-tanstack/src/auth-frame.tsx +12 -12
  40. package/template/apps/asas-tanstack/src/choose-password.tsx +150 -0
  41. package/template/apps/asas-tanstack/src/components.ts +35 -0
  42. package/template/apps/asas-tanstack/src/copy.ts +416 -79
  43. package/template/apps/asas-tanstack/src/first-run.ts +16 -0
  44. package/template/apps/asas-tanstack/src/links.ts +1 -1
  45. package/template/apps/asas-tanstack/src/locale-switch.tsx +7 -5
  46. package/template/apps/asas-tanstack/src/no-organization.tsx +108 -0
  47. package/template/apps/asas-tanstack/src/redirect.ts +20 -1
  48. package/template/apps/asas-tanstack/src/request-headers.ts +1 -1
  49. package/template/apps/asas-tanstack/src/routeTree.gen.ts +42 -0
  50. package/template/apps/asas-tanstack/src/router.tsx +12 -1
  51. package/template/apps/asas-tanstack/src/routes/(screens)/dashboard/files.ts +9 -2
  52. package/template/apps/asas-tanstack/src/routes/(screens)/dashboard/screen.json +475 -116
  53. package/template/apps/asas-tanstack/src/routes/(screens)/dashboard/types.ts +4 -2
  54. package/template/apps/asas-tanstack/src/routes/(screens)/portal/files.ts +7 -2
  55. package/template/apps/asas-tanstack/src/routes/(screens)/portal/screen.json +83 -319
  56. package/template/apps/asas-tanstack/src/routes/(screens)/portal/types.ts +3 -1
  57. package/template/apps/asas-tanstack/src/routes/__root.tsx +1 -1
  58. package/template/apps/asas-tanstack/src/routes/auth.accept-invitation.tsx +14 -7
  59. package/template/apps/asas-tanstack/src/routes/auth.first-run.tsx +114 -0
  60. package/template/apps/asas-tanstack/src/routes/auth.forgot-password.tsx +2 -2
  61. package/template/apps/asas-tanstack/src/routes/auth.handoff.ts +5 -5
  62. package/template/apps/asas-tanstack/src/routes/auth.reset-password.tsx +7 -100
  63. package/template/apps/asas-tanstack/src/routes/auth.set-password.tsx +16 -0
  64. package/template/apps/asas-tanstack/src/routes/auth.sign-in.tsx +27 -15
  65. package/template/apps/asas-tanstack/src/routes/auth.sign-up.tsx +59 -38
  66. package/template/apps/asas-tanstack/src/routes/index.tsx +18 -14
  67. package/template/apps/asas-tanstack/src/routes/unauthorized.tsx +24 -12
  68. package/template/apps/asas-tanstack/src/screen-form.tsx +5 -3
  69. package/template/apps/asas-tanstack/src/screen-list.tsx +6 -5
  70. package/template/apps/asas-tanstack/src/screen-names.ts +1 -1
  71. package/template/apps/asas-tanstack/src/screens.tsx +46 -26
  72. package/template/apps/asas-tanstack/src/server.ts +10 -0
  73. package/template/apps/asas-tanstack/src/slide.ts +1 -1
  74. package/template/apps/asas-tanstack/src/styles.css +7 -3
  75. package/template/apps/asas-tanstack/tsconfig.json +2 -2
  76. package/template/apps/asas-tanstack/vite.config.ts +7 -1
  77. package/template/package.json +3 -3
  78. package/template/templates/asas/.claude/skills/add-field/SKILL.md +27 -0
  79. package/template/templates/asas/.claude/skills/add-kayan/SKILL.md +26 -0
  80. package/template/templates/asas/.claude/skills/eject-admin-piece/SKILL.md +28 -0
  81. package/template/templates/asas/.claude/skills/upgrade-mithaq/SKILL.md +35 -0
  82. package/template/templates/asas/.env.example +22 -5
  83. package/template/templates/asas/AGENTS.md +101 -0
  84. package/template/templates/asas/CLAUDE.md +1 -0
  85. package/template/templates/asas/README.md +1094 -0
  86. package/template/templates/asas/package.json +19 -4
  87. package/template/templates/asas/src/asas.ts +81 -56
  88. package/template/templates/asas/src/{platform-http.ts → backoffice-http.ts} +48 -27
  89. package/template/templates/asas/src/dev-setup.ts +112 -0
  90. package/template/templates/asas/src/local-database.ts +22 -0
  91. package/template/templates/asas/src/messages/account.json +129 -103
  92. package/template/templates/asas/src/messages/auditLog.json +223 -105
  93. package/template/templates/asas/src/messages/backofficeLog.json +132 -0
  94. package/template/templates/asas/src/messages/courses.json +256 -214
  95. package/template/templates/asas/src/messages/enrollments.json +45 -27
  96. package/template/templates/asas/src/messages/invitation.json +72 -56
  97. package/template/templates/asas/src/messages/localUsers.json +34 -28
  98. package/template/templates/asas/src/messages/media.json +31 -21
  99. package/template/templates/asas/src/messages/member.json +59 -39
  100. package/template/templates/asas/src/messages/memberRoles.json +37 -31
  101. package/template/templates/asas/src/messages/mithaq.json +206 -162
  102. package/template/templates/asas/src/messages/organization.json +63 -41
  103. package/template/templates/asas/src/messages/organizationRole.json +59 -47
  104. package/template/templates/asas/src/messages/roles.json +59 -45
  105. package/template/templates/asas/src/messages/session.json +99 -79
  106. package/template/templates/asas/src/messages/sessions.json +110 -80
  107. package/template/templates/asas/src/messages/settings.json +51 -53
  108. package/template/templates/asas/src/messages/tags.json +31 -21
  109. package/template/templates/asas/src/messages/user.json +109 -87
  110. package/template/templates/asas/src/messages/verification.json +59 -47
  111. package/template/templates/asas/src/migrations/20261014221355_tags_restrict/migration.sql +1 -0
  112. package/template/templates/asas/src/migrations/20261014221355_tags_restrict/snapshot.json +3881 -0
  113. package/template/templates/asas/src/migrations/20261014222218_one_seat_per_session/migration.sql +1 -0
  114. package/template/templates/asas/src/migrations/20261014222218_one_seat_per_session/snapshot.json +3894 -0
  115. package/template/templates/asas/src/migrations/20261014223522_session_archive_reason/migration.sql +1 -0
  116. package/template/templates/asas/src/migrations/20261014223522_session_archive_reason/snapshot.json +3907 -0
  117. package/template/templates/asas/src/migrations/20261014225728_course_archive_by_operation/migration.sql +1 -0
  118. package/template/templates/asas/src/migrations/20261014225728_course_archive_by_operation/snapshot.json +3907 -0
  119. package/template/templates/asas/src/migrations/20261015042444_organization_names/migration.sql +1 -0
  120. package/template/templates/asas/src/migrations/20261015042444_organization_names/snapshot.json +3920 -0
  121. package/template/templates/asas/src/migrations/20261015053212_member_last_seen/migration.sql +1 -0
  122. package/template/templates/asas/src/migrations/20261015053212_member_last_seen/snapshot.json +3933 -0
  123. package/template/templates/asas/src/migrations/20261015093203_activity_and_staff_history/migration.sql +15 -0
  124. package/template/templates/asas/src/migrations/20261015093203_activity_and_staff_history/snapshot.json +4113 -0
  125. package/template/templates/asas/src/migrations/20261015095752_portal/migration.sql +2 -0
  126. package/template/templates/asas/src/migrations/20261015095752_portal/snapshot.json +4113 -0
  127. package/template/templates/asas/src/migrations/20261015135529_better_auth_indexes/migration.sql +9 -0
  128. package/template/templates/asas/src/migrations/20261015135529_better_auth_indexes/snapshot.json +4302 -0
  129. package/template/templates/asas/src/migrations/20261015162438_audit_changes_json/migration.sql +27 -0
  130. package/template/templates/asas/src/migrations/20261015162438_audit_changes_json/snapshot.json +4289 -0
  131. package/template/templates/asas/src/migrations/schema.ts +1 -0
  132. package/template/templates/asas/src/mithaq.ts +4 -406
  133. package/template/templates/asas/src/organizations.ts +3 -0
  134. package/template/templates/asas/src/seed.ts +147 -45
  135. package/template/templates/asas/src/{ui-platform → ui-backoffice}/home.tsx +9 -9
  136. package/template/templates/asas/src/ui-backoffice/organization-actions.tsx +121 -0
  137. package/template/templates/asas/src/{ui-platform → ui-backoffice}/record-page.tsx +4 -4
  138. package/template/templates/asas/src/{ui-platform → ui-backoffice}/role-cells.tsx +13 -6
  139. package/template/templates/asas/src/{ui-platform → ui-backoffice}/user-actions.tsx +46 -48
  140. package/template/templates/asas/src/ui-dashboard/dashboard.tsx +10 -4
  141. package/template/templates/asas/src/ui-dashboard/home.tsx +73 -0
  142. package/template/templates/asas/src/ui-dashboard/members-card.tsx +147 -0
  143. package/template/templates/asas/src/ui-dashboard/members.tsx +637 -438
  144. package/template/templates/asas/src/ui-dashboard/versions.tsx +22 -8
  145. package/template/templates/asas/src/ui-portal/courses-home.tsx +96 -0
  146. package/template/templates/asas/src/ui-portal/home.tsx +9 -13
  147. package/template/templates/features/audit-log/audit-log/audit-log.ts +284 -0
  148. package/template/templates/features/audit-log/backoffice-log/backoffice-log.ts +67 -0
  149. package/template/templates/features/audit-log/index.ts +4 -0
  150. package/template/templates/features/audit-log/package.json +13 -0
  151. package/template/templates/features/auth/index.ts +11 -0
  152. package/template/templates/{asas/src → features/auth}/local-users/local-users.ts +7 -7
  153. package/template/templates/{auth → features/auth}/package.json +2 -3
  154. package/template/templates/{asas/src/kayan → features}/auth/user/account.access.ts +2 -2
  155. package/template/templates/{asas/src/kayan → features}/auth/user/account.ts +2 -2
  156. package/template/templates/{asas/src/kayan → features}/auth/user/invitation.access.ts +1 -1
  157. package/template/templates/{asas/src/kayan → features}/auth/user/invitation.ts +3 -3
  158. package/template/templates/{asas/src/kayan → features}/auth/user/member.access.ts +4 -4
  159. package/template/templates/{asas/src/kayan → features}/auth/user/member.screens.ts +5 -5
  160. package/template/templates/{asas/src/kayan → features}/auth/user/member.ts +4 -3
  161. package/template/templates/{asas/src/kayan → features}/auth/user/organization.access.ts +6 -6
  162. package/template/templates/{asas/src/kayan → features}/auth/user/organization.screens.ts +6 -6
  163. package/template/templates/{asas/src/kayan → features}/auth/user/organization.ts +2 -1
  164. package/template/templates/{asas/src/kayan → features}/auth/user/organizationRole.access.ts +2 -2
  165. package/template/templates/{asas/src/kayan → features}/auth/user/organizationRole.ts +3 -3
  166. package/template/templates/{asas/src/kayan → features}/auth/user/session.access.ts +2 -2
  167. package/template/templates/{asas/src/kayan → features}/auth/user/session.ts +2 -2
  168. package/template/templates/{asas/src/kayan → features}/auth/user/user.access.ts +8 -7
  169. package/template/templates/{asas/src/kayan → features}/auth/user/user.screens.ts +9 -9
  170. package/template/templates/{asas/src/kayan → features}/auth/user/user.ts +2 -2
  171. package/template/templates/{asas/src/kayan → features}/auth/user/verification.access.ts +2 -2
  172. package/template/templates/{asas/src/kayan → features}/auth/user/verification.ts +2 -2
  173. package/template/templates/{asas/src → features/courses}/courses/courses.ts +122 -133
  174. package/template/templates/features/courses/courses/cover-reads.ts +33 -0
  175. package/template/templates/features/courses/courses/ui/archived-badge.tsx +9 -0
  176. package/template/templates/{asas/src → features/courses}/courses/ui/fee-cell.tsx +1 -1
  177. package/template/templates/{asas/src → features/courses}/courses/ui/status-cell.tsx +5 -3
  178. package/template/templates/features/courses/courses/ui/unpublish-button.tsx +15 -0
  179. package/template/templates/features/courses/domain/archive.ts +39 -0
  180. package/template/templates/features/courses/domain/on-offer.ts +6 -0
  181. package/template/templates/features/courses/enrollments/enrollments.ts +309 -0
  182. package/template/templates/{asas/src → features/courses}/enrollments/ui/session-cell.tsx +17 -7
  183. package/template/templates/{asas/src → features/courses/enrollments}/ui/session-labels.tsx +3 -3
  184. package/template/templates/features/courses/index.ts +8 -0
  185. package/template/templates/features/courses/package.json +24 -0
  186. package/template/templates/features/courses/portal/ui/catalogue.tsx +86 -0
  187. package/template/templates/features/courses/portal/ui/course.tsx +176 -0
  188. package/template/templates/features/courses/portal/ui/enrollments.tsx +170 -0
  189. package/template/templates/features/courses/portal/ui/parts.tsx +95 -0
  190. package/template/templates/features/courses/portal/ui/reads.ts +76 -0
  191. package/template/templates/features/courses/portal/ui/rules.ts +87 -0
  192. package/template/templates/features/courses/portal/ui/shell.tsx +194 -0
  193. package/template/templates/features/courses/sessions/seats.ts +42 -0
  194. package/template/templates/{asas/src → features/courses}/sessions/sessions.ts +45 -14
  195. package/template/templates/features/media/index.ts +10 -0
  196. package/template/templates/{asas/src → features/media}/media/media.ts +34 -40
  197. package/template/templates/{asas/src → features/media}/media/ui/preview.tsx +2 -2
  198. package/template/templates/features/media/package.json +19 -0
  199. package/template/templates/features/roles/index.ts +4 -0
  200. package/template/templates/{asas/src → features/roles}/member-roles/member-roles.ts +15 -15
  201. package/template/templates/features/roles/package.json +21 -0
  202. package/template/templates/{asas/src → features/roles}/roles/roles.ts +23 -23
  203. package/template/templates/{asas/src → features/roles}/roles/ui/role-form.tsx +65 -24
  204. package/template/templates/{asas/src → features/roles}/roles/ui/roles.tsx +49 -25
  205. package/template/templates/features/settings/index.ts +3 -0
  206. package/template/templates/features/settings/package.json +13 -0
  207. package/template/templates/{asas/src → features/settings}/settings/settings.ts +12 -17
  208. package/template/templates/features/tags/index.ts +3 -0
  209. package/template/templates/features/tags/package.json +14 -0
  210. package/template/templates/{asas/src → features/tags}/tags/tags.ts +15 -15
  211. package/template/templates/mithaq/package.json +33 -0
  212. package/template/templates/mithaq/src/mail/index.ts +32 -0
  213. package/template/templates/mithaq/src/mail/mailers.ts +36 -0
  214. package/template/templates/{asas/src/audit-log/sink.ts → mithaq/src/mithaq/audit-sink.ts} +31 -9
  215. package/template/templates/{auth/src/platform-roles.ts → mithaq/src/mithaq/auth/backoffice-roles.ts} +44 -23
  216. package/template/templates/mithaq/src/mithaq/auth/index.ts +1859 -0
  217. package/template/templates/mithaq/src/mithaq/auth/organizations.ts +80 -0
  218. package/template/templates/{asas/src → mithaq/src/mithaq}/pages.ts +16 -7
  219. package/template/templates/mithaq/src/mithaq/rich-text-nodes.ts +19 -0
  220. package/template/templates/mithaq/src/mithaq.ts +593 -0
  221. package/template/templates/mithaq/src/roles/default-member-roles.ts +29 -0
  222. package/template/templates/{asas → mithaq}/src/roles/grants.ts +1 -1
  223. package/template/templates/mithaq/src/roles/member-access.ts +11 -0
  224. package/template/templates/{asas/src → mithaq/src/roles}/statements.ts +6 -4
  225. package/template/templates/mithaq/src/roles/system-roles.ts +16 -0
  226. package/template/templates/{asas/src → mithaq/src/roles}/tenant-access.ts +96 -57
  227. package/template/templates/{asas/src → mithaq/src/roles}/tenant-roles.ts +84 -25
  228. package/template/templates/{asas → mithaq}/src/steps/expected-updated-at.ts +2 -2
  229. package/template/templates/{asas → mithaq}/src/storage/index.ts +3 -1
  230. package/template/templates/mithaq/src/ui/activity-page.tsx +33 -0
  231. package/template/templates/mithaq/src/ui/activity.tsx +527 -0
  232. package/template/templates/{asas → mithaq}/src/ui/app-shell.tsx +27 -19
  233. package/template/templates/mithaq/src/ui/rich-text-nodes.tsx +33 -0
  234. package/template/templates/{asas → mithaq}/src/ui/screen-nav.tsx +1 -1
  235. package/template/templates/{asas → mithaq}/src/ui/top-shell.tsx +8 -8
  236. package/template/apps/asas-platform/src/components/mithaq/cells.tsx +0 -112
  237. package/template/apps/asas-platform/src/components/mithaq/controls.tsx +0 -650
  238. package/template/apps/asas-platform/src/components/mithaq/field-shell.tsx +0 -53
  239. package/template/apps/asas-platform/src/components/mithaq/filter-operators.ts +0 -108
  240. package/template/apps/asas-platform/src/components/mithaq/form.tsx +0 -1467
  241. package/template/apps/asas-platform/src/components/mithaq/list-columns.tsx +0 -108
  242. package/template/apps/asas-platform/src/components/mithaq/list-filters.tsx +0 -368
  243. package/template/apps/asas-platform/src/components/mithaq/list-pagination.tsx +0 -153
  244. package/template/apps/asas-platform/src/components/mithaq/list-query.ts +0 -432
  245. package/template/apps/asas-platform/src/components/mithaq/list-selection.tsx +0 -74
  246. package/template/apps/asas-platform/src/components/mithaq/list.tsx +0 -865
  247. package/template/apps/asas-platform/src/components/mithaq/nav.tsx +0 -871
  248. package/template/apps/asas-platform/src/components/mithaq/nodes.tsx +0 -1024
  249. package/template/apps/asas-platform/src/components/mithaq/relationship-cell.tsx +0 -127
  250. package/template/apps/asas-platform/src/components/mithaq/relationship-control.tsx +0 -400
  251. package/template/apps/asas-platform/src/components/mithaq/rich-text-nodes.ts +0 -6
  252. package/template/apps/asas-platform/src/components/mithaq/rich-text.tsx +0 -1083
  253. package/template/apps/asas-platform/src/components/mithaq/upload.tsx +0 -686
  254. package/template/apps/asas-platform/src/components/ui/drawer.tsx +0 -216
  255. package/template/apps/asas-platform/src/redirect.ts +0 -1
  256. package/template/apps/asas-platform/src/routeTree.gen.ts +0 -181
  257. package/template/apps/asas-platform/src/router.tsx +0 -7
  258. package/template/apps/asas-platform/src/routes/(screens)/platform/files.ts +0 -4
  259. package/template/apps/asas-platform/src/routes/api/$.ts +0 -30
  260. package/template/apps/asas-platform/src/server.ts +0 -20
  261. package/template/apps/asas-tanstack/src/components/mithaq/cells.tsx +0 -112
  262. package/template/apps/asas-tanstack/src/components/mithaq/controls.tsx +0 -650
  263. package/template/apps/asas-tanstack/src/components/mithaq/field-shell.tsx +0 -53
  264. package/template/apps/asas-tanstack/src/components/mithaq/filter-operators.ts +0 -108
  265. package/template/apps/asas-tanstack/src/components/mithaq/form.tsx +0 -1467
  266. package/template/apps/asas-tanstack/src/components/mithaq/list-columns.tsx +0 -108
  267. package/template/apps/asas-tanstack/src/components/mithaq/list-filters.tsx +0 -368
  268. package/template/apps/asas-tanstack/src/components/mithaq/list-pagination.tsx +0 -153
  269. package/template/apps/asas-tanstack/src/components/mithaq/list-query.ts +0 -432
  270. package/template/apps/asas-tanstack/src/components/mithaq/list-selection.tsx +0 -74
  271. package/template/apps/asas-tanstack/src/components/mithaq/list.tsx +0 -865
  272. package/template/apps/asas-tanstack/src/components/mithaq/nav.tsx +0 -871
  273. package/template/apps/asas-tanstack/src/components/mithaq/nodes.tsx +0 -1024
  274. package/template/apps/asas-tanstack/src/components/mithaq/relationship-cell.tsx +0 -127
  275. package/template/apps/asas-tanstack/src/components/mithaq/relationship-control.tsx +0 -400
  276. package/template/apps/asas-tanstack/src/components/mithaq/rich-text-nodes.ts +0 -6
  277. package/template/apps/asas-tanstack/src/components/mithaq/rich-text.tsx +0 -1083
  278. package/template/apps/asas-tanstack/src/components/mithaq/upload.tsx +0 -686
  279. package/template/apps/asas-tanstack/src/components/ui/drawer.tsx +0 -215
  280. package/template/templates/asas/src/audit-log/audit-log.ts +0 -187
  281. package/template/templates/asas/src/audit-log/ui/activity.tsx +0 -243
  282. package/template/templates/asas/src/courses/ui/archive-button.tsx +0 -25
  283. package/template/templates/asas/src/courses/ui/no-courses-on-offer.tsx +0 -11
  284. package/template/templates/asas/src/courses/ui/on-offer.ts +0 -6
  285. package/template/templates/asas/src/enrollments/enrollments.ts +0 -137
  286. package/template/templates/asas/src/rich-text-nodes.ts +0 -11
  287. package/template/templates/asas/src/roles.ts +0 -16
  288. package/template/templates/asas/src/ui/rich-text-nodes.tsx +0 -15
  289. package/template/templates/asas/src/ui-platform/organization-actions.tsx +0 -114
  290. package/template/templates/auth/src/index.ts +0 -690
  291. /package/template/apps/{asas-platform → asas-backoffice}/components.json +0 -0
  292. /package/template/apps/{asas-platform → asas-backoffice}/gitignore +0 -0
  293. /package/template/apps/{asas-platform → asas-backoffice}/public/favicon.svg +0 -0
  294. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/accordion.tsx +0 -0
  295. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/alert-dialog.tsx +0 -0
  296. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/avatar.tsx +0 -0
  297. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/badge.tsx +0 -0
  298. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/breadcrumb.tsx +0 -0
  299. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/button-group.tsx +0 -0
  300. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/button.tsx +0 -0
  301. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/calendar.tsx +0 -0
  302. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/card.tsx +0 -0
  303. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/chart.tsx +0 -0
  304. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/checkbox.tsx +0 -0
  305. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/collapsible.tsx +0 -0
  306. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/combobox.tsx +0 -0
  307. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/dialog.tsx +0 -0
  308. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/direction.tsx +0 -0
  309. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/directional-icon.tsx +0 -0
  310. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/dropdown-menu.tsx +0 -0
  311. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/field.tsx +0 -0
  312. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/input-group.tsx +0 -0
  313. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/input-otp.tsx +0 -0
  314. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/input.tsx +0 -0
  315. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/label.tsx +0 -0
  316. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/popover.tsx +0 -0
  317. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/radio-group.tsx +0 -0
  318. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/resizable.tsx +0 -0
  319. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/scroll-area.tsx +0 -0
  320. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/select.tsx +0 -0
  321. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/separator.tsx +0 -0
  322. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/sheet.tsx +0 -0
  323. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/sidebar.tsx +0 -0
  324. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/skeleton.tsx +0 -0
  325. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/slider.tsx +0 -0
  326. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/spinner.tsx +0 -0
  327. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/switch.tsx +0 -0
  328. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/table.tsx +0 -0
  329. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/tabs.tsx +0 -0
  330. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/textarea.tsx +0 -0
  331. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/toggle-group.tsx +0 -0
  332. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/toggle.tsx +0 -0
  333. /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/tooltip.tsx +0 -0
  334. /package/template/apps/{asas-platform → asas-backoffice}/src/copy.ts +0 -0
  335. /package/template/apps/{asas-platform → asas-backoffice}/src/hooks/use-mobile.ts +0 -0
  336. /package/template/apps/{asas-platform → asas-backoffice}/src/lib/utils.ts +0 -0
  337. /package/template/apps/{asas-platform → asas-backoffice}/src/theme.ts +0 -0
  338. /package/template/templates/{asas/src/kayan → features}/auth/user/index.ts +0 -0
  339. /package/template/templates/{asas/src → features/courses}/courses/ui/no-courses.tsx +0 -0
  340. /package/template/templates/{asas → mithaq}/components.json +0 -0
  341. /package/template/templates/{asas → mithaq}/src/storage/defaults.ts +0 -0
  342. /package/template/templates/{asas → mithaq}/src/storage/local.ts +0 -0
  343. /package/template/templates/{asas → mithaq}/src/storage/r2.ts +0 -0
  344. /package/template/templates/{asas → mithaq}/src/storage/s3.ts +0 -0
  345. /package/template/templates/{asas → mithaq}/src/storage/uploadthing.ts +0 -0
  346. /package/template/templates/{asas → mithaq}/src/ui/kpi-card.tsx +0 -0
  347. /package/template/templates/{asas → mithaq}/src/ui/record-page.tsx +0 -0
  348. /package/template/templates/{asas → mithaq}/src/ui/table-page.tsx +0 -0
@@ -1,25 +0,0 @@
1
- // The portal's own button for `archive`, drawn in the edit page's danger zone
2
- // as the registry draws its buttons: one click, behind the page's confirm,
3
- // with the reason written for the viewer in the viewer's locale, where the
4
- // dashboard asks for one in a dialog.
5
- import type { ButtonProps } from 'mithaq/admin'
6
- import { useLocale, useRecord, useUser } from 'mithaq/admin/react'
7
- import { Button } from '@/components/ui/button'
8
-
9
- export function ArchiveButton({ busy, operation, run }: ButtonProps) {
10
- const { t } = useLocale()
11
- const record = useRecord()
12
- const user = useUser()
13
- return (
14
- <Button
15
- type="button"
16
- variant="outline"
17
- data-archive-button={operation}
18
- data-row={String(record?.id ?? '')}
19
- disabled={busy || !record}
20
- onClick={() => void run({ reason: t('courses.operations.archive.portalReason', 'Archived from the portal by {name}')!.replace('{name}', () => user.name) })}
21
- >
22
- {t('courses.operations.archive', 'Archive')}
23
- </Button>
24
- )
25
- }
@@ -1,11 +0,0 @@
1
- import type { EmptyProps } from 'mithaq/admin'
2
- import { useKayan, useLocale } from 'mithaq/admin/react'
3
-
4
- export function NoCourses({ page }: EmptyProps) {
5
- const { t } = useLocale()
6
- return (
7
- <p data-empty={`${useKayan().name}${page.path}`} className="text-muted-foreground text-sm">
8
- {t('courses.noneOnOffer', 'No courses on offer yet.')}
9
- </p>
10
- )
11
- }
@@ -1,6 +0,0 @@
1
- // The courses the portal offers: every course not archived. The portal lists
2
- // these alone, as its screen's `baseFilter` for the kayan, and its home counts
3
- // these alone. Plain data in a file of its own, so the page that counts reads it
4
- // without the kayan's declaration. A course with no `archived` value is not
5
- // archived either.
6
- export const onOffer = { or: [{ archived: { exists: false } }, { archived: { equals: false } }] }
@@ -1,137 +0,0 @@
1
- import { defaultFields, defaultOperations, folderOf } from 'mithaq'
2
- import { defineKayan, organization } from '../mithaq.ts'
3
- import { readsPast, user as actor } from '../tenant-access.ts'
4
- import { activity, appPage, danger, platformList, platformRecord, topPage } from '../pages.ts'
5
- import { user } from '../kayan/auth/user/user.ts'
6
- import { sessions } from '../sessions/sessions.ts'
7
-
8
- const ui = folderOf(new URL('./ui/', import.meta.url))
9
- const sessionCell = ui('session-cell.tsx#SessionCell')
10
- const enrollment = [{ section: 'enrollment', label: { en: 'Enrollment', ar: 'التسجيل' }, fields: ['session', 'student'] }] as const
11
-
12
- /**
13
- * The seats an actor reads, edits and deletes, inside its active organization:
14
- * every seat of its organization for an actor holding
15
- * `enrollments.others` and for platform staff, its own seats alone for anyone
16
- * else. That is the student, whose enrollment keys would otherwise reach every
17
- * other student's seat, and a custom role a tenant writes without the key.
18
- * Another's seat answers 404, as a missing row does.
19
- *
20
- * The id is read off the actor as an own key, and an actor carrying none reaches
21
- * no seat. Every read answers from it, a session's join of its enrollments
22
- * included.
23
- */
24
- const ownSeats = ({ user }: { user: unknown }) => {
25
- if (readsPast(user, 'enrollments.others')) return true
26
- const actor = user && typeof user === 'object' ? (user as Record<string, unknown>) : undefined
27
- const id = actor && Object.hasOwn(actor, 'id') ? actor.id : undefined
28
- return typeof id === 'string' && id ? { student: { equals: id } } : false
29
- }
30
-
31
- export const enrollments = defineKayan({
32
- name: 'enrollments',
33
- access: { read: ownSeats, update: ownSeats, delete: ownSeats },
34
- fields: {
35
- ...defaultFields,
36
- organization,
37
- // Read as the session's course and its start on every screen, where a
38
- // session alone is titled by its start.
39
- //
40
- // Both are required, so no write makes a seat for nobody or in nothing, and
41
- // a session or a person that holds one is not deleted under it: a required
42
- // relationship restricts.
43
- session: {
44
- kind: 'relationship', label: { en: 'Session', ar: 'الحصة' }, relationTo: () => sessions,
45
- rules: { required: true },
46
- targets: { dashboard: { cell: sessionCell }, portal: { cell: sessionCell }, platform: { cell: sessionCell } },
47
- },
48
- // A create that names no student enrolls the person making it: the runner's
49
- // defaults step fills it from the actor, and a field with a default is one a
50
- // create may leave out, at the HTTP boundary too. A role without the column's
51
- // key is refused the filled value, so today only the instructor's and the
52
- // administrator's API create fills it; the student reads its own seats and
53
- // creates none.
54
- student: {
55
- kind: 'relationship', label: { en: 'Student', ar: 'الطالب' }, relationTo: () => user,
56
- rules: { required: true, defaultValue: actor.id },
57
- },
58
- /**
59
- * The field the language names as its soft-delete mark, so a student who
60
- * leaves a session is a row this kayan keeps rather than one it removes: an
61
- * enrollment is the record that the student was there. It is the one kayan
62
- * of this template that takes the mark. Nothing points at an enrollment, so
63
- * no child outlives it, and nothing refers to it through a `restrict`
64
- * foreign key that a delete would have to release. Nobody supplies the
65
- * mark: the runner writes it at the delete.
66
- *
67
- * `session` and `student` are required, so each restricts, and a session or
68
- * a person a marked enrollment still names is not deleted under it.
69
- */
70
- deletedAt: {
71
- kind: 'datetime',
72
- label: { en: 'Deleted at', ar: 'تاريخ الحذف' },
73
- rules: { providedBy: { create: 'never', update: 'never' } },
74
- },
75
- },
76
- targets: {
77
- // Every organization's rows on the platform, read-only, and each row's
78
- // record, which only reads. A record is titled by its student, a person the
79
- // platform reads, where a session is titled only by its start.
80
- platform: {
81
- useAsTitle: 'student',
82
- pages: {
83
- ...platformList('/enrollments', { columns: ['session', 'student', 'organization', 'createdAt'], filters: ['organization', 'session', 'student'], sort: '-createdAt' }),
84
- ...platformRecord({
85
- path: '/enrollments/:id',
86
- main: [{ section: 'enrollment', label: { en: 'Enrollment', ar: 'التسجيل' }, fields: ['session', 'student', 'deletedAt'] }],
87
- }),
88
- },
89
- },
90
- service: { operations: defaultOperations },
91
- // Both screens list enrollments; the portal's create opens as a drawer over
92
- // its list. Titled by the student on the dashboard, as on the platform, so a
93
- // tab and a heading tell one seat from another; on the portal, where the
94
- // student is most often the viewer, by the session.
95
- dashboard: {
96
- useAsTitle: 'student',
97
- description: {
98
- en: 'Which student holds a seat in which session.',
99
- ar: 'أي طالب يشغل مقعدا في أي حصة.',
100
- },
101
- pages: {
102
- // The same table every kayan's list is. Searched by the student's name,
103
- // the one column of a person a tenant reads, and filtered by session,
104
- // student and when the student enrolled, as the course list is.
105
- list: { path: '/enrollments', page: appPage([{ layout: 'table', main: [{ list: {
106
- columns: ['session', 'student', 'createdAt'],
107
- filters: ['session', 'student', 'createdAt'],
108
- search: ['student.name'],
109
- } }] }]) },
110
- create: { path: '/enrollments/new', page: appPage([{ layout: 'record', main: [{ form: enrollment }] }]) },
111
- // The editor layout, and the one timestamp worth reading here, named and
112
- // read-only: when the student enrolled, beside the organization it
113
- // belongs to, read by its name.
114
- edit: {
115
- path: '/enrollments/:id',
116
- page: appPage([{
117
- layout: 'record',
118
- main: [{ form: enrollment }],
119
- side: [{ section: 'record', label: { en: 'Record', ar: 'السجل' }, fields: [{ field: 'organization', readOnly: true }, { field: 'createdAt', readOnly: true }] }, activity],
120
- danger: danger(),
121
- }]),
122
- },
123
- },
124
- },
125
- portal: {
126
- useAsTitle: 'session',
127
- pages: {
128
- list: { path: '/enrollments', page: topPage([{ layout: 'page', main: [{ list: { columns: ['session', 'createdAt'] } }] }]) },
129
- // The student too, as the dashboard draws it, so an instructor picks
130
- // whom it enrolls. A role without `enrollments.fields.student` is not
131
- // projected the field and is drawn the session alone.
132
- create: { path: '/enrollments/new', mode: 'drawer', page: topPage([{ layout: 'page', main: [{ form: ['session', 'student'] }] }]) },
133
- edit: { path: '/enrollments/:id', page: topPage([{ layout: 'page', main: [{ form: ['session'] }] }]) },
134
- },
135
- },
136
- },
137
- })
@@ -1,11 +0,0 @@
1
- // The Lexical node classes this project's rich text is written in: the one
2
- // list both halves read, the server's write and every screen's editor and
3
- // viewer, so neither can take a node the other does not. A node of the
4
- // project's own is spread after the defaults, `[...defaultNodes, CalloutNode]`,
5
- // and a node that draws React keeps its DOM-free class here and its React
6
- // subclass in the client file. This project opts in to the upload node, an
7
- // image of the organization's own `media` inside the text, whose server half
8
- // refuses one pointing at a kayan that holds no files.
9
- import { defaultNodes, UploadNode } from 'mithaq/rich-text'
10
-
11
- export const richTextNodes = [...defaultNodes, UploadNode]
@@ -1,16 +0,0 @@
1
- // The subpath, so a page piece reading the fixed roles' labels loads no server code.
2
- import { platformRoles } from '@asas/auth/platform-roles'
3
- import type { SystemRoles } from 'mithaq'
4
- import { tenantRoles } from './tenant-roles.ts'
5
-
6
- export { tenantRoles }
7
-
8
- /**
9
- * Every role this project ships, the platform's and the tenants', which is what
10
- * the access target takes whole: it holds a slug's keys wherever the project's
11
- * reader answers it. The platform roles are `@asas/auth`'s, because the column
12
- * they live on is Better Auth's own `user.role` and the admin plugin's roles are
13
- * built from the same lists. The reader answers them in the platform app alone,
14
- * and an assignment never names one.
15
- */
16
- export const systemRoles = { ...platformRoles, ...tenantRoles } as const satisfies SystemRoles
@@ -1,15 +0,0 @@
1
- // What every screen's rich text editor and viewer draw with: this project's
2
- // own node list, the one its server parses every write with, each class swapped
3
- // for its React subclass where one extends it, and the `/` menu's picks. A
4
- // provider each screen names, so no control, read view or panel can take
5
- // another list.
6
- import type { ReactNode } from 'react'
7
- import type { ProviderProps } from 'mithaq/admin'
8
- import { RichTextContext, defaultPicks, defaultViews, viewsOf } from '@/components/mithaq/rich-text.tsx'
9
- import { UploadPlugin, UploadView, imagePick } from '@/components/mithaq/upload.tsx'
10
- import { richTextNodes } from '../rich-text-nodes.ts'
11
-
12
- // The upload node's `/` entry "Image" opens its dialog in every editor.
13
- const value = { nodes: viewsOf(richTextNodes, [...defaultViews, UploadView]), picks: [...defaultPicks, imagePick], Plugin: UploadPlugin }
14
-
15
- export const RichTextNodes = ({ children }: ProviderProps<ReactNode>) => <RichTextContext value={value}>{children}</RichTextContext>
@@ -1,114 +0,0 @@
1
- // The list's cell for the `slug` column. Rename is drawn only where this actor holds
2
- // `organization.rename`, and members only where this actor reads them; the route refuses a rename
3
- // without the key. A rename that lands asks the list behind it to be read again through
4
- // `mithaq:refresh`, so the list keeps its scroll.
5
- import { useState, type FormEvent } from 'react'
6
- import { holds, type CellProps } from 'mithaq/admin'
7
- import { useAccess, useLocale, useScreen } from 'mithaq/admin/react'
8
- import { writeQuery } from '@/components/mithaq/list-query.ts'
9
- import { Button } from '@/components/ui/button'
10
- import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'
11
- import { Input } from '@/components/ui/input'
12
- import { Label } from '@/components/ui/label'
13
-
14
- const slugShape = /^[a-z0-9]+(-[a-z0-9]+)*$/
15
-
16
- export function OrganizationActions({ value, row }: CellProps) {
17
- const { t } = useLocale()
18
- const access = useAccess()
19
- const screen = useScreen()
20
- const renames = holds(access, 'organization.rename')
21
- const members = holds(access, 'member.find') && screen.kayan.member?.pages.list !== undefined
22
- const [open, setOpen] = useState(false)
23
- const [refusal, setRefusal] = useState<string>()
24
- const [done, setDone] = useState<string>()
25
- /** Said here rather than by the browser's own bubble, which is in the browser's language. */
26
- const [wrong, setWrong] = useState<{ name?: string; slug?: string }>({})
27
- const id = String(row.id ?? '')
28
- const save = async (event: FormEvent<HTMLFormElement>) => {
29
- event.preventDefault()
30
- const box = (key: string) => (event.currentTarget.elements.namedItem(key) as HTMLInputElement | null)?.value ?? ''
31
- const name = box('name')
32
- const slug = box('slug')
33
- const found = {
34
- name: name.trim() ? undefined : t('organization.name.required', 'This field is required.'),
35
- slug: !slug ? t('organization.slug.required', 'This field is required.') : slugShape.test(slug) ? undefined : t('platform.slugPattern', 'A slug is lowercase letters and digits joined by single dashes, such as admin-org.'),
36
- }
37
- setWrong(found)
38
- if (found.name || found.slug) return
39
- const response = await fetch('/api/platform/organizations/update', {
40
- method: 'POST',
41
- headers: { 'content-type': 'application/json' },
42
- body: JSON.stringify({ id, name, slug }),
43
- })
44
- if (!response.ok) {
45
- const key = ((await response.json().catch(() => null)) as { data?: { key?: string } } | null)?.data?.key
46
- return setRefusal((key && t(key)) ?? t('platform.refused', 'The platform refused that action.'))
47
- }
48
- window.dispatchEvent(new Event('mithaq:refresh'))
49
- // A function, so a name holding `$&` is put in as written.
50
- setDone((t('platform.renamed', 'The organization is now named {name}.') ?? '').replace('{name}', () => name))
51
- }
52
- return (
53
- <div data-organization={id} className="flex items-center gap-2 whitespace-nowrap">
54
- {/* An identifier, read left to right in either locale. */}
55
- <span dir="ltr">{String(value ?? '')}</span>
56
- {renames ? (
57
- <Button size="sm" variant="outline" className="max-sm:h-11" data-action="rename" onClick={() => setOpen(true)}>
58
- {t('platform.rename', 'Rename')}
59
- </Button>
60
- ) : null}
61
- {members ? (
62
- <Button
63
- size="sm"
64
- variant="outline"
65
- className="max-sm:h-11"
66
- data-action="members"
67
- nativeButton={false}
68
- render={<a href={`${screen.path}${screen.kayan.member!.pages.list!.path}?${new URLSearchParams(writeQuery({ where: { or: [{ and: [{ organizationId: { equals: id } }] }] } }))}`} />}
69
- >
70
- {t('platform.members', 'Members')}
71
- </Button>
72
- ) : null}
73
- {open ? (
74
- <Dialog open onOpenChange={setOpen}>
75
- {/* Cancel is the way out, so the primitive's own close, named in
76
- English alone, is not drawn beside it. */}
77
- <DialogContent showCloseButton={false}>
78
- <DialogHeader>
79
- <DialogTitle>{t('platform.rename', 'Rename')}</DialogTitle>
80
- <DialogDescription aria-live="polite">{done ?? t('platform.renameAbout', 'The new name and slug take the place of the old ones for everyone in this organization.')}</DialogDescription>
81
- </DialogHeader>
82
- {done ? (
83
- <DialogFooter>
84
- <DialogClose render={<Button type="button" variant="outline" />}>{t('admin.close', 'Close')}</DialogClose>
85
- </DialogFooter>
86
- ) : (
87
- <form noValidate onSubmit={(event) => void save(event)} className="grid gap-4">
88
- <div className="grid gap-2">
89
- <Label htmlFor={`organization-name-${id}`}>{t('organization.name', 'Name')}</Label>
90
- <Input id={`organization-name-${id}`} name="name" required aria-required dir="auto" defaultValue={String(row.name ?? '')} aria-invalid={wrong.name ? true : undefined} aria-describedby={wrong.name ? `organization-name-${id}-error` : undefined} />
91
- {wrong.name ? <p id={`organization-name-${id}-error`} role="alert" className="text-sm text-destructive">{wrong.name}</p> : null}
92
- </div>
93
- <div className="grid gap-2">
94
- <Label htmlFor={`organization-slug-${id}`}>{t('organization.slug', 'Slug')}</Label>
95
- <Input id={`organization-slug-${id}`} name="slug" required aria-required dir="ltr" pattern={slugShape.source.slice(1, -1)} defaultValue={String(value ?? '')} aria-invalid={wrong.slug ? true : undefined} aria-describedby={wrong.slug ? `organization-slug-${id}-error` : undefined} />
96
- {wrong.slug ? <p id={`organization-slug-${id}-error`} role="alert" className="text-sm text-destructive">{wrong.slug}</p> : null}
97
- </div>
98
- {refusal ? (
99
- <p role="alert" className="text-sm text-destructive">
100
- {refusal}
101
- </p>
102
- ) : null}
103
- <DialogFooter>
104
- <DialogClose render={<Button type="button" variant="outline" />}>{t('admin.cancel', 'Cancel')}</DialogClose>
105
- <Button type="submit">{t('admin.save', 'Save')}</Button>
106
- </DialogFooter>
107
- </form>
108
- )}
109
- </DialogContent>
110
- </Dialog>
111
- ) : null}
112
- </div>
113
- )
114
- }