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
@@ -0,0 +1,16 @@
1
+ import { createServerFn } from '@tanstack/react-start'
2
+
3
+ type FirstRun = { open: false } | { open: true; code: 'none' | 'required' | 'unset' }
4
+
5
+ /**
6
+ * Whether this app of one organization still waits for its first owner, and while it does,
7
+ * whether first-run asks the setup code: the provider's own state, read in process. With
8
+ * many organizations nobody waits: each sign-up founds one.
9
+ */
10
+ export const firstRun = createServerFn({ method: 'GET' }).handler(async (): Promise<FirstRun> => {
11
+ // Imported inside the server half so no page ships the provider to the browser.
12
+ const [{ asas }, { organizations }] = await Promise.all([import('asas'), import('asas/organizations')])
13
+ if (organizations === 'many') return { open: false }
14
+ type Provider = { name: string; server: { api: { firstRunState(): Promise<FirstRun> } } }
15
+ return (asas.auth.strategies as unknown as Provider[]).find((one) => one.name === 'user')!.server.api.firstRunState()
16
+ })
@@ -35,4 +35,4 @@ export const clampedHref = ({ href, page, totalPages }: { href: string; page: nu
35
35
  else url.searchParams.delete('page')
36
36
  return `${url.pathname}${url.search}${url.hash}`
37
37
  }
38
- // mithaq-admin b06d8d335d306c07556f8f2b81fba20ba7ded198 4754cbac64eeac528e7e037173ad56ffa8d07df3e526e1191bbe3be400db97a5
38
+ // mithaq-admin 2d3ab739c92c6c2b397041b76bf4b23b2902b7a2 4754cbac64eeac528e7e037173ad56ffa8d07df3e526e1191bbe3be400db97a5
@@ -1,9 +1,11 @@
1
+ import { useRouter } from '@tanstack/react-router'
1
2
  import { Button } from '@/components/ui/button'
2
- import { localeEntries } from './components/mithaq/nav.tsx'
3
- import { locales, switchLocale, type Locale } from './copy.ts'
3
+ import { localeEntries } from 'mithaq-admin/locale-menu.ts'
4
+ import { locales, showLocale, type Locale } from './copy.ts'
4
5
 
5
- /** The language switch for pages without a form: `switchLocale` reloads without asking, so a page with a form must use the user menu, which asks first. */
6
+ /** The language switch of the auth and landing pages, which redraws the page in place, so a form keeps what was typed. */
6
7
  export function LocaleSwitch({ locale }: { locale: Locale }) {
8
+ const router = useRouter()
7
9
  return (
8
10
  <div className="flex items-center gap-1">
9
11
  {localeEntries(locales, locale).map((entry) => (
@@ -14,7 +16,7 @@ export function LocaleSwitch({ locale }: { locale: Locale }) {
14
16
  size="xs"
15
17
  aria-current={entry.active}
16
18
  aria-label={entry.label}
17
- onClick={() => switchLocale({ to: entry.locale })}
19
+ onClick={() => void showLocale({ to: entry.locale, router })}
18
20
  >
19
21
  <span className="hidden sm:inline">{entry.label}</span>
20
22
  <span className="sm:hidden">{entry.locale.toUpperCase()}</span>
@@ -23,4 +25,4 @@ export function LocaleSwitch({ locale }: { locale: Locale }) {
23
25
  </div>
24
26
  )
25
27
  }
26
- // mithaq-admin b06d8d335d306c07556f8f2b81fba20ba7ded198 43c6d309a5bae4f6af3cdcf4c741106b3a16129ac77d142f1e4254594f5b8a54
28
+ // mithaq-admin 0.0.0 37e32a32766452cd88389e2e4cc6c246ccc3ccb40bf941f8c1e3835b4e377f98
@@ -0,0 +1,108 @@
1
+ // What `/unauthorized` draws below its sentence for a person who belongs to no organization: the invitations sent to
2
+ // their address, and with many organizations a way to found one. The screen host imports it from the app, which knows
3
+ // the organization mode the host does not.
4
+ import { useEffect, useState } from 'react'
5
+ import { defaultLocale, organizations } from 'asas/organizations'
6
+ import { endonym } from 'mithaq-admin/locale-menu.ts'
7
+ import { Button } from '@/components/ui/button'
8
+ import { Input } from '@/components/ui/input'
9
+ import { authArm } from './api.ts'
10
+ import { useRefusal } from './auth-frame.tsx'
11
+ import { locales } from './copy.ts'
12
+ import { useCopy } from './routes/__root.tsx'
13
+
14
+ /** An invitation as the auth setup answers it: the organization's name in each locale beside the provider's one. */
15
+ type Invitation = { id: string; organizationName: string; organizationNames?: Record<string, string>; expiresAt: string }
16
+
17
+ /**
18
+ * Better Auth requires a unique slug, so a random tail keeps same-named organizations apart.
19
+ * Padded before the cut, so the tail is always six characters and the slug never ends in `-`.
20
+ */
21
+ const slugOf = (name: string) =>
22
+ `${name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '').slice(0, 40) || 'organization'}-${Math.random().toString(36).slice(2).padEnd(6, '0').slice(0, 6)}`
23
+
24
+ /** Signing in again lands a signed-in person on their first screen, in the organization the session now names. */
25
+ const goIn = () => window.location.assign('/auth/sign-in')
26
+
27
+ export function NoOrganization({ email, founds = organizations === 'many' }: { email: string | undefined; founds?: boolean }) {
28
+ const { t, locale } = useCopy()
29
+ const refusal = useRefusal()
30
+ const [invitations, setInvitations] = useState<Invitation[]>([])
31
+ const [name, setName] = useState('')
32
+ // The organization's name in each other locale, optional: one left empty falls back to `name`.
33
+ const [names, setNames] = useState<Record<string, string>>({})
34
+ const others = locales.filter((one) => one !== defaultLocale)
35
+ const [busy, setBusy] = useState(false)
36
+ const [failed, setFailed] = useState<string>()
37
+ useEffect(() => {
38
+ // A refusal, such as an address nobody proved, reads as no invitation.
39
+ void fetch('/api/auth/user/organization/list-user-invitations').then(async (answer) => {
40
+ if (answer.ok) setInvitations(((await answer.json()) as Invitation[]).filter((one) => new Date(one.expiresAt).getTime() > Date.now()))
41
+ })
42
+ if (founds) {
43
+ void fetch('/api/auth/user/get-session').then(async (answer) => {
44
+ const named = ((await answer.json().catch(() => null)) as { user?: { name?: string } } | null)?.user?.name
45
+ if (named) setName((typed) => typed || t('auth.workspaceOf', '{name}\'s workspace')!.replace('{name}', () => named))
46
+ })
47
+ }
48
+ }, [])
49
+ /** One request at a time, its refusal said in this app's words. */
50
+ const send = async ({ path, body, done }: { path: string; body: Record<string, unknown>; done: () => void }) => {
51
+ setBusy(true)
52
+ setFailed(undefined)
53
+ const answered = await authArm(path, body)
54
+ setBusy(false)
55
+ if (!answered.ok) return setFailed(refusal(answered, t('auth.requestFailed', 'That request did not work.')))
56
+ done()
57
+ }
58
+ return (
59
+ <div data-no-organization="" className="grid gap-4">
60
+ {invitations.length ? (
61
+ <section className="grid gap-2">
62
+ <h2 className="text-sm font-medium">{t('auth.yourInvitations', 'Your invitations')}</h2>
63
+ <ul className="grid gap-2">
64
+ {invitations.map((one) => (
65
+ <li key={one.id} data-invitation={one.id} className="flex flex-wrap items-center justify-between gap-2 rounded-md border px-3 py-2">
66
+ <bdi className="[overflow-wrap:anywhere]">{one.organizationNames?.[locale] || one.organizationName}</bdi>
67
+ <span className="flex gap-2">
68
+ <Button type="button" size="sm" data-accept={one.id} disabled={busy} onClick={() => void send({ path: 'organization/accept-invitation', body: { invitationId: one.id }, done: goIn })}>
69
+ {t('auth.invitationAccept', 'Accept the invitation')}
70
+ </Button>
71
+ <Button type="button" size="sm" variant="outline" data-decline={one.id} disabled={busy} onClick={() => void send({ path: 'organization/reject-invitation', body: { invitationId: one.id }, done: () => setInvitations((all) => all.filter((other) => other.id !== one.id)) })}>
72
+ {t('auth.invitationDecline', 'Decline')}
73
+ </Button>
74
+ </span>
75
+ </li>
76
+ ))}
77
+ </ul>
78
+ </section>
79
+ ) : null}
80
+ {founds ? (
81
+ <form
82
+ data-create-organization=""
83
+ className="grid gap-2"
84
+ noValidate
85
+ onSubmit={(event) => {
86
+ event.preventDefault()
87
+ const named = { [defaultLocale]: name.trim(), ...Object.fromEntries(others.map((one) => [one, names[one]?.trim() ?? '']).filter(([, one]) => one)) }
88
+ if (name.trim()) void send({ path: 'organization/create', body: { name: name.trim(), names: JSON.stringify(named), slug: slugOf(name.trim()) }, done: goIn })
89
+ }}
90
+ >
91
+ <label htmlFor="new-organization" className="text-sm font-medium">{t('auth.createOrganization', 'Create an organization')}</label>
92
+ <Input id="new-organization" value={name} maxLength={100} autoComplete="organization" dir="auto" onChange={(event) => setName(event.target.value)} />
93
+ {others.map((one) => (
94
+ <div key={one} className="grid gap-1">
95
+ <label htmlFor={`new-organization-${one}`} className="text-muted-foreground text-sm">{t('auth.organizationNameIn', 'Its name in {language}, if it has one')!.replace('{language}', () => endonym(one))}</label>
96
+ <Input id={`new-organization-${one}`} lang={one} dir="auto" value={names[one] ?? ''} maxLength={100} onChange={(event) => setNames((held) => ({ ...held, [one]: event.target.value }))} />
97
+ </div>
98
+ ))}
99
+ <Button type="submit" disabled={busy || !name.trim()}>{t('auth.createOrganizationSubmit', 'Create')}</Button>
100
+ </form>
101
+ ) : null}
102
+ <p className="text-muted-foreground text-sm">
103
+ {t('auth.askToBeInvited', 'Ask an administrator to invite {email}.')!.split(/(\{email\})/).map((part, at) => (part === '{email}' ? <bdi key={at} className="[overflow-wrap:anywhere]">{email}</bdi> : part))}
104
+ </p>
105
+ {failed ? <p role="alert" className="text-destructive text-sm">{failed}</p> : null}
106
+ </div>
107
+ )
108
+ }
@@ -6,15 +6,34 @@
6
6
  * `//elsewhere` and `javascript:` are refused however they are spelled. A backslash, a C0 control
7
7
  * and DEL are refused before the parse, since the parser rewrites or strips them before reading
8
8
  * the host. They are written as escapes so git and grep keep reading this file as text.
9
+ *
10
+ * The answer is the parser's own path, its dot segments resolved, plain or percent-encoded, so what
11
+ * a caller reads is where the browser goes. A path that resolves to `//` is refused, since a browser
12
+ * reads it as another origin: `/..//elsewhere` resolves to `//elsewhere`.
9
13
  */
10
14
  const base = 'https://mithaq.invalid'
11
15
 
12
16
  export const wanted = ({ asked, home }: { asked: string | undefined; home: string }): string => {
13
17
  if (asked === undefined || !asked.startsWith('/') || /[\\\x00-\x1f\x7f]/.test(asked)) return home
14
18
  try {
15
- return new URL(asked, base).origin === base ? asked : home
19
+ const url = new URL(asked, base)
20
+ return url.origin === base && !url.pathname.startsWith('//') ? url.pathname + url.search + url.hash : home
16
21
  } catch {
17
22
  // `new URL('//', base)` throws rather than resolving.
18
23
  return home
19
24
  }
20
25
  }
26
+
27
+ /**
28
+ * Where a signed-in person goes: the path asked for where it lies inside a screen they open, else the
29
+ * one screen they open, else the dashboard, since whoever opens several is staff, else `/unauthorized`,
30
+ * which asks which of several or says why there is none. The dashboard is found by its screen's name,
31
+ * never its place in the list. A path in a screen they do not open is not followed, since there they
32
+ * would only be refused.
33
+ */
34
+ export const landing = ({ asked, screens }: { asked: string | undefined; screens: readonly { name: string; path: string }[] }): string => {
35
+ const home = (screens.length === 1 ? screens[0] : screens.find((one) => one.name === 'dashboard'))?.path ?? '/unauthorized'
36
+ const path = wanted({ asked, home })
37
+ const { pathname } = new URL(path, base)
38
+ return screens.some(({ path: screen }) => pathname === screen || pathname.startsWith(`${screen}/`)) ? path : home
39
+ }
@@ -8,4 +8,4 @@ export const mergedHeaders = (session: Headers, own?: HeadersInit): Headers => {
8
8
  if (own) for (const [key, value] of new Headers(own)) if (key !== 'cookie') headers.set(key, value)
9
9
  return headers
10
10
  }
11
- // mithaq-admin b06d8d335d306c07556f8f2b81fba20ba7ded198 2969a3dafbf201d6eb6074ecda0e8f17e341cbd1ca176100350844e74ec23623
11
+ // mithaq-admin 2d3ab739c92c6c2b397041b76bf4b23b2902b7a2 2969a3dafbf201d6eb6074ecda0e8f17e341cbd1ca176100350844e74ec23623
@@ -15,9 +15,11 @@ import { Route as screensDashboardRouteImport } from './routes/(screens)/dashboa
15
15
  import { Route as screensPortalRouteImport } from './routes/(screens)/portal'
16
16
  import { Route as ApiSplatRouteImport } from './routes/api/$'
17
17
  import { Route as AuthAcceptInvitationRouteImport } from './routes/auth.accept-invitation'
18
+ import { Route as AuthFirstRunRouteImport } from './routes/auth.first-run'
18
19
  import { Route as AuthForgotPasswordRouteImport } from './routes/auth.forgot-password'
19
20
  import { Route as AuthHandoffRouteImport } from './routes/auth.handoff'
20
21
  import { Route as AuthResetPasswordRouteImport } from './routes/auth.reset-password'
22
+ import { Route as AuthSetPasswordRouteImport } from './routes/auth.set-password'
21
23
  import { Route as AuthSignInRouteImport } from './routes/auth.sign-in'
22
24
  import { Route as AuthSignUpRouteImport } from './routes/auth.sign-up'
23
25
  import { Route as screensDashboardIndexRouteImport } from './routes/(screens)/dashboard.index'
@@ -55,6 +57,11 @@ const AuthAcceptInvitationRoute = AuthAcceptInvitationRouteImport.update({
55
57
  path: '/auth/accept-invitation',
56
58
  getParentRoute: () => rootRouteImport,
57
59
  } as any)
60
+ const AuthFirstRunRoute = AuthFirstRunRouteImport.update({
61
+ id: '/auth/first-run',
62
+ path: '/auth/first-run',
63
+ getParentRoute: () => rootRouteImport,
64
+ } as any)
58
65
  const AuthForgotPasswordRoute = AuthForgotPasswordRouteImport.update({
59
66
  id: '/auth/forgot-password',
60
67
  path: '/auth/forgot-password',
@@ -70,6 +77,11 @@ const AuthResetPasswordRoute = AuthResetPasswordRouteImport.update({
70
77
  path: '/auth/reset-password',
71
78
  getParentRoute: () => rootRouteImport,
72
79
  } as any)
80
+ const AuthSetPasswordRoute = AuthSetPasswordRouteImport.update({
81
+ id: '/auth/set-password',
82
+ path: '/auth/set-password',
83
+ getParentRoute: () => rootRouteImport,
84
+ } as any)
73
85
  const AuthSignInRoute = AuthSignInRouteImport.update({
74
86
  id: '/auth/sign-in',
75
87
  path: '/auth/sign-in',
@@ -108,9 +120,11 @@ export interface FileRoutesByFullPath {
108
120
  '/portal': typeof screensPortalRouteWithChildren
109
121
  '/api/$': typeof ApiSplatRoute
110
122
  '/auth/accept-invitation': typeof AuthAcceptInvitationRoute
123
+ '/auth/first-run': typeof AuthFirstRunRoute
111
124
  '/auth/forgot-password': typeof AuthForgotPasswordRoute
112
125
  '/auth/handoff': typeof AuthHandoffRoute
113
126
  '/auth/reset-password': typeof AuthResetPasswordRoute
127
+ '/auth/set-password': typeof AuthSetPasswordRoute
114
128
  '/auth/sign-in': typeof AuthSignInRoute
115
129
  '/auth/sign-up': typeof AuthSignUpRoute
116
130
  '/dashboard/$': typeof screensDashboardSplatRoute
@@ -123,9 +137,11 @@ export interface FileRoutesByTo {
123
137
  '/unauthorized': typeof UnauthorizedRoute
124
138
  '/api/$': typeof ApiSplatRoute
125
139
  '/auth/accept-invitation': typeof AuthAcceptInvitationRoute
140
+ '/auth/first-run': typeof AuthFirstRunRoute
126
141
  '/auth/forgot-password': typeof AuthForgotPasswordRoute
127
142
  '/auth/handoff': typeof AuthHandoffRoute
128
143
  '/auth/reset-password': typeof AuthResetPasswordRoute
144
+ '/auth/set-password': typeof AuthSetPasswordRoute
129
145
  '/auth/sign-in': typeof AuthSignInRoute
130
146
  '/auth/sign-up': typeof AuthSignUpRoute
131
147
  '/dashboard/$': typeof screensDashboardSplatRoute
@@ -141,9 +157,11 @@ export interface FileRoutesById {
141
157
  '/(screens)/portal': typeof screensPortalRouteWithChildren
142
158
  '/api/$': typeof ApiSplatRoute
143
159
  '/auth/accept-invitation': typeof AuthAcceptInvitationRoute
160
+ '/auth/first-run': typeof AuthFirstRunRoute
144
161
  '/auth/forgot-password': typeof AuthForgotPasswordRoute
145
162
  '/auth/handoff': typeof AuthHandoffRoute
146
163
  '/auth/reset-password': typeof AuthResetPasswordRoute
164
+ '/auth/set-password': typeof AuthSetPasswordRoute
147
165
  '/auth/sign-in': typeof AuthSignInRoute
148
166
  '/auth/sign-up': typeof AuthSignUpRoute
149
167
  '/(screens)/dashboard/$': typeof screensDashboardSplatRoute
@@ -160,9 +178,11 @@ export interface FileRouteTypes {
160
178
  | '/portal'
161
179
  | '/api/$'
162
180
  | '/auth/accept-invitation'
181
+ | '/auth/first-run'
163
182
  | '/auth/forgot-password'
164
183
  | '/auth/handoff'
165
184
  | '/auth/reset-password'
185
+ | '/auth/set-password'
166
186
  | '/auth/sign-in'
167
187
  | '/auth/sign-up'
168
188
  | '/dashboard/$'
@@ -175,9 +195,11 @@ export interface FileRouteTypes {
175
195
  | '/unauthorized'
176
196
  | '/api/$'
177
197
  | '/auth/accept-invitation'
198
+ | '/auth/first-run'
178
199
  | '/auth/forgot-password'
179
200
  | '/auth/handoff'
180
201
  | '/auth/reset-password'
202
+ | '/auth/set-password'
181
203
  | '/auth/sign-in'
182
204
  | '/auth/sign-up'
183
205
  | '/dashboard/$'
@@ -192,9 +214,11 @@ export interface FileRouteTypes {
192
214
  | '/(screens)/portal'
193
215
  | '/api/$'
194
216
  | '/auth/accept-invitation'
217
+ | '/auth/first-run'
195
218
  | '/auth/forgot-password'
196
219
  | '/auth/handoff'
197
220
  | '/auth/reset-password'
221
+ | '/auth/set-password'
198
222
  | '/auth/sign-in'
199
223
  | '/auth/sign-up'
200
224
  | '/(screens)/dashboard/$'
@@ -210,9 +234,11 @@ export interface RootRouteChildren {
210
234
  screensPortalRoute: typeof screensPortalRouteWithChildren
211
235
  ApiSplatRoute: typeof ApiSplatRoute
212
236
  AuthAcceptInvitationRoute: typeof AuthAcceptInvitationRoute
237
+ AuthFirstRunRoute: typeof AuthFirstRunRoute
213
238
  AuthForgotPasswordRoute: typeof AuthForgotPasswordRoute
214
239
  AuthHandoffRoute: typeof AuthHandoffRoute
215
240
  AuthResetPasswordRoute: typeof AuthResetPasswordRoute
241
+ AuthSetPasswordRoute: typeof AuthSetPasswordRoute
216
242
  AuthSignInRoute: typeof AuthSignInRoute
217
243
  AuthSignUpRoute: typeof AuthSignUpRoute
218
244
  }
@@ -261,6 +287,13 @@ declare module '@tanstack/react-router' {
261
287
  preLoaderRoute: typeof AuthAcceptInvitationRouteImport
262
288
  parentRoute: typeof rootRouteImport
263
289
  }
290
+ '/auth/first-run': {
291
+ id: '/auth/first-run'
292
+ path: '/auth/first-run'
293
+ fullPath: '/auth/first-run'
294
+ preLoaderRoute: typeof AuthFirstRunRouteImport
295
+ parentRoute: typeof rootRouteImport
296
+ }
264
297
  '/auth/forgot-password': {
265
298
  id: '/auth/forgot-password'
266
299
  path: '/auth/forgot-password'
@@ -282,6 +315,13 @@ declare module '@tanstack/react-router' {
282
315
  preLoaderRoute: typeof AuthResetPasswordRouteImport
283
316
  parentRoute: typeof rootRouteImport
284
317
  }
318
+ '/auth/set-password': {
319
+ id: '/auth/set-password'
320
+ path: '/auth/set-password'
321
+ fullPath: '/auth/set-password'
322
+ preLoaderRoute: typeof AuthSetPasswordRouteImport
323
+ parentRoute: typeof rootRouteImport
324
+ }
285
325
  '/auth/sign-in': {
286
326
  id: '/auth/sign-in'
287
327
  path: '/auth/sign-in'
@@ -361,9 +401,11 @@ const rootRouteChildren: RootRouteChildren = {
361
401
  screensPortalRoute: screensPortalRouteWithChildren,
362
402
  ApiSplatRoute: ApiSplatRoute,
363
403
  AuthAcceptInvitationRoute: AuthAcceptInvitationRoute,
404
+ AuthFirstRunRoute: AuthFirstRunRoute,
364
405
  AuthForgotPasswordRoute: AuthForgotPasswordRoute,
365
406
  AuthHandoffRoute: AuthHandoffRoute,
366
407
  AuthResetPasswordRoute: AuthResetPasswordRoute,
408
+ AuthSetPasswordRoute: AuthSetPasswordRoute,
367
409
  AuthSignInRoute: AuthSignInRoute,
368
410
  AuthSignUpRoute: AuthSignUpRoute,
369
411
  }
@@ -1,7 +1,18 @@
1
1
  import { createRouter } from '@tanstack/react-router'
2
2
  import { routeTree } from './routeTree.gen'
3
3
  import { flatSearch } from './screen-list.tsx'
4
+ import { ComponentsProvider, RouteError } from 'mithaq-admin/components.tsx'
5
+ import { components } from './components.ts'
4
6
 
5
7
  // The search is read and written as the URL's own pairs, one string each, because a list
6
8
  // keeps its `qs` query there.
7
- export const getRouter = () => createRouter({ routeTree, scrollRestoration: true, ...flatSearch })
9
+ export const getRouter = () =>
10
+ createRouter({
11
+ routeTree,
12
+ scrollRestoration: true,
13
+ ...flatSearch,
14
+ // Around every route, so each screen draws its controls from this map.
15
+ Wrap: ({ children }) => <ComponentsProvider components={components}>{children}</ComponentsProvider>,
16
+ // Drawn in place of the route that threw, so the shell around it stays.
17
+ defaultErrorComponent: RouteError,
18
+ })
@@ -1,4 +1,11 @@
1
1
  // Written by `mithaq generate screens`. Do not edit.
2
2
  /// <reference types="vite/client" />
3
- // Every file the `dashboard` screen's references name, each loaded when a page draws it.
4
- export const files = import.meta.glob(['./src/audit-log/ui/activity.tsx', './src/courses/ui/fee-cell.tsx', './src/courses/ui/no-courses.tsx', './src/courses/ui/status-cell.tsx', './src/enrollments/ui/session-cell.tsx', './src/media/ui/preview.tsx', './src/roles/ui/role-form.tsx', './src/roles/ui/roles.tsx', './src/ui-dashboard/dashboard.tsx', './src/ui-dashboard/members.tsx', './src/ui-dashboard/theme-provider.tsx', './src/ui-dashboard/versions.tsx', './src/ui/app-shell.tsx', './src/ui/record-page.tsx', './src/ui/rich-text-nodes.tsx', './src/ui/session-labels.tsx', './src/ui/table-page.tsx', './src/ui/top-shell.tsx'], { base: '/node_modules/asas/', exhaustive: true })
3
+ // Every file the `dashboard` screen's references name, each loaded when a page draws it, keyed as the reference prints it.
4
+ const named = (name: string, files: Record<string, () => Promise<unknown>>) => Object.fromEntries(Object.entries(files).map(([file, load]) => [`${name}:${file}`, load]))
5
+ export const files = {
6
+ ...import.meta.glob(['./src/ui-dashboard/dashboard.tsx', './src/ui-dashboard/members.tsx', './src/ui-dashboard/theme-provider.tsx', './src/ui-dashboard/versions.tsx'], { base: '../../../../../../templates/asas/', exhaustive: true }),
7
+ ...named('@asas/courses', import.meta.glob(['./courses/ui/archived-badge.tsx', './courses/ui/fee-cell.tsx', './courses/ui/no-courses.tsx', './courses/ui/status-cell.tsx', './courses/ui/unpublish-button.tsx', './enrollments/ui/session-cell.tsx', './enrollments/ui/session-labels.tsx'], { base: '../../../../../../templates/features/courses/', exhaustive: true })),
8
+ ...named('@asas/media', import.meta.glob(['./media/ui/preview.tsx'], { base: '../../../../../../templates/features/media/', exhaustive: true })),
9
+ ...named('@asas/mithaq', import.meta.glob(['./src/ui/activity-page.tsx', './src/ui/activity.tsx', './src/ui/app-shell.tsx', './src/ui/record-page.tsx', './src/ui/rich-text-nodes.tsx', './src/ui/table-page.tsx', './src/ui/top-shell.tsx'], { base: '../../../../../../templates/mithaq/', exhaustive: true })),
10
+ ...named('@asas/roles', import.meta.glob(['./roles/ui/role-form.tsx', './roles/ui/roles.tsx'], { base: '../../../../../../templates/features/roles/', exhaustive: true })),
11
+ }