@mesob/auth-react 0.4.6 → 0.4.7

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 (136) hide show
  1. package/dist/{chunk-TB2ZPGLW.js → chunk-4X3CJHKR.js} +2 -2
  2. package/dist/{chunk-PG65ZD7A.js → chunk-5BFG47VF.js} +4 -4
  3. package/dist/{chunk-OQUUS5ZX.js → chunk-5E3XN6SW.js} +2 -2
  4. package/dist/{chunk-KOBZ34XU.js → chunk-6THPM5LB.js} +7 -1
  5. package/dist/chunk-6THPM5LB.js.map +1 -0
  6. package/dist/{chunk-RBXITSE2.js → chunk-73ZNGEWU.js} +5 -5
  7. package/dist/{chunk-DY3NVBLJ.js → chunk-7CLKBH5Z.js} +10 -1
  8. package/dist/chunk-7CLKBH5Z.js.map +1 -0
  9. package/dist/{chunk-FPYQ7XGV.js → chunk-ECF6S2Y2.js} +90 -20
  10. package/dist/chunk-ECF6S2Y2.js.map +1 -0
  11. package/dist/{chunk-G74DDR4O.js → chunk-GBDNBY6K.js} +2 -2
  12. package/dist/{chunk-LHZ4EEN6.js → chunk-H5PUZDNU.js} +7 -1
  13. package/dist/chunk-H5PUZDNU.js.map +1 -0
  14. package/dist/{chunk-A3GIMM2R.js → chunk-H7JRQFFI.js} +2 -2
  15. package/dist/{chunk-IFAVSKHE.js → chunk-IQNQGPIT.js} +7 -1
  16. package/dist/chunk-IQNQGPIT.js.map +1 -0
  17. package/dist/chunk-MWMSZVH3.js +601 -0
  18. package/dist/chunk-MWMSZVH3.js.map +1 -0
  19. package/dist/{chunk-L32Z3TPA.js → chunk-N4JFMKGK.js} +67 -12
  20. package/dist/chunk-N4JFMKGK.js.map +1 -0
  21. package/dist/{chunk-A7ORWWM5.js → chunk-NFGFJPCX.js} +9 -1
  22. package/dist/chunk-NFGFJPCX.js.map +1 -0
  23. package/dist/{chunk-SW7WD64K.js → chunk-NJMNRSJH.js} +7 -1
  24. package/dist/chunk-NJMNRSJH.js.map +1 -0
  25. package/dist/{chunk-HXHI4FU6.js → chunk-OXUOGOG3.js} +111 -91
  26. package/dist/chunk-OXUOGOG3.js.map +1 -0
  27. package/dist/{chunk-ETOCBXDT.js → chunk-QPEUVMSP.js} +9 -1
  28. package/dist/chunk-QPEUVMSP.js.map +1 -0
  29. package/dist/{chunk-YN7OEQI7.js → chunk-RCQTWNAG.js} +7 -1
  30. package/dist/chunk-RCQTWNAG.js.map +1 -0
  31. package/dist/{chunk-55BMNC4S.js → chunk-RRLFPSSM.js} +25 -11
  32. package/dist/chunk-RRLFPSSM.js.map +1 -0
  33. package/dist/{chunk-NUWAI3FE.js → chunk-SGUROG23.js} +8 -2
  34. package/dist/chunk-SGUROG23.js.map +1 -0
  35. package/dist/{chunk-SXVTYYUT.js → chunk-T34HJRUW.js} +7 -1
  36. package/dist/chunk-T34HJRUW.js.map +1 -0
  37. package/dist/{chunk-UAKGEJUN.js → chunk-TEHMLZFI.js} +2 -2
  38. package/dist/chunk-V6ZHX4LT.js +15 -0
  39. package/dist/chunk-V6ZHX4LT.js.map +1 -0
  40. package/dist/{chunk-CXMPZWMX.js → chunk-VVKXFEAN.js} +2 -2
  41. package/dist/{chunk-ZXKEG3X5.js → chunk-X6EUQZSZ.js} +10 -1
  42. package/dist/chunk-X6EUQZSZ.js.map +1 -0
  43. package/dist/{chunk-WQ3UUUKF.js → chunk-Y4AH5JY4.js} +6 -4
  44. package/dist/chunk-Y4AH5JY4.js.map +1 -0
  45. package/dist/components/auth/forgot-password.js +2 -2
  46. package/dist/components/auth/reset-password-form.js +2 -2
  47. package/dist/components/auth/set-password.js +2 -2
  48. package/dist/components/auth/sign-in.js +2 -2
  49. package/dist/components/auth/sign-up.js +2 -2
  50. package/dist/components/auth/verify-email.js +2 -2
  51. package/dist/components/auth/verify-phone.js +2 -2
  52. package/dist/components/iam/domains-page.d.ts +1 -0
  53. package/dist/components/iam/domains-page.js +14 -0
  54. package/dist/components/iam/domains-page.js.map +1 -0
  55. package/dist/components/iam/iam-guard.d.ts +7 -0
  56. package/dist/components/iam/iam-guard.js +10 -0
  57. package/dist/components/iam/iam-guard.js.map +1 -0
  58. package/dist/components/iam/permissions-page.js +3 -1
  59. package/dist/components/iam/role-detail-page.d.ts +1 -1
  60. package/dist/components/iam/role-detail-page.js +3 -1
  61. package/dist/components/iam/role-permissions-page.d.ts +1 -1
  62. package/dist/components/iam/role-permissions-page.js +3 -1
  63. package/dist/components/iam/roles-page.js +3 -1
  64. package/dist/components/iam/sessions-page.js +3 -1
  65. package/dist/components/iam/tenants-page.js +3 -1
  66. package/dist/components/iam/users-page.js +4 -2
  67. package/dist/components/profile/change-email-form.js +2 -2
  68. package/dist/components/profile/change-phone-form.js +1 -1
  69. package/dist/components/profile/security.js +6 -6
  70. package/dist/index.d.ts +2 -0
  71. package/dist/index.js +60 -52
  72. package/dist/index.js.map +1 -1
  73. package/dist/pages/auth/forgot-password.js +2 -2
  74. package/dist/pages/auth/reset-password.js +2 -2
  75. package/dist/pages/auth/set-password.js +2 -2
  76. package/dist/pages/auth/sign-in.js +2 -2
  77. package/dist/pages/auth/sign-up.js +2 -2
  78. package/dist/pages/auth/verify-email.js +2 -2
  79. package/dist/pages/auth/verify-phone.js +2 -2
  80. package/dist/pages/iam/domains/_components/domain-card.d.ts +6 -0
  81. package/dist/pages/iam/domains/_components/domain-form.d.ts +9 -0
  82. package/dist/pages/iam/domains/_components/domains-data.d.ts +10 -0
  83. package/dist/pages/iam/domains/_components/domains-list.d.ts +15 -0
  84. package/dist/pages/iam/domains.d.ts +1 -0
  85. package/dist/pages/iam/permissions.js +3 -1
  86. package/dist/pages/iam/role-detail.js +3 -1
  87. package/dist/pages/iam/role-detail.js.map +1 -1
  88. package/dist/pages/iam/role-permissions.js +3 -1
  89. package/dist/pages/iam/role-permissions.js.map +1 -1
  90. package/dist/pages/iam/role-users.js +5 -3
  91. package/dist/pages/iam/role-users.js.map +1 -1
  92. package/dist/pages/iam/roles/users/_components/role-users-page.d.ts +1 -1
  93. package/dist/pages/iam/roles.js +3 -1
  94. package/dist/pages/iam/sessions.js +3 -1
  95. package/dist/pages/iam/tenant-detail.js +3 -1
  96. package/dist/pages/iam/tenant-detail.js.map +1 -1
  97. package/dist/pages/iam/tenants/tenant-detail-page-content.d.ts +1 -1
  98. package/dist/pages/iam/tenants.js +3 -1
  99. package/dist/pages/iam/user-activity.js +3 -1
  100. package/dist/pages/iam/user-activity.js.map +1 -1
  101. package/dist/pages/iam/user-detail-layout.js +3 -1
  102. package/dist/pages/iam/user-detail-layout.js.map +1 -1
  103. package/dist/pages/iam/user-detail.js +3 -1
  104. package/dist/pages/iam/user-detail.js.map +1 -1
  105. package/dist/pages/iam/users/_components/user-detail-layout-content.d.ts +1 -1
  106. package/dist/pages/iam/users/_components/user-detail-page-content.d.ts +1 -1
  107. package/dist/pages/iam/users/activity/user-activity-page-content.d.ts +1 -1
  108. package/dist/pages/iam/users/user-selector.js +2 -2
  109. package/dist/pages/iam/users.js +4 -2
  110. package/dist/pages/profile/security.js +6 -6
  111. package/dist/utils/handle-error.d.ts +4 -1
  112. package/package.json +3 -3
  113. package/dist/chunk-55BMNC4S.js.map +0 -1
  114. package/dist/chunk-A7ORWWM5.js.map +0 -1
  115. package/dist/chunk-DY3NVBLJ.js.map +0 -1
  116. package/dist/chunk-ETOCBXDT.js.map +0 -1
  117. package/dist/chunk-FPYQ7XGV.js.map +0 -1
  118. package/dist/chunk-HXHI4FU6.js.map +0 -1
  119. package/dist/chunk-IFAVSKHE.js.map +0 -1
  120. package/dist/chunk-KOBZ34XU.js.map +0 -1
  121. package/dist/chunk-L32Z3TPA.js.map +0 -1
  122. package/dist/chunk-LHZ4EEN6.js.map +0 -1
  123. package/dist/chunk-NUWAI3FE.js.map +0 -1
  124. package/dist/chunk-SW7WD64K.js.map +0 -1
  125. package/dist/chunk-SXVTYYUT.js.map +0 -1
  126. package/dist/chunk-WQ3UUUKF.js.map +0 -1
  127. package/dist/chunk-YN7OEQI7.js.map +0 -1
  128. package/dist/chunk-ZXKEG3X5.js.map +0 -1
  129. /package/dist/{chunk-TB2ZPGLW.js.map → chunk-4X3CJHKR.js.map} +0 -0
  130. /package/dist/{chunk-PG65ZD7A.js.map → chunk-5BFG47VF.js.map} +0 -0
  131. /package/dist/{chunk-OQUUS5ZX.js.map → chunk-5E3XN6SW.js.map} +0 -0
  132. /package/dist/{chunk-RBXITSE2.js.map → chunk-73ZNGEWU.js.map} +0 -0
  133. /package/dist/{chunk-G74DDR4O.js.map → chunk-GBDNBY6K.js.map} +0 -0
  134. /package/dist/{chunk-A3GIMM2R.js.map → chunk-H7JRQFFI.js.map} +0 -0
  135. /package/dist/{chunk-UAKGEJUN.js.map → chunk-TEHMLZFI.js.map} +0 -0
  136. /package/dist/{chunk-CXMPZWMX.js.map → chunk-VVKXFEAN.js.map} +0 -0
@@ -1,15 +1,15 @@
1
1
  "use client";
2
2
  import {
3
3
  Security
4
- } from "../../chunk-RBXITSE2.js";
4
+ } from "../../chunk-73ZNGEWU.js";
5
+ import "../../chunk-5BFG47VF.js";
6
+ import "../../chunk-5AEV7RAN.js";
7
+ import "../../chunk-ZZ6D4KE4.js";
5
8
  import "../../chunk-TLQMK2QF.js";
6
9
  import "../../chunk-6IEX2RLA.js";
7
- import "../../chunk-DG6GRTPG.js";
8
- import "../../chunk-PG65ZD7A.js";
9
- import "../../chunk-X2BHF4KC.js";
10
- import "../../chunk-5AEV7RAN.js";
11
10
  import "../../chunk-UGQP733V.js";
12
- import "../../chunk-ZZ6D4KE4.js";
11
+ import "../../chunk-X2BHF4KC.js";
12
+ import "../../chunk-DG6GRTPG.js";
13
13
  import "../../chunk-Z34NJZRL.js";
14
14
  import "../../chunk-RMJNENJB.js";
15
15
  import "../../chunk-V2W3WPCZ.js";
@@ -3,5 +3,8 @@ export type AuthErrorContent = {
3
3
  description: string;
4
4
  };
5
5
  type TranslatorFunction = (key: string, params?: Record<string, string | number>) => string;
6
- export declare const handleError: (err: unknown, setError: (error: AuthErrorContent | null) => void, t: TranslatorFunction) => void;
6
+ export type HandleErrorOptions = {
7
+ signIn?: boolean;
8
+ };
9
+ export declare const handleError: (err: unknown, setError: (error: AuthErrorContent | null) => void, t: TranslatorFunction, options?: HandleErrorOptions) => void;
7
10
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mesob/auth-react",
3
- "version": "0.4.6",
3
+ "version": "0.4.7",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -132,8 +132,8 @@
132
132
  ],
133
133
  "dependencies": {
134
134
  "@hookform/resolvers": "^5.2.2",
135
- "@mesob/common": "^0.4.6",
136
- "@mesob/ui": "^0.4.6",
135
+ "@mesob/common": "^0.4.7",
136
+ "@mesob/ui": "^0.4.7",
137
137
  "@tabler/icons-react": "^3.35.0",
138
138
  "deepmerge-ts": "^7.1.5",
139
139
  "nuqs": "^2.8.1",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/constants/auth.error.codes.ts","../src/utils/handle-error.ts"],"sourcesContent":["export const AUTH_ERROR_MAPPING: Record<\n string,\n { title: string; description: string }\n> = {\n USER_NOT_FOUND: {\n title: 'Account Not Found',\n description:\n 'We could not find an account with that identifier. Please check your spelling or sign up.',\n },\n INVALID_PASSWORD: {\n title: 'Invalid Password',\n description: 'The password you entered is incorrect. Please try again.',\n },\n USER_EXISTS: {\n title: 'Account Already Exists',\n description:\n 'An account with this identifier already exists. Please sign in instead.',\n },\n VERIFICATION_EXPIRED: {\n title: 'Verification Expired',\n description:\n 'The verification code or link has expired. Please request a new one.',\n },\n VERIFICATION_MISMATCH: {\n title: 'Invalid Code',\n description:\n 'The verification code you entered is invalid. Please double-check and try again.',\n },\n VERIFICATION_NOT_FOUND: {\n title: 'Verification Not Found',\n description:\n 'We could not find a pending verification request. Please restart the process.',\n },\n TOO_MANY_ATTEMPTS: {\n title: 'Too Many Attempts',\n description:\n 'You have made too many requests recently. Please wait a moment before trying again.',\n },\n REQUIRES_VERIFICATION: {\n title: 'Verification Required',\n description:\n 'You need to verify your account before you can continue. Please check your email or phone.',\n },\n UNAUTHORIZED: {\n title: 'Unauthorized',\n description:\n 'You are not authorized to perform this action. Please sign in again.',\n },\n ACCESS_DENIED: {\n title: 'Access Denied',\n description:\n 'You do not have permission to access this resource. Please contact support if you believe this is an error.',\n },\n HAS_NO_PASSWORD: {\n title: 'No Password Set',\n description:\n 'Your account does not have a password yet. Continue to set a password before signing in.',\n },\n PASSWORD_ALREADY_SET: {\n title: 'Password Already Set',\n description:\n 'This account already has a password. Use the normal sign-in form instead.',\n },\n};\n\nexport const validCodes = Object.keys(AUTH_ERROR_MAPPING);\n","import { AUTH_ERROR_MAPPING, validCodes } from '../constants/auth.error.codes';\nimport type { AuthError } from '../types';\n\nexport type AuthErrorContent = {\n title: string;\n description: string;\n};\n\ntype TranslatorFunction = (\n key: string,\n params?: Record<string, string | number>,\n) => string;\n\n// Type guard to check if error is an AuthError\nfunction isAuthError(err: unknown): err is AuthError {\n return (\n typeof err === 'object' &&\n err !== null &&\n 'message' in err &&\n typeof (err as { message: unknown }).message === 'string'\n );\n}\n\nfunction extractErrorCode(err: AuthError): string {\n if (err.code && validCodes.includes(err.code)) {\n return err.code;\n }\n if (err.message) {\n const messageUpper = err.message.toUpperCase().trim();\n if (validCodes.includes(messageUpper)) {\n return messageUpper;\n }\n }\n return '';\n}\n\nfunction sanitizeErrorMessage(message: string): string {\n const lowerMessage = message.toLowerCase();\n const isDatabaseError =\n lowerMessage.includes('failed query') ||\n lowerMessage.includes('select') ||\n lowerMessage.includes('insert') ||\n lowerMessage.includes('update') ||\n lowerMessage.includes('delete') ||\n lowerMessage.includes('from') ||\n lowerMessage.includes('where') ||\n lowerMessage.includes('limit') ||\n lowerMessage.includes('params:') ||\n lowerMessage.includes('query') ||\n message.includes('\"iam\".') ||\n message.includes('\"tenants\"') ||\n message.includes('\"users\"') ||\n message.includes('\"sessions\"') ||\n message.includes('\"accounts\"') ||\n lowerMessage.includes('relation') ||\n lowerMessage.includes('column') ||\n lowerMessage.includes('syntax error') ||\n lowerMessage.includes('database') ||\n lowerMessage.includes('postgres') ||\n lowerMessage.includes('sql');\n\n if (isDatabaseError) {\n return 'An error occurred while processing your request';\n }\n\n return message;\n}\n\nfunction handleAuthError(\n err: AuthError,\n setError: (error: AuthErrorContent | null) => void,\n t: TranslatorFunction,\n) {\n const errorCode = extractErrorCode(err);\n\n if (errorCode && AUTH_ERROR_MAPPING[errorCode]) {\n const mapping = AUTH_ERROR_MAPPING[errorCode];\n setError({\n title: mapping.title,\n description: mapping.description,\n });\n return;\n }\n\n const sanitizedMessage = sanitizeErrorMessage(\n err.message || t('errors.fallback'),\n );\n setError({\n title: t('errors.fallback'),\n description: sanitizedMessage,\n });\n}\n\nfunction handleGenericError(\n err: unknown,\n setError: (error: AuthErrorContent | null) => void,\n t: TranslatorFunction,\n) {\n const rawMessage = err instanceof Error ? err.message : t('errors.fallback');\n const sanitizedMessage = sanitizeErrorMessage(rawMessage);\n setError({\n title: 'Error',\n description: sanitizedMessage,\n });\n}\n\nexport const handleError = (\n err: unknown,\n setError: (error: AuthErrorContent | null) => void,\n t: TranslatorFunction,\n) => {\n if (isAuthError(err)) {\n handleAuthError(err, setError, t);\n } else {\n handleGenericError(err, setError, t);\n }\n};\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/pages/iam/users/activity/user-activity-page-content.tsx","../src/pages/iam/users/activity/_components/role-section.tsx","../src/pages/iam/roles/_components/role-selector.tsx"],"sourcesContent":["'use client';\n\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Section,\n} from '@mesob/ui/components';\nimport { IconCalendar } from '@tabler/icons-react';\nimport { RoleSection } from './_components/role-section';\n\ntype UserActivityPageContentProps = {\n userId: string;\n};\n\nexport function UserActivityPageContent({\n userId,\n}: UserActivityPageContentProps) {\n if (!userId) {\n return null;\n }\n\n return (\n <div className=\"space-y-4\">\n <Card>\n <CardHeader>\n <CardTitle>Activity</CardTitle>\n </CardHeader>\n <CardContent className=\"flex items-center gap-2 text-muted-foreground text-sm\">\n <IconCalendar className=\"h-4 w-4\" />\n Activity (placeholder)\n </CardContent>\n </Card>\n <RoleSection userId={userId} />\n <Section title=\"Permissions\">test</Section>\n <Section title=\"Groups\">test</Section>\n </div>\n );\n}\n","'use client';\n\nimport {\n Button,\n EntityEmptyState,\n EntityLoadingState,\n EntitySection,\n useEntitySectionState,\n} from '@mesob/ui/components';\nimport { IconPlus, IconShield } from '@tabler/icons-react';\nimport { useMemo, useState } from 'react';\nimport { RoleSelector } from '../../../roles/_components/role-selector';\nimport type { Role } from '../../../roles/_components/roles-data';\nimport { str } from '../../../roles/_components/roles-data';\nimport { RolesList } from '../../../roles/_components/roles-list';\nimport {\n authApi$,\n defaultEntityQueryOptions,\n} from '../../../shared/page-helpers';\n\nconst LIMIT = 100;\nconst TABLE_COLUMN_COUNT = 4;\n\nfunction filterAndSort(\n roles: Role[],\n search: string,\n sort: string,\n order: 'asc' | 'desc',\n) {\n let out = roles;\n if (search.trim()) {\n const q = search.trim().toLowerCase();\n out = out.filter(\n (r) =>\n str(r.name).toLowerCase().includes(q) ||\n r.code.toLowerCase().includes(q),\n );\n }\n const mult = order === 'asc' ? 1 : -1;\n const by = sort === 'code' ? 'code' : 'createdAt';\n out = [...out].sort((a, b) =>\n by === 'code'\n ? mult * a.code.localeCompare(b.code)\n : mult *\n (new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()),\n );\n return out;\n}\n\nexport function RoleSection({ userId }: { userId: string }) {\n const [open, setOpen] = useState(false);\n const sectionState = useEntitySectionState({\n defaultSort: 'createdAt',\n defaultOrder: 'desc',\n defaultPageSize: 10,\n filterOptions: [\n { label: 'All', value: '' },\n { label: 'By Code', value: 'code' },\n ],\n sortOptions: [\n { label: 'Created', value: 'createdAt' },\n { label: 'Updated', value: 'updatedAt' },\n { label: 'Code', value: 'code' },\n ],\n views: ['table', 'card'],\n });\n\n const { data, isPending, isFetching } = authApi$.useQuery(\n 'get',\n '/roles',\n { params: { query: { limit: LIMIT } } },\n { ...defaultEntityQueryOptions, enabled: open },\n );\n const isLoading = isPending || isFetching;\n const roles = data?.roles ?? [];\n\n const filtered = useMemo(\n () =>\n filterAndSort(\n roles,\n sectionState.search,\n sectionState.sort,\n sectionState.order,\n ),\n [roles, sectionState.search, sectionState.sort, sectionState.order],\n );\n const pageCount = Math.ceil(filtered.length / sectionState.pageSize) || 1;\n const pageIndex = Math.min(sectionState.page - 1, Math.max(0, pageCount - 1));\n const paginated = useMemo(\n () =>\n filtered.slice(\n pageIndex * sectionState.pageSize,\n pageIndex * sectionState.pageSize + sectionState.pageSize,\n ),\n [filtered, pageIndex, sectionState.pageSize],\n );\n\n return (\n <EntitySection\n title=\"Role\"\n state={sectionState}\n onOpenChange={setOpen}\n actions={\n <RoleSelector\n trigger={\n <Button variant=\"outline\" size=\"sm\">\n <IconPlus className=\"h-4 w-4\" />\n Add role\n </Button>\n }\n multiple\n onSelect={(roles) => {\n // TODO: assign roles to user; logging for now\n // biome-ignore lint/suspicious/noConsole: intentional for now\n console.log('Selected roles:', userId, roles);\n }}\n />\n }\n config={{\n searchPlaceholder: 'Search roles...',\n filterOptions: sectionState.filterOptions,\n sortOptions: sectionState.sortOptions,\n views: sectionState.views,\n }}\n >\n {(state) => (\n <>\n {isLoading && (\n <EntityLoadingState\n view={state.view as 'table' | 'card'}\n rowCount={state.pageSize}\n columnCount={TABLE_COLUMN_COUNT}\n cardCount={state.pageSize}\n />\n )}\n {!isLoading && filtered.length === 0 && (\n <EntityEmptyState\n icon={IconShield}\n entityName=\"role\"\n title=\"No roles\"\n description={\n roles.length === 0 ? 'No roles in tenant.' : 'No matches.'\n }\n />\n )}\n {!isLoading && filtered.length > 0 && (\n <RolesList\n data={paginated}\n view={state.view as 'table' | 'card'}\n pageIndex={pageIndex}\n pageSize={state.pageSize}\n pageCount={pageCount}\n totalRows={filtered.length}\n onPageChange={(p) => state.setPage(p + 1)}\n onPageSizeChange={(size) => {\n state.setPageSize(size);\n state.setPage(1);\n }}\n />\n )}\n </>\n )}\n </EntitySection>\n );\n}\n","'use client';\n\nimport {\n EntitySelector,\n type EntitySelectorColumn,\n type EntitySelectorConfig,\n useEntitySectionState,\n} from '@mesob/ui/components';\nimport { cn } from '@mesob/ui/lib/utils';\nimport { IconCalendar, IconShield } from '@tabler/icons-react';\nimport type { ReactNode } from 'react';\nimport type { paths } from '../../../../data/openapi';\nimport { authApi$, defaultEntityQueryOptions } from '../../shared/page-helpers';\nimport { RoleCard } from './role-card';\nimport type { Role } from './roles-data';\nimport { str } from './roles-data';\n\nfunction SelectableRoleCard({\n role,\n selected,\n onToggle,\n}: {\n role: Role;\n selected: boolean;\n onToggle: () => void;\n}) {\n return (\n // biome-ignore lint/a11y/useSemanticElements: div to avoid nested buttons from RoleCard\n <div\n role=\"button\"\n tabIndex={0}\n onClick={onToggle}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n onToggle();\n }\n }}\n className={cn(\n 'cursor-pointer rounded-lg transition-shadow focus:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n selected && 'ring-primary ring-2',\n )}\n >\n <RoleCard role={role} mode=\"static\" />\n </div>\n );\n}\n\nconst roleColumns: EntitySelectorColumn<Role>[] = [\n {\n key: 'role',\n header: 'Role',\n cell: (role) => (\n <>\n <p className=\"font-medium\">{str(role.name) || role.code}</p>\n <p className=\"text-sm text-muted-foreground\">{role.code}</p>\n </>\n ),\n },\n {\n key: 'description',\n header: 'Description',\n cell: (role) => (\n <span className=\"text-muted-foreground line-clamp-1 max-w-[200px]\">\n {str(role.description) || '—'}\n </span>\n ),\n },\n {\n key: 'created',\n header: 'Created',\n cell: (role) => (\n <div className=\"flex items-center gap-1 text-muted-foreground\">\n <IconCalendar className=\"h-4 w-4\" />\n {new Date(role.createdAt).toLocaleDateString()}\n </div>\n ),\n },\n];\n\ntype RoleSelectorProps = {\n trigger: ReactNode;\n multiple?: boolean;\n onSelect: (roles: Role[]) => void;\n modalSize?: 'sm' | 'md' | 'lg' | 'xl' | 'full';\n contentClassName?: string;\n};\n\nexport function RoleSelector({\n trigger,\n multiple = true,\n onSelect,\n modalSize = 'xl',\n contentClassName,\n}: RoleSelectorProps) {\n const state = useEntitySectionState({\n defaultSort: 'createdAt',\n defaultOrder: 'desc',\n defaultPageSize: 10,\n searchParamName: 'search',\n });\n const rolesQuery = state.queryConfig as {\n params: {\n query: NonNullable<paths['/roles']['get']['parameters']['query']>;\n };\n };\n\n const { data, isPending, isFetching } = authApi$.useQuery(\n 'get',\n '/roles',\n rolesQuery,\n defaultEntityQueryOptions,\n );\n\n const roles = data?.roles ?? [];\n\n const config: EntitySelectorConfig<Role> = {\n title: 'Select role(s)',\n modalSize,\n contentClassName,\n multiple,\n entityName: 'role',\n entityIcon: IconShield,\n columns: roleColumns,\n columnCount: 3,\n getItemLabel: (role) => str(role.name) || role.code,\n searchPlaceholder: 'Search roles...',\n wrapHeaderInCard: false,\n filterOptions: [\n { label: 'All', value: '' },\n { label: 'By Code', value: 'code' },\n ],\n sortOptions: [\n { label: 'Created', value: 'createdAt' },\n { label: 'Updated', value: 'updatedAt' },\n { label: 'Code', value: 'code' },\n ],\n showViewToggle: false,\n renderCard: (role, selected, onToggle) => (\n <SelectableRoleCard role={role} selected={selected} onToggle={onToggle} />\n ),\n };\n\n return (\n <EntitySelector<Role>\n trigger={trigger}\n config={config}\n onSelect={onSelect}\n items={roles}\n total={data?.total}\n isLoading={isPending || isFetching}\n state={state}\n />\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AAEA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,gBAAAA,qBAAoB;;;ACP7B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,yBAAAC;AAAA,OACK;AACP,SAAS,UAAU,cAAAC,mBAAkB;AACrC,SAAS,SAAS,gBAAgB;;;ACRlC;AAAA,EACE;AAAA,EAGA;AAAA,OACK;AACP,SAAS,UAAU;AACnB,SAAS,cAAc,kBAAkB;AAiCnC,SAUA,UAVA,KAUA,YAVA;AAzBN,SAAS,mBAAmB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD;AAAA;AAAA,IAEE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,UAAU;AAAA,QACV,SAAS;AAAA,QACT,WAAW,CAAC,MAAM;AAChB,cAAI,EAAE,QAAQ,SAAS;AACrB,qBAAS;AAAA,UACX;AAAA,QACF;AAAA,QACA,WAAW;AAAA,UACT;AAAA,UACA,YAAY;AAAA,QACd;AAAA,QAEA,8BAAC,YAAS,MAAY,MAAK,UAAS;AAAA;AAAA,IACtC;AAAA;AAEJ;AAEA,IAAM,cAA4C;AAAA,EAChD;AAAA,IACE,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,MAAM,CAAC,SACL,iCACE;AAAA,0BAAC,OAAE,WAAU,eAAe,cAAI,KAAK,IAAI,KAAK,KAAK,MAAK;AAAA,MACxD,oBAAC,OAAE,WAAU,iCAAiC,eAAK,MAAK;AAAA,OAC1D;AAAA,EAEJ;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,MAAM,CAAC,SACL,oBAAC,UAAK,WAAU,oDACb,cAAI,KAAK,WAAW,KAAK,UAC5B;AAAA,EAEJ;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,MAAM,CAAC,SACL,qBAAC,SAAI,WAAU,iDACb;AAAA,0BAAC,gBAAa,WAAU,WAAU;AAAA,MACjC,IAAI,KAAK,KAAK,SAAS,EAAE,mBAAmB;AAAA,OAC/C;AAAA,EAEJ;AACF;AAUO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA,YAAY;AAAA,EACZ;AACF,GAAsB;AACpB,QAAM,QAAQ,sBAAsB;AAAA,IAClC,aAAa;AAAA,IACb,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,EACnB,CAAC;AACD,QAAM,aAAa,MAAM;AAMzB,QAAM,EAAE,MAAM,WAAW,WAAW,IAAI,SAAS;AAAA,IAC/C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,QAAQ,MAAM,SAAS,CAAC;AAE9B,QAAM,SAAqC;AAAA,IACzC,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,aAAa;AAAA,IACb,cAAc,CAAC,SAAS,IAAI,KAAK,IAAI,KAAK,KAAK;AAAA,IAC/C,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,eAAe;AAAA,MACb,EAAE,OAAO,OAAO,OAAO,GAAG;AAAA,MAC1B,EAAE,OAAO,WAAW,OAAO,OAAO;AAAA,IACpC;AAAA,IACA,aAAa;AAAA,MACX,EAAE,OAAO,WAAW,OAAO,YAAY;AAAA,MACvC,EAAE,OAAO,WAAW,OAAO,YAAY;AAAA,MACvC,EAAE,OAAO,QAAQ,OAAO,OAAO;AAAA,IACjC;AAAA,IACA,gBAAgB;AAAA,IAChB,YAAY,CAAC,MAAM,UAAU,aAC3B,oBAAC,sBAAmB,MAAY,UAAoB,UAAoB;AAAA,EAE5E;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO;AAAA,MACP,OAAO,MAAM;AAAA,MACb,WAAW,aAAa;AAAA,MACxB;AAAA;AAAA,EACF;AAEJ;;;ADhDY,SAqBJ,YAAAC,WApBM,OAAAC,MADF,QAAAC,aAAA;AArFZ,IAAM,QAAQ;AACd,IAAM,qBAAqB;AAE3B,SAAS,cACP,OACA,QACA,MACA,OACA;AACA,MAAI,MAAM;AACV,MAAI,OAAO,KAAK,GAAG;AACjB,UAAM,IAAI,OAAO,KAAK,EAAE,YAAY;AACpC,UAAM,IAAI;AAAA,MACR,CAAC,MACC,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,CAAC,KACpC,EAAE,KAAK,YAAY,EAAE,SAAS,CAAC;AAAA,IACnC;AAAA,EACF;AACA,QAAM,OAAO,UAAU,QAAQ,IAAI;AACnC,QAAM,KAAK,SAAS,SAAS,SAAS;AACtC,QAAM,CAAC,GAAG,GAAG,EAAE;AAAA,IAAK,CAAC,GAAG,MACtB,OAAO,SACH,OAAO,EAAE,KAAK,cAAc,EAAE,IAAI,IAClC,QACC,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ;AAAA,EACvE;AACA,SAAO;AACT;AAEO,SAAS,YAAY,EAAE,OAAO,GAAuB;AAC1D,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,eAAeC,uBAAsB;AAAA,IACzC,aAAa;AAAA,IACb,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,eAAe;AAAA,MACb,EAAE,OAAO,OAAO,OAAO,GAAG;AAAA,MAC1B,EAAE,OAAO,WAAW,OAAO,OAAO;AAAA,IACpC;AAAA,IACA,aAAa;AAAA,MACX,EAAE,OAAO,WAAW,OAAO,YAAY;AAAA,MACvC,EAAE,OAAO,WAAW,OAAO,YAAY;AAAA,MACvC,EAAE,OAAO,QAAQ,OAAO,OAAO;AAAA,IACjC;AAAA,IACA,OAAO,CAAC,SAAS,MAAM;AAAA,EACzB,CAAC;AAED,QAAM,EAAE,MAAM,WAAW,WAAW,IAAI,SAAS;AAAA,IAC/C;AAAA,IACA;AAAA,IACA,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,MAAM,EAAE,EAAE;AAAA,IACtC,EAAE,GAAG,2BAA2B,SAAS,KAAK;AAAA,EAChD;AACA,QAAM,YAAY,aAAa;AAC/B,QAAM,QAAQ,MAAM,SAAS,CAAC;AAE9B,QAAM,WAAW;AAAA,IACf,MACE;AAAA,MACE;AAAA,MACA,aAAa;AAAA,MACb,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAAA,IACF,CAAC,OAAO,aAAa,QAAQ,aAAa,MAAM,aAAa,KAAK;AAAA,EACpE;AACA,QAAM,YAAY,KAAK,KAAK,SAAS,SAAS,aAAa,QAAQ,KAAK;AACxE,QAAM,YAAY,KAAK,IAAI,aAAa,OAAO,GAAG,KAAK,IAAI,GAAG,YAAY,CAAC,CAAC;AAC5E,QAAM,YAAY;AAAA,IAChB,MACE,SAAS;AAAA,MACP,YAAY,aAAa;AAAA,MACzB,YAAY,aAAa,WAAW,aAAa;AAAA,IACnD;AAAA,IACF,CAAC,UAAU,WAAW,aAAa,QAAQ;AAAA,EAC7C;AAEA,SACE,gBAAAF;AAAA,IAAC;AAAA;AAAA,MACC,OAAM;AAAA,MACN,OAAO;AAAA,MACP,cAAc;AAAA,MACd,SACE,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,SACE,gBAAAC,MAAC,UAAO,SAAQ,WAAU,MAAK,MAC7B;AAAA,4BAAAD,KAAC,YAAS,WAAU,WAAU;AAAA,YAAE;AAAA,aAElC;AAAA,UAEF,UAAQ;AAAA,UACR,UAAU,CAACG,WAAU;AAGnB,oBAAQ,IAAI,mBAAmB,QAAQA,MAAK;AAAA,UAC9C;AAAA;AAAA,MACF;AAAA,MAEF,QAAQ;AAAA,QACN,mBAAmB;AAAA,QACnB,eAAe,aAAa;AAAA,QAC5B,aAAa,aAAa;AAAA,QAC1B,OAAO,aAAa;AAAA,MACtB;AAAA,MAEC,WAAC,UACA,gBAAAF,MAAAF,WAAA,EACG;AAAA,qBACC,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACC,MAAM,MAAM;AAAA,YACZ,UAAU,MAAM;AAAA,YAChB,aAAa;AAAA,YACb,WAAW,MAAM;AAAA;AAAA,QACnB;AAAA,QAED,CAAC,aAAa,SAAS,WAAW,KACjC,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAMI;AAAA,YACN,YAAW;AAAA,YACX,OAAM;AAAA,YACN,aACE,MAAM,WAAW,IAAI,wBAAwB;AAAA;AAAA,QAEjD;AAAA,QAED,CAAC,aAAa,SAAS,SAAS,KAC/B,gBAAAJ;AAAA,UAAC;AAAA;AAAA,YACC,MAAM;AAAA,YACN,MAAM,MAAM;AAAA,YACZ;AAAA,YACA,UAAU,MAAM;AAAA,YAChB;AAAA,YACA,WAAW,SAAS;AAAA,YACpB,cAAc,CAAC,MAAM,MAAM,QAAQ,IAAI,CAAC;AAAA,YACxC,kBAAkB,CAAC,SAAS;AAC1B,oBAAM,YAAY,IAAI;AACtB,oBAAM,QAAQ,CAAC;AAAA,YACjB;AAAA;AAAA,QACF;AAAA,SAEJ;AAAA;AAAA,EAEJ;AAEJ;;;ADzIU,gBAAAK,MAEF,QAAAC,aAFE;AAXH,SAAS,wBAAwB;AAAA,EACtC;AACF,GAAiC;AAC/B,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AAEA,SACE,gBAAAA,MAAC,SAAI,WAAU,aACb;AAAA,oBAAAA,MAAC,QACC;AAAA,sBAAAD,KAAC,cACC,0BAAAA,KAAC,aAAU,sBAAQ,GACrB;AAAA,MACA,gBAAAC,MAAC,eAAY,WAAU,yDACrB;AAAA,wBAAAD,KAACE,eAAA,EAAa,WAAU,WAAU;AAAA,QAAE;AAAA,SAEtC;AAAA,OACF;AAAA,IACA,gBAAAF,KAAC,eAAY,QAAgB;AAAA,IAC7B,gBAAAA,KAAC,WAAQ,OAAM,eAAc,kBAAI;AAAA,IACjC,gBAAAA,KAAC,WAAQ,OAAM,UAAS,kBAAI;AAAA,KAC9B;AAEJ;","names":["IconCalendar","useEntitySectionState","IconShield","Fragment","jsx","jsxs","useEntitySectionState","roles","IconShield","jsx","jsxs","IconCalendar"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/iam/role-detail-page.tsx"],"sourcesContent":["'use client';\n\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport {\n EntityFormActions,\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n Input,\n LocaleInputText,\n LocaleInputTextarea,\n Section,\n Skeleton,\n} from '@mesob/ui/components';\nimport { useLocaleSchemas } from '@mesob/ui/providers';\nimport { useQueryClient } from '@tanstack/react-query';\nimport { useEffect, useMemo } from 'react';\nimport type { Resolver } from 'react-hook-form';\nimport { useForm } from 'react-hook-form';\nimport { toast } from 'sonner';\nimport { z } from 'zod';\nimport { useApi, useConfig } from '../../provider';\n\ntype RoleFormData = {\n name: Record<string, string>;\n code: string;\n description: Record<string, string>;\n};\n\ntype RoleDetailPageProps = {\n roleId: string;\n basePath?: string;\n};\n\nexport function RoleDetailPage({\n roleId,\n basePath = '/iam/roles',\n}: RoleDetailPageProps) {\n const { hooks } = useApi();\n const { config } = useConfig();\n const qc = useQueryClient();\n const { localeInputDefault, requiredSchema, optionalSchema } =\n useLocaleSchemas();\n const schema = useMemo(\n () =>\n z.object({\n name: requiredSchema,\n code: z.string().min(1, 'Code is required'),\n description: optionalSchema,\n }),\n [requiredSchema, optionalSchema],\n );\n const defaults: RoleFormData = useMemo(\n () => ({\n name: { ...localeInputDefault },\n code: '',\n description: { ...localeInputDefault },\n }),\n [localeInputDefault],\n );\n\n const { data, isLoading } = hooks.useQuery(\n 'get',\n '/roles/{id}',\n { params: { path: { id: roleId } } },\n { enabled: !!roleId },\n );\n\n const update = hooks.useMutation('put', '/roles/{id}', {\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: ['get', '/roles'] });\n qc.invalidateQueries({ queryKey: ['get', '/roles/{id}'] });\n toast.success('Role updated');\n },\n onError: () => {\n toast.error('Failed to update role');\n },\n });\n const remove = hooks.useMutation('delete', '/roles/{id}', {\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: ['get', '/roles'] });\n toast.success('Role deleted');\n config.navigation?.onNavigate?.(basePath);\n },\n onError: () => {\n toast.error('Failed to delete role');\n },\n });\n\n const form = useForm<RoleFormData>({\n resolver: zodResolver(schema) as Resolver<RoleFormData>,\n defaultValues: defaults,\n });\n\n const { reset, formState, control, register } = form;\n\n useEffect(() => {\n if (!data?.role) {\n return;\n }\n const r = data.role;\n reset({\n name: (r.name ?? {}) as RoleFormData['name'],\n code: r.code,\n description: (r.description ?? {}) as RoleFormData['description'],\n });\n }, [data?.role, reset]);\n\n if (!roleId) {\n return null;\n }\n\n const role = data?.role;\n const editable = role?.isEditable !== false;\n const deletable = role?.isDeletable !== false;\n const onSubmit = form.handleSubmit(async (d) => {\n await update.mutateAsync({\n params: { path: { id: roleId } },\n body: {\n name: d.name,\n code: d.code,\n description: d.description ?? undefined,\n },\n });\n });\n\n const footer = role ? (\n <EntityFormActions\n mode=\"edit\"\n onSubmit={onSubmit}\n onDelete={\n deletable\n ? () =>\n remove.mutate({\n params: { path: { id: roleId } },\n })\n : undefined\n }\n isSubmitting={update.isPending}\n isDeleting={remove.isPending}\n disabled={!editable}\n itemName=\"role\"\n />\n ) : null;\n\n return (\n <Section title=\"Role details\" footer={footer} defaultOpen>\n {isLoading || !role ? (\n <RoleDetailSkeleton />\n ) : (\n <Form {...form}>\n <form onSubmit={onSubmit} className=\"space-y-4\">\n <LocaleInputText\n label=\"Name\"\n field=\"name\"\n required\n register={register}\n errors={formState.errors}\n placeholder=\"e.g. Administrator\"\n disabled={!editable}\n />\n <FormField\n control={control}\n name=\"code\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>\n Code <span className=\"text-destructive\">*</span>\n </FormLabel>\n <FormControl>\n <Input\n placeholder=\"e.g. admin\"\n disabled={!editable}\n {...field}\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n <LocaleInputTextarea\n label=\"Description\"\n field=\"description\"\n register={register}\n errors={formState.errors}\n placeholder=\"Description\"\n rows={3}\n disabled={!editable}\n />\n </form>\n </Form>\n )}\n </Section>\n );\n}\n\nfunction RoleDetailSkeleton() {\n return (\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Skeleton className=\"h-4 w-16\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n <div className=\"space-y-2\">\n <Skeleton className=\"h-4 w-14\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n <div className=\"space-y-2\">\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-20 w-full\" />\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;AAEA,SAAS,mBAAmB;AAC5B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,wBAAwB;AACjC,SAAS,sBAAsB;AAC/B,SAAS,WAAW,eAAe;AAEnC,SAAS,eAAe;AACxB,SAAS,aAAa;AACtB,SAAS,SAAS;AA2Gd,cAuCc,YAvCd;AA7FG,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA,WAAW;AACb,GAAwB;AACtB,QAAM,EAAE,MAAM,IAAI,OAAO;AACzB,QAAM,EAAE,OAAO,IAAI,UAAU;AAC7B,QAAM,KAAK,eAAe;AAC1B,QAAM,EAAE,oBAAoB,gBAAgB,eAAe,IACzD,iBAAiB;AACnB,QAAM,SAAS;AAAA,IACb,MACE,EAAE,OAAO;AAAA,MACP,MAAM;AAAA,MACN,MAAM,EAAE,OAAO,EAAE,IAAI,GAAG,kBAAkB;AAAA,MAC1C,aAAa;AAAA,IACf,CAAC;AAAA,IACH,CAAC,gBAAgB,cAAc;AAAA,EACjC;AACA,QAAM,WAAyB;AAAA,IAC7B,OAAO;AAAA,MACL,MAAM,EAAE,GAAG,mBAAmB;AAAA,MAC9B,MAAM;AAAA,MACN,aAAa,EAAE,GAAG,mBAAmB;AAAA,IACvC;AAAA,IACA,CAAC,kBAAkB;AAAA,EACrB;AAEA,QAAM,EAAE,MAAM,UAAU,IAAI,MAAM;AAAA,IAChC;AAAA,IACA;AAAA,IACA,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,OAAO,EAAE,EAAE;AAAA,IACnC,EAAE,SAAS,CAAC,CAAC,OAAO;AAAA,EACtB;AAEA,QAAM,SAAS,MAAM,YAAY,OAAO,eAAe;AAAA,IACrD,WAAW,MAAM;AACf,SAAG,kBAAkB,EAAE,UAAU,CAAC,OAAO,QAAQ,EAAE,CAAC;AACpD,SAAG,kBAAkB,EAAE,UAAU,CAAC,OAAO,aAAa,EAAE,CAAC;AACzD,YAAM,QAAQ,cAAc;AAAA,IAC9B;AAAA,IACA,SAAS,MAAM;AACb,YAAM,MAAM,uBAAuB;AAAA,IACrC;AAAA,EACF,CAAC;AACD,QAAM,SAAS,MAAM,YAAY,UAAU,eAAe;AAAA,IACxD,WAAW,MAAM;AACf,SAAG,kBAAkB,EAAE,UAAU,CAAC,OAAO,QAAQ,EAAE,CAAC;AACpD,YAAM,QAAQ,cAAc;AAC5B,aAAO,YAAY,aAAa,QAAQ;AAAA,IAC1C;AAAA,IACA,SAAS,MAAM;AACb,YAAM,MAAM,uBAAuB;AAAA,IACrC;AAAA,EACF,CAAC;AAED,QAAM,OAAO,QAAsB;AAAA,IACjC,UAAU,YAAY,MAAM;AAAA,IAC5B,eAAe;AAAA,EACjB,CAAC;AAED,QAAM,EAAE,OAAO,WAAW,SAAS,SAAS,IAAI;AAEhD,YAAU,MAAM;AACd,QAAI,CAAC,MAAM,MAAM;AACf;AAAA,IACF;AACA,UAAM,IAAI,KAAK;AACf,UAAM;AAAA,MACJ,MAAO,EAAE,QAAQ,CAAC;AAAA,MAClB,MAAM,EAAE;AAAA,MACR,aAAc,EAAE,eAAe,CAAC;AAAA,IAClC,CAAC;AAAA,EACH,GAAG,CAAC,MAAM,MAAM,KAAK,CAAC;AAEtB,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,MAAM;AACnB,QAAM,WAAW,MAAM,eAAe;AACtC,QAAM,YAAY,MAAM,gBAAgB;AACxC,QAAM,WAAW,KAAK,aAAa,OAAO,MAAM;AAC9C,UAAM,OAAO,YAAY;AAAA,MACvB,QAAQ,EAAE,MAAM,EAAE,IAAI,OAAO,EAAE;AAAA,MAC/B,MAAM;AAAA,QACJ,MAAM,EAAE;AAAA,QACR,MAAM,EAAE;AAAA,QACR,aAAa,EAAE,eAAe;AAAA,MAChC;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAED,QAAM,SAAS,OACb;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA,UACE,YACI,MACE,OAAO,OAAO;AAAA,QACZ,QAAQ,EAAE,MAAM,EAAE,IAAI,OAAO,EAAE;AAAA,MACjC,CAAC,IACH;AAAA,MAEN,cAAc,OAAO;AAAA,MACrB,YAAY,OAAO;AAAA,MACnB,UAAU,CAAC;AAAA,MACX,UAAS;AAAA;AAAA,EACX,IACE;AAEJ,SACE,oBAAC,WAAQ,OAAM,gBAAe,QAAgB,aAAW,MACtD,uBAAa,CAAC,OACb,oBAAC,sBAAmB,IAEpB,oBAAC,QAAM,GAAG,MACR,+BAAC,UAAK,UAAoB,WAAU,aAClC;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,OAAM;AAAA,QACN,UAAQ;AAAA,QACR;AAAA,QACA,QAAQ,UAAU;AAAA,QAClB,aAAY;AAAA,QACZ,UAAU,CAAC;AAAA;AAAA,IACb;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,MAAK;AAAA,QACL,QAAQ,CAAC,EAAE,MAAM,MACf,qBAAC,YACC;AAAA,+BAAC,aAAU;AAAA;AAAA,YACJ,oBAAC,UAAK,WAAU,oBAAmB,eAAC;AAAA,aAC3C;AAAA,UACA,oBAAC,eACC;AAAA,YAAC;AAAA;AAAA,cACC,aAAY;AAAA,cACZ,UAAU,CAAC;AAAA,cACV,GAAG;AAAA;AAAA,UACN,GACF;AAAA,UACA,oBAAC,eAAY;AAAA,WACf;AAAA;AAAA,IAEJ;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,OAAM;AAAA,QACN;AAAA,QACA,QAAQ,UAAU;AAAA,QAClB,aAAY;AAAA,QACZ,MAAM;AAAA,QACN,UAAU,CAAC;AAAA;AAAA,IACb;AAAA,KACF,GACF,GAEJ;AAEJ;AAEA,SAAS,qBAAqB;AAC5B,SACE,qBAAC,SAAI,WAAU,aACb;AAAA,yBAAC,SAAI,WAAU,aACb;AAAA,0BAAC,YAAS,WAAU,YAAW;AAAA,MAC/B,oBAAC,YAAS,WAAU,eAAc;AAAA,OACpC;AAAA,IACA,qBAAC,SAAI,WAAU,aACb;AAAA,0BAAC,YAAS,WAAU,YAAW;AAAA,MAC/B,oBAAC,YAAS,WAAU,eAAc;AAAA,OACpC;AAAA,IACA,qBAAC,SAAI,WAAU,aACb;AAAA,0BAAC,YAAS,WAAU,YAAW;AAAA,MAC/B,oBAAC,YAAS,WAAU,eAAc;AAAA,OACpC;AAAA,KACF;AAEJ;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/pages/iam/tenants/tenant-detail-page-content.tsx"],"sourcesContent":["'use client';\n\nimport {\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n EntityDetailHeader,\n PageContainer,\n type TabItem,\n useBreadcrumbs,\n} from '@mesob/ui/components';\nimport { IconBuilding } from '@tabler/icons-react';\nimport { useQueryClient } from '@tanstack/react-query';\nimport { useMemo } from 'react';\nimport { useApi, useConfig } from '../../../provider';\nimport { str } from './_components/tenants-data';\n\ntype TenantDetailPageContentProps = {\n tenantId: string;\n};\n\nexport function TenantDetailPageContent({\n tenantId,\n}: TenantDetailPageContentProps) {\n const { hooks } = useApi();\n const { config } = useConfig();\n const homeHref = config.navigation?.defaultRedirectUrl || '/';\n const qc = useQueryClient();\n\n const { data, isLoading } = hooks.useQuery(\n 'get',\n '/tenants/{id}',\n { params: { path: { id: tenantId } } },\n { enabled: !!tenantId },\n );\n const tenant = data?.tenant;\n\n const toggleActive = hooks.useMutation('put', '/tenants/{id}', {\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: ['get', '/tenants/{id}'] });\n qc.invalidateQueries({ queryKey: ['get', '/tenants'] });\n },\n });\n\n const title = tenant ? str(tenant.name) || tenant.id : (tenantId ?? 'Tenant');\n useBreadcrumbs({\n items: [\n { label: 'Home', href: homeHref },\n { label: 'IAM', href: '/iam' },\n { label: 'Tenants', href: '/iam/tenants' },\n { label: title },\n ],\n });\n\n const tabs: TabItem[] = useMemo(\n () => [\n {\n value: 'detail',\n name: 'Detail',\n content: (\n <Card className=\"mt-4\">\n <CardHeader>\n <CardTitle>Tenant details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2 text-sm\">\n {tenant && (\n <>\n <p>\n <span className=\"text-muted-foreground\">Name:</span>{' '}\n {str(tenant.name) || '—'}\n </p>\n <p>\n <span className=\"text-muted-foreground\">Description:</span>{' '}\n {str(tenant.description) || '—'}\n </p>\n <p>\n <span className=\"text-muted-foreground\">Language:</span>{' '}\n {tenant.defaultLanguage ?? '—'}\n </p>\n <p>\n <span className=\"text-muted-foreground\">Currency:</span>{' '}\n {tenant.defaultCurrency ?? '—'}\n </p>\n <p>\n <span className=\"text-muted-foreground\">Timezone:</span>{' '}\n {tenant.timezone ?? '—'}\n </p>\n </>\n )}\n </CardContent>\n </Card>\n ),\n },\n {\n value: 'theme',\n name: 'Theme',\n content: (\n <Card className=\"mt-4\">\n <CardHeader>\n <CardTitle>Theme</CardTitle>\n </CardHeader>\n <CardContent className=\"text-muted-foreground text-sm\">\n Theme settings (placeholder)\n </CardContent>\n </Card>\n ),\n },\n {\n value: 'settings',\n name: 'Settings',\n content: (\n <Card className=\"mt-4\">\n <CardHeader>\n <CardTitle>Settings</CardTitle>\n </CardHeader>\n <CardContent className=\"text-muted-foreground text-sm\">\n Tenant settings (placeholder)\n </CardContent>\n </Card>\n ),\n },\n ],\n [tenant],\n );\n\n const actions = tenant && (\n <Button\n variant={tenant.isActive ? 'secondary' : 'default'}\n size=\"sm\"\n onClick={() =>\n toggleActive.mutate({\n params: { path: { id: tenantId } },\n body: { isActive: !tenant.isActive },\n })\n }\n disabled={toggleActive.isPending}\n >\n {tenant.isActive ? 'Deactivate' : 'Activate'}\n </Button>\n );\n\n if (!tenantId) {\n return null;\n }\n if (isLoading || !tenant) {\n return (\n <div className=\"flex flex-1 flex-col gap-4 p-4 pt-0\">\n <div className=\"h-24 animate-pulse rounded-xl bg-muted\" />\n </div>\n );\n }\n\n return (\n <PageContainer className=\"flex flex-1 flex-col gap-4 p-4 pt-0\">\n <EntityDetailHeader\n title={title}\n icon={<IconBuilding className=\"h-5 w-5 text-muted-foreground\" />}\n actions={actions}\n tabs={tabs}\n />\n </PageContainer>\n );\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/pages/iam/users/_components/user-card.tsx","../src/pages/iam/users/_components/user-form.tsx"],"sourcesContent":["'use client';\n\nimport {\n Button,\n Card,\n CardContent,\n CardHeader,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuPortal,\n DropdownMenuTrigger,\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '@mesob/ui/components';\nimport { IconCircleCheck, IconDots, IconPencil } from '@tabler/icons-react';\nimport { useState } from 'react';\nimport { Link } from '../../shared/page-helpers';\nimport { UserForm } from './user-form';\nimport type { User } from './users-data';\n\ntype UserCardProps = { user: User };\n\nexport function UserCard({ user }: UserCardProps) {\n const [editOpen, setEditOpen] = useState(false);\n return (\n <>\n <Card className=\"group hover:shadow-md transition-shadow\">\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-start justify-between\">\n <Link\n href={`/iam/users/${user.id}`}\n className=\"text-left font-semibold hover:text-primary hover:underline\"\n >\n {user.fullName}\n </Link>\n <DropdownMenu>\n <DropdownMenuTrigger\n render={\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 opacity-0 group-hover:opacity-100 transition-opacity\"\n />\n }\n >\n <IconDots className=\"h-4 w-4\" />\n </DropdownMenuTrigger>\n <DropdownMenuPortal>\n <DropdownMenuContent>\n <DropdownMenuItem onClick={() => setEditOpen(true)}>\n <IconPencil className=\"mr-2 h-4 w-4\" />\n Edit\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenuPortal>\n </DropdownMenu>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n {user.email && (\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm\">{user.email}</span>\n {user.emailVerified && (\n <Tooltip>\n <TooltipTrigger>\n <IconCircleCheck className=\"size-4 text-muted-foreground\" />\n </TooltipTrigger>\n <TooltipContent>Email verified</TooltipContent>\n </Tooltip>\n )}\n </div>\n )}\n <p className=\"text-xs text-muted-foreground\">\n Last sign in{' '}\n {user.lastSignInAt\n ? new Date(user.lastSignInAt).toLocaleDateString()\n : 'never'}\n </p>\n </CardContent>\n </Card>\n {editOpen && (\n <UserForm\n mode=\"edit\"\n userId={user.id}\n open={editOpen}\n onClose={() => setEditOpen(false)}\n />\n )}\n </>\n );\n}\n","'use client';\n\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport {\n Checkbox,\n EntityDrawer,\n EntityFormActions,\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n Input,\n Skeleton,\n Stack,\n} from '@mesob/ui/components';\nimport { useQueryClient } from '@tanstack/react-query';\nimport { useEffect } from 'react';\nimport { useForm, useWatch } from 'react-hook-form';\nimport { z } from 'zod';\nimport type { Role } from '../../roles/_components/roles-data';\nimport { str } from '../../roles/_components/roles-data';\nimport { authApi$ } from '../../shared/page-helpers';\n\nconst schema = z.object({\n fullName: z.string().trim().min(1, 'Full name is required'),\n email: z.string().email('Invalid email').nullable().or(z.literal('')),\n phone: z.string().nullable(),\n emailVerified: z.boolean(),\n phoneVerified: z.boolean(),\n roleIds: z.array(z.string().uuid()),\n});\n\ntype FormData = z.infer<typeof schema>;\n\nconst defaults: FormData = {\n fullName: '',\n email: '',\n phone: null,\n emailVerified: false,\n phoneVerified: false,\n roleIds: [],\n};\n\ntype UserFormProps = {\n mode: 'new' | 'edit';\n userId?: string;\n open: boolean;\n onClose: () => void;\n onSuccess?: () => void;\n};\n\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: form + roles section\nexport function UserForm({\n mode,\n userId,\n open,\n onClose,\n onSuccess,\n}: UserFormProps) {\n const qc = useQueryClient();\n const { data: userData, isLoading: userLoading } = authApi$.useQuery(\n 'get',\n '/users/{id}',\n { params: { path: { id: userId ?? '' } } },\n { enabled: mode === 'edit' && !!userId && open },\n );\n const { data: rolesData } = authApi$.useQuery(\n 'get',\n '/roles',\n { params: { query: { limit: 100 } } },\n { enabled: open },\n );\n const allRoles = rolesData?.roles ?? [];\n const roles = allRoles\n .filter((r: Role) => (r.code ?? '').toLowerCase() !== 'owner')\n .sort((a: Role, b: Role) =>\n (str(a.name) || a.code)\n .toLowerCase()\n .localeCompare((str(b.name) || b.code).toLowerCase()),\n );\n const user = userData?.user;\n\n const form = useForm<FormData>({\n resolver: zodResolver(schema),\n defaultValues: defaults,\n });\n const { control, formState, reset, setValue } = form;\n const email = useWatch({ control, name: 'email' }) ?? '';\n const phone = useWatch({ control, name: 'phone' }) ?? '';\n const roleIds = useWatch({ control, name: 'roleIds' }) ?? [];\n const hasEmail = (email ?? '').toString().trim().length > 0;\n const hasPhone = (phone ?? '').toString().trim().length > 0;\n\n useEffect(() => {\n if (!hasEmail) {\n setValue('emailVerified', false, { shouldDirty: false });\n }\n if (!hasPhone) {\n setValue('phoneVerified', false, { shouldDirty: false });\n }\n }, [hasEmail, hasPhone, setValue]);\n\n useEffect(() => {\n if (!open) {\n return;\n }\n if (mode === 'edit' && user && !userLoading) {\n reset({\n fullName: user.fullName,\n email: user.email ?? '',\n phone: user.phone ?? null,\n emailVerified: user.emailVerified ?? false,\n phoneVerified: user.phoneVerified ?? false,\n roleIds: user.roles ?? [],\n });\n } else {\n reset(defaults);\n }\n }, [mode, user, open, userLoading, reset]);\n\n const create = authApi$.useMutation('post', '/users', {\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: ['get', '/users'] });\n },\n });\n const update = authApi$.useMutation('put', '/users/{id}', {\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: ['get', '/users'] });\n if (userId) {\n qc.invalidateQueries({ queryKey: ['get', '/users/{id}'] });\n }\n },\n });\n const del = authApi$.useMutation('delete', '/users/{id}', {\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: ['get', '/users'] });\n },\n });\n\n const onSubmit = form.handleSubmit(async (d) => {\n const base = {\n fullName: d.fullName,\n email: d.email?.trim() || undefined,\n phone: d.phone?.trim() || undefined,\n emailVerified: d.emailVerified,\n phoneVerified: d.phoneVerified,\n };\n if (mode === 'new') {\n await create.mutateAsync({\n body: {\n ...base,\n email: base.email || undefined,\n phone: base.phone || undefined,\n },\n });\n } else if (userId) {\n await update.mutateAsync({\n params: { path: { id: userId } },\n body: {\n ...base,\n email: base.email ?? null,\n phone: base.phone ?? null,\n roleIds: d.roleIds,\n },\n });\n }\n onSuccess?.();\n onClose();\n });\n\n const onDelete = async () => {\n if (!userId) {\n return;\n }\n await del.mutateAsync({ params: { path: { id: userId } } });\n onSuccess?.();\n onClose();\n };\n\n const toggleRole = (roleId: string, checked: boolean) => {\n const next = checked\n ? [...roleIds, roleId]\n : roleIds.filter((id) => id !== roleId);\n setValue('roleIds', next, { shouldDirty: true });\n };\n\n const isSubmitting = create.isPending || update.isPending;\n\n return (\n <EntityDrawer\n title={mode === 'new' ? 'New user' : 'Edit user'}\n open={open}\n onClose={onClose}\n isDirty={formState.isDirty}\n size=\"lg\"\n form={\n userLoading && mode === 'edit' ? (\n <FormSkeleton />\n ) : (\n <Form {...form}>\n <form onSubmit={onSubmit} className=\"space-y-6\">\n <Stack>\n <FormField\n control={control}\n name=\"fullName\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>\n Full name <span className=\"text-destructive\">*</span>\n </FormLabel>\n <FormControl>\n <Input placeholder=\"Full name\" {...field} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n <FormField\n control={control}\n name=\"email\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>Email</FormLabel>\n <FormControl>\n <Input\n type=\"email\"\n placeholder=\"user@example.com\"\n {...field}\n value={field.value ?? ''}\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n <FormField\n control={control}\n name=\"phone\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>Phone</FormLabel>\n <FormControl>\n <Input\n placeholder=\"+251911223344\"\n {...field}\n value={field.value ?? ''}\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n <div className=\"space-y-4\">\n <FormLabel>Verification</FormLabel>\n <div className=\"flex flex-wrap gap-6 pt-1\">\n <FormField\n control={control}\n name=\"emailVerified\"\n render={({ field }) => (\n <FormItem className=\"flex flex-row items-center gap-2 space-y-0\">\n <FormControl>\n <Checkbox\n size=\"lg\"\n checked={field.value}\n disabled={!hasEmail}\n onCheckedChange={(c) =>\n field.onChange(c === true)\n }\n />\n </FormControl>\n <FormLabel className=\"cursor-pointer font-normal\">\n Email verified\n </FormLabel>\n <FormMessage />\n </FormItem>\n )}\n />\n <FormField\n control={control}\n name=\"phoneVerified\"\n render={({ field }) => (\n <FormItem className=\"flex flex-row items-center gap-2 space-y-0\">\n <FormControl>\n <Checkbox\n size=\"lg\"\n checked={field.value}\n disabled={!hasPhone}\n onCheckedChange={(c) =>\n field.onChange(c === true)\n }\n />\n </FormControl>\n <FormLabel className=\"cursor-pointer font-normal\">\n Phone verified\n </FormLabel>\n <FormMessage />\n </FormItem>\n )}\n />\n </div>\n </div>\n </Stack>\n\n {mode === 'edit' && roles.length > 0 && (\n <div className=\"space-y-4\">\n <FormLabel>Roles</FormLabel>\n <div className=\"flex flex-col gap-3 pt-1\">\n {roles.map((role: Role) => {\n const desc = str(role.description);\n return (\n <div key={role.id} className=\"flex items-start gap-3\">\n <Checkbox\n size=\"lg\"\n id={`role-${role.id}`}\n checked={roleIds.includes(role.id)}\n onCheckedChange={(c) =>\n toggleRole(role.id, c === true)\n }\n className=\"mt-0.5\"\n />\n <label\n htmlFor={`role-${role.id}`}\n className=\"flex min-w-0 flex-1 cursor-pointer flex-col gap-0.5\"\n >\n <span className=\"text-sm font-medium\">\n {str(role.name) || role.code}\n </span>\n {desc ? (\n <span className=\"text-xs text-muted-foreground\">\n {desc}\n </span>\n ) : null}\n </label>\n </div>\n );\n })}\n </div>\n </div>\n )}\n </form>\n </Form>\n )\n }\n actions={\n <EntityFormActions\n mode={mode}\n onSubmit={onSubmit}\n onReset={mode === 'new' ? () => reset(defaults) : undefined}\n onDelete={mode === 'edit' ? onDelete : undefined}\n isSubmitting={isSubmitting}\n isDeleting={del.isPending}\n disabled={userLoading && mode === 'edit'}\n itemName=\"user\"\n />\n }\n />\n );\n}\n\nfunction FormSkeleton() {\n return (\n <div className=\"space-y-4\">\n {[1, 2, 3, 4, 5].map((i) => (\n <div key={i} className=\"space-y-2\">\n <Skeleton className=\"h-4 w-20\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n ))}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AAEA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,iBAAiB,UAAU,kBAAkB;AACtD,SAAS,gBAAgB;;;ACfzB,SAAS,mBAAmB;AAC5B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,sBAAsB;AAC/B,SAAS,iBAAiB;AAC1B,SAAS,SAAS,gBAAgB;AAClC,SAAS,SAAS;AAmLR,cAUY,YAVZ;AA9KV,IAAM,SAAS,EAAE,OAAO;AAAA,EACtB,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,GAAG,uBAAuB;AAAA,EAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,EAAE,SAAS,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC;AAAA,EACpE,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,eAAe,EAAE,QAAQ;AAAA,EACzB,eAAe,EAAE,QAAQ;AAAA,EACzB,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC;AACpC,CAAC;AAID,IAAM,WAAqB;AAAA,EACzB,UAAU;AAAA,EACV,OAAO;AAAA,EACP,OAAO;AAAA,EACP,eAAe;AAAA,EACf,eAAe;AAAA,EACf,SAAS,CAAC;AACZ;AAWO,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAkB;AAChB,QAAM,KAAK,eAAe;AAC1B,QAAM,EAAE,MAAM,UAAU,WAAW,YAAY,IAAI,SAAS;AAAA,IAC1D;AAAA,IACA;AAAA,IACA,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,UAAU,GAAG,EAAE,EAAE;AAAA,IACzC,EAAE,SAAS,SAAS,UAAU,CAAC,CAAC,UAAU,KAAK;AAAA,EACjD;AACA,QAAM,EAAE,MAAM,UAAU,IAAI,SAAS;AAAA,IACnC;AAAA,IACA;AAAA,IACA,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,IAAI,EAAE,EAAE;AAAA,IACpC,EAAE,SAAS,KAAK;AAAA,EAClB;AACA,QAAM,WAAW,WAAW,SAAS,CAAC;AACtC,QAAM,QAAQ,SACX,OAAO,CAAC,OAAa,EAAE,QAAQ,IAAI,YAAY,MAAM,OAAO,EAC5D;AAAA,IAAK,CAAC,GAAS,OACb,IAAI,EAAE,IAAI,KAAK,EAAE,MACf,YAAY,EACZ,eAAe,IAAI,EAAE,IAAI,KAAK,EAAE,MAAM,YAAY,CAAC;AAAA,EACxD;AACF,QAAM,OAAO,UAAU;AAEvB,QAAM,OAAO,QAAkB;AAAA,IAC7B,UAAU,YAAY,MAAM;AAAA,IAC5B,eAAe;AAAA,EACjB,CAAC;AACD,QAAM,EAAE,SAAS,WAAW,OAAO,SAAS,IAAI;AAChD,QAAM,QAAQ,SAAS,EAAE,SAAS,MAAM,QAAQ,CAAC,KAAK;AACtD,QAAM,QAAQ,SAAS,EAAE,SAAS,MAAM,QAAQ,CAAC,KAAK;AACtD,QAAM,UAAU,SAAS,EAAE,SAAS,MAAM,UAAU,CAAC,KAAK,CAAC;AAC3D,QAAM,YAAY,SAAS,IAAI,SAAS,EAAE,KAAK,EAAE,SAAS;AAC1D,QAAM,YAAY,SAAS,IAAI,SAAS,EAAE,KAAK,EAAE,SAAS;AAE1D,YAAU,MAAM;AACd,QAAI,CAAC,UAAU;AACb,eAAS,iBAAiB,OAAO,EAAE,aAAa,MAAM,CAAC;AAAA,IACzD;AACA,QAAI,CAAC,UAAU;AACb,eAAS,iBAAiB,OAAO,EAAE,aAAa,MAAM,CAAC;AAAA,IACzD;AAAA,EACF,GAAG,CAAC,UAAU,UAAU,QAAQ,CAAC;AAEjC,YAAU,MAAM;AACd,QAAI,CAAC,MAAM;AACT;AAAA,IACF;AACA,QAAI,SAAS,UAAU,QAAQ,CAAC,aAAa;AAC3C,YAAM;AAAA,QACJ,UAAU,KAAK;AAAA,QACf,OAAO,KAAK,SAAS;AAAA,QACrB,OAAO,KAAK,SAAS;AAAA,QACrB,eAAe,KAAK,iBAAiB;AAAA,QACrC,eAAe,KAAK,iBAAiB;AAAA,QACrC,SAAS,KAAK,SAAS,CAAC;AAAA,MAC1B,CAAC;AAAA,IACH,OAAO;AACL,YAAM,QAAQ;AAAA,IAChB;AAAA,EACF,GAAG,CAAC,MAAM,MAAM,MAAM,aAAa,KAAK,CAAC;AAEzC,QAAM,SAAS,SAAS,YAAY,QAAQ,UAAU;AAAA,IACpD,WAAW,MAAM;AACf,SAAG,kBAAkB,EAAE,UAAU,CAAC,OAAO,QAAQ,EAAE,CAAC;AAAA,IACtD;AAAA,EACF,CAAC;AACD,QAAM,SAAS,SAAS,YAAY,OAAO,eAAe;AAAA,IACxD,WAAW,MAAM;AACf,SAAG,kBAAkB,EAAE,UAAU,CAAC,OAAO,QAAQ,EAAE,CAAC;AACpD,UAAI,QAAQ;AACV,WAAG,kBAAkB,EAAE,UAAU,CAAC,OAAO,aAAa,EAAE,CAAC;AAAA,MAC3D;AAAA,IACF;AAAA,EACF,CAAC;AACD,QAAM,MAAM,SAAS,YAAY,UAAU,eAAe;AAAA,IACxD,WAAW,MAAM;AACf,SAAG,kBAAkB,EAAE,UAAU,CAAC,OAAO,QAAQ,EAAE,CAAC;AAAA,IACtD;AAAA,EACF,CAAC;AAED,QAAM,WAAW,KAAK,aAAa,OAAO,MAAM;AAC9C,UAAM,OAAO;AAAA,MACX,UAAU,EAAE;AAAA,MACZ,OAAO,EAAE,OAAO,KAAK,KAAK;AAAA,MAC1B,OAAO,EAAE,OAAO,KAAK,KAAK;AAAA,MAC1B,eAAe,EAAE;AAAA,MACjB,eAAe,EAAE;AAAA,IACnB;AACA,QAAI,SAAS,OAAO;AAClB,YAAM,OAAO,YAAY;AAAA,QACvB,MAAM;AAAA,UACJ,GAAG;AAAA,UACH,OAAO,KAAK,SAAS;AAAA,UACrB,OAAO,KAAK,SAAS;AAAA,QACvB;AAAA,MACF,CAAC;AAAA,IACH,WAAW,QAAQ;AACjB,YAAM,OAAO,YAAY;AAAA,QACvB,QAAQ,EAAE,MAAM,EAAE,IAAI,OAAO,EAAE;AAAA,QAC/B,MAAM;AAAA,UACJ,GAAG;AAAA,UACH,OAAO,KAAK,SAAS;AAAA,UACrB,OAAO,KAAK,SAAS;AAAA,UACrB,SAAS,EAAE;AAAA,QACb;AAAA,MACF,CAAC;AAAA,IACH;AACA,gBAAY;AACZ,YAAQ;AAAA,EACV,CAAC;AAED,QAAM,WAAW,YAAY;AAC3B,QAAI,CAAC,QAAQ;AACX;AAAA,IACF;AACA,UAAM,IAAI,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,OAAO,EAAE,EAAE,CAAC;AAC1D,gBAAY;AACZ,YAAQ;AAAA,EACV;AAEA,QAAM,aAAa,CAAC,QAAgB,YAAqB;AACvD,UAAM,OAAO,UACT,CAAC,GAAG,SAAS,MAAM,IACnB,QAAQ,OAAO,CAAC,OAAO,OAAO,MAAM;AACxC,aAAS,WAAW,MAAM,EAAE,aAAa,KAAK,CAAC;AAAA,EACjD;AAEA,QAAM,eAAe,OAAO,aAAa,OAAO;AAEhD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,SAAS,QAAQ,aAAa;AAAA,MACrC;AAAA,MACA;AAAA,MACA,SAAS,UAAU;AAAA,MACnB,MAAK;AAAA,MACL,MACE,eAAe,SAAS,SACtB,oBAAC,gBAAa,IAEd,oBAAC,QAAM,GAAG,MACR,+BAAC,UAAK,UAAoB,WAAU,aAClC;AAAA,6BAAC,SACC;AAAA;AAAA,YAAC;AAAA;AAAA,cACC;AAAA,cACA,MAAK;AAAA,cACL,QAAQ,CAAC,EAAE,MAAM,MACf,qBAAC,YACC;AAAA,qCAAC,aAAU;AAAA;AAAA,kBACC,oBAAC,UAAK,WAAU,oBAAmB,eAAC;AAAA,mBAChD;AAAA,gBACA,oBAAC,eACC,8BAAC,SAAM,aAAY,aAAa,GAAG,OAAO,GAC5C;AAAA,gBACA,oBAAC,eAAY;AAAA,iBACf;AAAA;AAAA,UAEJ;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC;AAAA,cACA,MAAK;AAAA,cACL,QAAQ,CAAC,EAAE,MAAM,MACf,qBAAC,YACC;AAAA,oCAAC,aAAU,mBAAK;AAAA,gBAChB,oBAAC,eACC;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,aAAY;AAAA,oBACX,GAAG;AAAA,oBACJ,OAAO,MAAM,SAAS;AAAA;AAAA,gBACxB,GACF;AAAA,gBACA,oBAAC,eAAY;AAAA,iBACf;AAAA;AAAA,UAEJ;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC;AAAA,cACA,MAAK;AAAA,cACL,QAAQ,CAAC,EAAE,MAAM,MACf,qBAAC,YACC;AAAA,oCAAC,aAAU,mBAAK;AAAA,gBAChB,oBAAC,eACC;AAAA,kBAAC;AAAA;AAAA,oBACC,aAAY;AAAA,oBACX,GAAG;AAAA,oBACJ,OAAO,MAAM,SAAS;AAAA;AAAA,gBACxB,GACF;AAAA,gBACA,oBAAC,eAAY;AAAA,iBACf;AAAA;AAAA,UAEJ;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,aAAU,0BAAY;AAAA,YACvB,qBAAC,SAAI,WAAU,6BACb;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC;AAAA,kBACA,MAAK;AAAA,kBACL,QAAQ,CAAC,EAAE,MAAM,MACf,qBAAC,YAAS,WAAU,8CAClB;AAAA,wCAAC,eACC;AAAA,sBAAC;AAAA;AAAA,wBACC,MAAK;AAAA,wBACL,SAAS,MAAM;AAAA,wBACf,UAAU,CAAC;AAAA,wBACX,iBAAiB,CAAC,MAChB,MAAM,SAAS,MAAM,IAAI;AAAA;AAAA,oBAE7B,GACF;AAAA,oBACA,oBAAC,aAAU,WAAU,8BAA6B,4BAElD;AAAA,oBACA,oBAAC,eAAY;AAAA,qBACf;AAAA;AAAA,cAEJ;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC;AAAA,kBACA,MAAK;AAAA,kBACL,QAAQ,CAAC,EAAE,MAAM,MACf,qBAAC,YAAS,WAAU,8CAClB;AAAA,wCAAC,eACC;AAAA,sBAAC;AAAA;AAAA,wBACC,MAAK;AAAA,wBACL,SAAS,MAAM;AAAA,wBACf,UAAU,CAAC;AAAA,wBACX,iBAAiB,CAAC,MAChB,MAAM,SAAS,MAAM,IAAI;AAAA;AAAA,oBAE7B,GACF;AAAA,oBACA,oBAAC,aAAU,WAAU,8BAA6B,4BAElD;AAAA,oBACA,oBAAC,eAAY;AAAA,qBACf;AAAA;AAAA,cAEJ;AAAA,eACF;AAAA,aACF;AAAA,WACF;AAAA,QAEC,SAAS,UAAU,MAAM,SAAS,KACjC,qBAAC,SAAI,WAAU,aACb;AAAA,8BAAC,aAAU,mBAAK;AAAA,UAChB,oBAAC,SAAI,WAAU,4BACZ,gBAAM,IAAI,CAAC,SAAe;AACzB,kBAAM,OAAO,IAAI,KAAK,WAAW;AACjC,mBACE,qBAAC,SAAkB,WAAU,0BAC3B;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,IAAI,QAAQ,KAAK,EAAE;AAAA,kBACnB,SAAS,QAAQ,SAAS,KAAK,EAAE;AAAA,kBACjC,iBAAiB,CAAC,MAChB,WAAW,KAAK,IAAI,MAAM,IAAI;AAAA,kBAEhC,WAAU;AAAA;AAAA,cACZ;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,SAAS,QAAQ,KAAK,EAAE;AAAA,kBACxB,WAAU;AAAA,kBAEV;AAAA,wCAAC,UAAK,WAAU,uBACb,cAAI,KAAK,IAAI,KAAK,KAAK,MAC1B;AAAA,oBACC,OACC,oBAAC,UAAK,WAAU,iCACb,gBACH,IACE;AAAA;AAAA;AAAA,cACN;AAAA,iBAtBQ,KAAK,EAuBf;AAAA,UAEJ,CAAC,GACH;AAAA,WACF;AAAA,SAEJ,GACF;AAAA,MAGJ,SACE;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA,SAAS,SAAS,QAAQ,MAAM,MAAM,QAAQ,IAAI;AAAA,UAClD,UAAU,SAAS,SAAS,WAAW;AAAA,UACvC;AAAA,UACA,YAAY,IAAI;AAAA,UAChB,UAAU,eAAe,SAAS;AAAA,UAClC,UAAS;AAAA;AAAA,MACX;AAAA;AAAA,EAEJ;AAEJ;AAEA,SAAS,eAAe;AACtB,SACE,oBAAC,SAAI,WAAU,aACZ,WAAC,GAAG,GAAG,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACpB,qBAAC,SAAY,WAAU,aACrB;AAAA,wBAAC,YAAS,WAAU,YAAW;AAAA,IAC/B,oBAAC,YAAS,WAAU,eAAc;AAAA,OAF1B,CAGV,CACD,GACH;AAEJ;;;ADzVI,mBAIQ,OAAAA,MAoBM,QAAAC,aAxBd;AAHG,SAAS,SAAS,EAAE,KAAK,GAAkB;AAChD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAC9C,SACE,gBAAAA,MAAA,YACE;AAAA,oBAAAA,MAAC,QAAK,WAAU,2CACd;AAAA,sBAAAD,KAAC,cAAW,WAAU,QACpB,0BAAAC,MAAC,SAAI,WAAU,oCACb;AAAA,wBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,MAAM,cAAc,KAAK,EAAE;AAAA,YAC3B,WAAU;AAAA,YAET,eAAK;AAAA;AAAA,QACR;AAAA,QACA,gBAAAC,MAAC,gBACC;AAAA,0BAAAD;AAAA,YAAC;AAAA;AAAA,cACC,QACE,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,SAAQ;AAAA,kBACR,MAAK;AAAA,kBACL,WAAU;AAAA;AAAA,cACZ;AAAA,cAGF,0BAAAA,KAAC,YAAS,WAAU,WAAU;AAAA;AAAA,UAChC;AAAA,UACA,gBAAAA,KAAC,sBACC,0BAAAA,KAAC,uBACC,0BAAAC,MAAC,oBAAiB,SAAS,MAAM,YAAY,IAAI,GAC/C;AAAA,4BAAAD,KAAC,cAAW,WAAU,gBAAe;AAAA,YAAE;AAAA,aAEzC,GACF,GACF;AAAA,WACF;AAAA,SACF,GACF;AAAA,MACA,gBAAAC,MAAC,eAAY,WAAU,aACpB;AAAA,aAAK,SACJ,gBAAAA,MAAC,SAAI,WAAU,2BACb;AAAA,0BAAAD,KAAC,UAAK,WAAU,WAAW,eAAK,OAAM;AAAA,UACrC,KAAK,iBACJ,gBAAAC,MAAC,WACC;AAAA,4BAAAD,KAAC,kBACC,0BAAAA,KAAC,mBAAgB,WAAU,gCAA+B,GAC5D;AAAA,YACA,gBAAAA,KAAC,kBAAe,4BAAc;AAAA,aAChC;AAAA,WAEJ;AAAA,QAEF,gBAAAC,MAAC,OAAE,WAAU,iCAAgC;AAAA;AAAA,UAC9B;AAAA,UACZ,KAAK,eACF,IAAI,KAAK,KAAK,YAAY,EAAE,mBAAmB,IAC/C;AAAA,WACN;AAAA,SACF;AAAA,OACF;AAAA,IACC,YACC,gBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,MAAM;AAAA,QACN,SAAS,MAAM,YAAY,KAAK;AAAA;AAAA,IAClC;AAAA,KAEJ;AAEJ;","names":["jsx","jsxs"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/auth/sign-up.tsx"],"sourcesContent":["'use client';\n\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport {\n Alert,\n AlertDescription,\n AlertTitle,\n Button,\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n Input,\n useFormField,\n} from '@mesob/ui/components';\nimport { useMesob } from '@mesob/ui/providers';\nimport { IconAlertCircle, IconEye, IconEyeOff } from '@tabler/icons-react';\nimport type { ChangeEvent, ComponentProps } from 'react';\nimport { useEffect, useState } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { toast } from 'sonner';\nimport { z } from 'zod';\nimport { useTranslator } from '../../hooks/use-translator';\nimport { useApi, useConfig } from '../../provider';\nimport type { AuthErrorContent } from '../../utils/handle-error';\nimport { handleError } from '../../utils/handle-error';\nimport { AuthLayout } from './auth-layout';\n\nconst isPhone = (s: string) => /^\\+?[0-9()[\\]\\s-]{6,}$/.test(s);\n\ntype PasswordInputProps = {\n field: ComponentProps<'input'> & {\n value: string;\n onChange: (e: ChangeEvent<HTMLInputElement>) => void;\n onBlur: () => void;\n };\n show: boolean;\n onToggle: () => void;\n};\n\nfunction PasswordInput({ field, show, onToggle }: PasswordInputProps) {\n const { formItemId, error } = useFormField();\n return (\n <div className=\"relative\">\n <Input\n {...field}\n id={formItemId}\n type={show ? 'text' : 'password'}\n aria-invalid={!!error}\n className=\"pr-10\"\n />\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"absolute right-0 top-0 h-full px-3 text-muted-foreground hover:text-foreground\"\n onClick={onToggle}\n aria-label={show ? 'Hide password' : 'Show password'}\n >\n {show ? (\n <IconEyeOff className=\"h-4 w-4\" />\n ) : (\n <IconEye className=\"h-4 w-4\" />\n )}\n </Button>\n </div>\n );\n}\n\ntype SignUpFormValues = {\n fullName: string;\n identifier: string;\n password: string;\n confirmPassword: string;\n};\n\ntype SignUpProps = {\n redirectUrl?: string;\n initialIdentifier?: string;\n};\n\nconst signUpSchema = (t: (key: string) => string) =>\n z\n .object({\n fullName: z.string().min(1, t('errors.fullNameRequired')),\n identifier: z\n .string()\n .min(1, t('errors.contactRequired'))\n .refine(\n (val) => {\n if (!val) {\n return false;\n }\n return val.includes('@') || isPhone(val);\n },\n {\n message: t('errors.invalidEmailOrPhone'),\n },\n ),\n password: z\n .string()\n .min(8, t('errors.passwordLength'))\n .max(128, t('errors.longPasswordError')),\n confirmPassword: z.string(),\n })\n .refine((data) => data.password === data.confirmPassword, {\n message: t('errors.passwordsMismatch'),\n path: ['confirmPassword'],\n });\n\nexport const SignUp = ({\n redirectUrl,\n initialIdentifier,\n}: SignUpProps = {}) => {\n const { hooks, setAuth } = useApi();\n const { config } = useConfig();\n const mesob = useMesob();\n const t = useTranslator('Auth.signUp');\n const Link = mesob?.navigation?.Link;\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<AuthErrorContent | null>(null);\n const [showPassword, setShowPassword] = useState(false);\n const [showConfirmPassword, setShowConfirmPassword] = useState(false);\n\n const signUpMutation = hooks.useMutation('post', '/sign-up');\n\n const signInLink = config.navigation?.links?.signIn || '/auth/sign-in';\n const onNavigate =\n config.navigation?.onNavigate ||\n ((path: string) => {\n if (typeof window !== 'undefined') {\n window.location.href = path;\n }\n });\n const logoImage = config.ui.logoImage;\n const defaultRedirect =\n redirectUrl || config.navigation?.defaultRedirectUrl || '/';\n\n const hasInitialIdentifier = !!initialIdentifier;\n\n const form = useForm<SignUpFormValues>({\n resolver: zodResolver(signUpSchema(t)),\n defaultValues: {\n fullName: '',\n identifier: initialIdentifier || '',\n password: '',\n confirmPassword: '',\n },\n });\n\n useEffect(() => {\n if (initialIdentifier) {\n form.setValue('identifier', initialIdentifier);\n }\n }, [initialIdentifier, form]);\n\n useEffect(() => {\n if (error) {\n toast.error(error.title || 'Error', {\n description: error.description,\n });\n }\n }, [error]);\n\n const handleSubmit = form.handleSubmit(async (values) => {\n setIsLoading(true);\n setError(null);\n\n try {\n const identifier = values.identifier;\n const usingPhone = isPhone(identifier);\n\n const res = await signUpMutation.mutateAsync({\n body: usingPhone\n ? {\n phone: identifier,\n password: values.password,\n fullName: values.fullName,\n }\n : {\n email: identifier,\n password: values.password,\n fullName: values.fullName,\n },\n });\n\n if ('verificationId' in res && res.verificationId) {\n const redirectParam = defaultRedirect\n ? `&redirect=${encodeURIComponent(defaultRedirect)}`\n : '';\n if (usingPhone) {\n onNavigate(\n `/auth/verify-phone?context=sign-up&verificationId=${res.verificationId}&phone=${encodeURIComponent(identifier)}${redirectParam}`,\n );\n } else {\n onNavigate(\n `/auth/verify-email?verificationId=${res.verificationId}&email=${encodeURIComponent(identifier)}${redirectParam}`,\n );\n }\n return;\n }\n\n if ('user' in res && 'session' in res) {\n setAuth(res);\n }\n onNavigate(defaultRedirect);\n } catch (err) {\n handleError(err, setError, t);\n } finally {\n setIsLoading(false);\n }\n });\n\n const getIdentifierLabel = () => {\n if (!hasInitialIdentifier) {\n return t('form.accountLabel') || 'Email/Phone';\n }\n if (initialIdentifier?.includes('@')) {\n return t('form.emailLabel');\n }\n return t('form.phoneLabel');\n };\n const identifierLabel = getIdentifierLabel();\n\n let errorContent: AuthErrorContent | null = null;\n if (error) {\n if (typeof error === 'string') {\n errorContent = { title: 'Error', description: error };\n } else {\n errorContent = error;\n }\n }\n\n return (\n <AuthLayout\n title={config.ui.name}\n description={t('description')}\n logoImage={logoImage}\n footer={\n <p>\n {t('footer.hasAccount')}{' '}\n {Link ? (\n <Link href={signInLink} className=\"text-primary hover:underline\">\n {t('footer.signInCta')}\n </Link>\n ) : (\n <a\n href={signInLink}\n onClick={(e) => {\n e.preventDefault();\n onNavigate(signInLink);\n }}\n className=\"text-primary hover:underline\"\n >\n {t('footer.signInCta')}\n </a>\n )}\n </p>\n }\n >\n <Form {...form}>\n <form id=\"sign-up-form\" onSubmit={handleSubmit} className=\"space-y-4\">\n <FormField\n control={form.control}\n name=\"fullName\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>{t('form.fullNameLabel')}</FormLabel>\n <FormControl>\n <Input {...field} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n <FormField\n control={form.control}\n name=\"identifier\"\n render={({ field }) => (\n <FormItem>\n <FormLabel\n className={hasInitialIdentifier ? 'block' : undefined}\n >\n {identifierLabel}\n </FormLabel>\n <FormControl>\n <Input\n {...field}\n type={field.value.includes('@') ? 'email' : 'tel'}\n disabled={hasInitialIdentifier}\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n <FormField\n control={form.control}\n name=\"password\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>{t('form.passwordLabel')}</FormLabel>\n <PasswordInput\n field={field}\n show={showPassword}\n onToggle={() => setShowPassword(!showPassword)}\n />\n <FormMessage />\n </FormItem>\n )}\n />\n <FormField\n control={form.control}\n name=\"confirmPassword\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>{t('form.confirmPasswordLabel')}</FormLabel>\n <PasswordInput\n field={field}\n show={showConfirmPassword}\n onToggle={() => setShowConfirmPassword(!showConfirmPassword)}\n />\n <FormMessage />\n </FormItem>\n )}\n />\n <Button\n type=\"submit\"\n form=\"sign-up-form\"\n className=\"w-full\"\n disabled={isLoading || signUpMutation.isPending}\n >\n {isLoading || signUpMutation.isPending\n ? t('form.submitting')\n : t('form.submit')}\n </Button>\n </form>\n </Form>\n {errorContent && (\n <Alert variant=\"destructive\" className=\"mt-4\">\n <IconAlertCircle className=\"h-4 w-4\" />\n <AlertTitle>{errorContent.title}</AlertTitle>\n <AlertDescription>{errorContent.description}</AlertDescription>\n </Alert>\n )}\n </AuthLayout>\n );\n};\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/iam/role-permissions-page.tsx"],"sourcesContent":["'use client';\n\nimport {\n Badge,\n Button,\n DataTablePagination,\n DeleteConfirmButton,\n DisplayTable,\n EntityEmptyState,\n EntityFilter,\n EntityHeader,\n EntityLoadingState,\n EntitySearch,\n EntitySort,\n EntityViewToggle,\n PageBody,\n Tbody,\n Td,\n Th,\n Thead,\n Tr,\n useEntityPagination,\n useEntityParams,\n} from '@mesob/ui/components';\nimport { IconKey, IconPlus, IconTrash } from '@tabler/icons-react';\nimport { useQueryClient } from '@tanstack/react-query';\nimport type { ReactNode } from 'react';\nimport { useMemo } from 'react';\nimport { toast } from 'sonner';\nimport type { paths } from '../../data/openapi';\nimport { useApi } from '../../provider';\nimport { PermissionSelector } from './permission-selector';\n\ntype Permission = {\n id: string;\n description?: unknown;\n activity: string;\n application: string;\n feature: string;\n};\n\ntype RolePermissionsPageProps = {\n roleId: string;\n};\n\nconst TABLE_COLUMN_COUNT = 4;\n\nexport function RolePermissionsPage({ roleId }: RolePermissionsPageProps) {\n const { hooks } = useApi();\n const qc = useQueryClient();\n const { queryConfig, params, setParams } = useEntityParams({\n searchKey: 'search',\n defaultSort: 'application',\n defaultOrder: 'asc',\n });\n const permissionsQuery = useMemo(\n () =>\n ({\n params: {\n path: { id: roleId },\n query: queryConfig.params.query,\n },\n }) as {\n params: {\n path: { id: string };\n query: NonNullable<\n paths['/roles/{id}/permissions']['get']['parameters']['query']\n >;\n };\n },\n [queryConfig, roleId],\n );\n\n const { data, isPending, isFetching } = hooks.useQuery(\n 'get',\n '/roles/{id}/permissions',\n permissionsQuery,\n { enabled: !!roleId },\n );\n const assignPermissions = hooks.useMutation(\n 'post',\n '/roles/{id}/permissions',\n {\n onSuccess: (result: { created?: number } | undefined) => {\n qc.invalidateQueries({ queryKey: ['get', '/roles'] });\n qc.invalidateQueries({ queryKey: ['get', '/roles/{id}'] });\n qc.invalidateQueries({ queryKey: ['get', '/roles/{id}/permissions'] });\n toast.success(\n result?.created\n ? `${result.created} permission(s) added`\n : 'No changes',\n );\n },\n onError: () => {\n toast.error('Failed to assign permissions');\n },\n },\n );\n const revokePermission = hooks.useMutation(\n 'delete',\n '/roles/{id}/permissions/{permissionId}',\n {\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: ['get', '/roles'] });\n qc.invalidateQueries({ queryKey: ['get', '/roles/{id}'] });\n qc.invalidateQueries({\n queryKey: ['get', '/roles/{id}/permissions'],\n });\n toast.success('Permission removed');\n },\n onError: () => {\n toast.error('Failed to remove permission');\n },\n },\n );\n\n const permissions = (data?.permissions ?? []) as Permission[];\n const { total, pageCount } = useEntityPagination({\n items: permissions,\n total: data?.total,\n pageSize: params.pageSize,\n });\n const isLoading = isPending || isFetching;\n const currentView = (params.view || 'table') as 'table' | 'card';\n\n if (!roleId) {\n return null;\n }\n\n let content: ReactNode;\n if (isLoading) {\n content = (\n <EntityLoadingState\n view={currentView}\n rowCount={params.pageSize}\n columnCount={TABLE_COLUMN_COUNT}\n cardCount={params.pageSize}\n />\n );\n } else if (total === 0) {\n content = (\n <EntityEmptyState\n icon={IconKey}\n entityName=\"permission\"\n title=\"No permissions assigned\"\n description=\"Assign permissions from the selector to grant access to this role.\"\n />\n );\n } else if (currentView === 'table') {\n content = (\n <div className=\"space-y-4\">\n <DisplayTable withTableBorder>\n <Thead>\n <Tr>\n <Th>Permission</Th>\n <Th>Application</Th>\n <Th>Feature</Th>\n <Th className=\"w-[60px]\" />\n </Tr>\n </Thead>\n <Tbody>\n {permissions.map((permission) => (\n <Tr key={permission.id}>\n <Td>\n <div className=\"space-y-1\">\n <p className=\"font-medium\">{permission.activity}</p>\n <p className=\"font-mono text-xs text-muted-foreground\">\n {permission.id}\n </p>\n </div>\n </Td>\n <Td>\n <Badge variant=\"secondary\">{permission.application}</Badge>\n </Td>\n <Td>\n <Badge variant=\"outline\">{permission.feature}</Badge>\n </Td>\n <Td>\n <DeleteConfirmButton\n entityName=\"permission\"\n onConfirm={() =>\n revokePermission.mutate({\n params: {\n path: { id: roleId, permissionId: permission.id },\n },\n })\n }\n triggerClassName=\"size-8 text-destructive hover:text-destructive\"\n />\n </Td>\n </Tr>\n ))}\n </Tbody>\n </DisplayTable>\n <DataTablePagination\n pageIndex={params.page - 1}\n pageSize={params.pageSize}\n pageCount={pageCount}\n totalRows={total}\n onPageChange={(page) => setParams({ page: page + 1 })}\n onPageSizeChange={(pageSize) => setParams({ pageSize, page: 1 })}\n />\n </div>\n );\n } else {\n content = (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3\">\n {permissions.map((permission) => (\n <div\n key={permission.id}\n className=\"rounded-xl border border-border/60 bg-card p-4 shadow-sm\"\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"space-y-2\">\n <p className=\"font-semibold\">{permission.activity}</p>\n <div className=\"flex flex-wrap gap-2\">\n <Badge variant=\"secondary\">{permission.application}</Badge>\n <Badge variant=\"outline\">{permission.feature}</Badge>\n </div>\n <p className=\"font-mono text-xs text-muted-foreground\">\n {permission.id}\n </p>\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() =>\n revokePermission.mutate({\n params: {\n path: { id: roleId, permissionId: permission.id },\n },\n })\n }\n disabled={revokePermission.isPending}\n >\n <IconTrash className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n ))}\n </div>\n <DataTablePagination\n pageIndex={params.page - 1}\n pageSize={params.pageSize}\n pageCount={pageCount}\n totalRows={total}\n onPageChange={(page) => setParams({ page: page + 1 })}\n onPageSizeChange={(pageSize) => setParams({ pageSize, page: 1 })}\n />\n </div>\n );\n }\n\n return (\n <PageBody className=\"px-0 pb-6\">\n <EntityHeader\n icon={<IconKey className=\"h-5 w-5\" />}\n title=\"Role permissions\"\n actions={\n <PermissionSelector\n trigger={\n <Button size=\"sm\" loading={assignPermissions.isPending}>\n <IconPlus className=\"h-4 w-4\" />\n Add permissions\n </Button>\n }\n onSelect={(selectedPermissions) => {\n if (!selectedPermissions.length) {\n return;\n }\n\n assignPermissions.mutate({\n params: { path: { id: roleId } },\n body: {\n permissionIds: selectedPermissions.map(\n (permission) => permission.id,\n ),\n },\n });\n }}\n excludeIds={permissions.map((permission) => permission.id)}\n />\n }\n search={\n <EntitySearch\n paramKey=\"search\"\n placeholder=\"Search assigned permissions...\"\n />\n }\n filter={\n <EntityFilter\n options={[\n { label: 'All', value: '' },\n { label: 'Application', value: 'application' },\n { label: 'Feature', value: 'feature' },\n { label: 'Activity', value: 'activity' },\n ]}\n placeholder=\"Search field\"\n />\n }\n sort={\n <EntitySort\n defaultSort=\"application\"\n defaultOrder=\"asc\"\n options={[\n { label: 'ID', value: 'id' },\n { label: 'Application', value: 'application' },\n { label: 'Feature', value: 'feature' },\n { label: 'Activity', value: 'activity' },\n ]}\n />\n }\n view={<EntityViewToggle views={['table', 'card']} />}\n />\n {content}\n </PageBody>\n );\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/iam/tenants-page.tsx","../src/pages/iam/tenants/_components/tenant-form.tsx","../src/pages/iam/tenants/_components/tenants-list.tsx","../src/pages/iam/tenants/_components/tenant-card.tsx"],"sourcesContent":["'use client';\n\nimport {\n EntityDrawerTrigger,\n EntityFilter,\n EntityHeader,\n EntitySearch,\n EntitySort,\n EntityViewToggle,\n PageBody,\n PageContainer,\n useBreadcrumbs,\n useEntityPagination,\n useEntityParams,\n} from '@mesob/ui/components';\nimport { IconBuilding } from '@tabler/icons-react';\nimport { useState } from 'react';\nimport type { paths } from '../../data/openapi';\nimport { defaultEntityQueryOptions } from '../../lib/query-options';\nimport { TenantForm } from '../../pages/iam/tenants/_components/tenant-form';\nimport { TenantsList } from '../../pages/iam/tenants/_components/tenants-list';\nimport { useApi, useConfig } from '../../provider';\n\nexport function TenantsPage() {\n const { hooks } = useApi();\n const { config } = useConfig();\n const homeHref = config.navigation?.defaultRedirectUrl || '/';\n useBreadcrumbs({\n items: [\n { label: 'Home', href: homeHref },\n { label: 'IAM', href: '/iam/tenants' },\n { label: 'Tenants' },\n ],\n });\n const [createOpen, setCreateOpen] = useState(false);\n\n const { queryConfig, params, setParams } = useEntityParams({\n searchKey: 'search',\n });\n const tenantsQuery = queryConfig as {\n params: {\n query: NonNullable<paths['/tenants']['get']['parameters']['query']>;\n };\n };\n\n const { data, error, isPending, isFetching } = hooks.useQuery(\n 'get',\n '/tenants',\n tenantsQuery,\n defaultEntityQueryOptions,\n );\n\n const isLoading = isPending || isFetching;\n const tenants = data?.tenants ?? [];\n const { total, pageCount } = useEntityPagination({\n items: tenants,\n total: data?.total,\n pageSize: params.pageSize,\n });\n const errorStatus = (error as { status?: number } | null)?.status;\n const hasAccessError = errorStatus === 401 || errorStatus === 403;\n const hasError = Boolean(error) && !isLoading;\n\n return (\n <PageContainer className=\"flex flex-1 flex-col gap-4 p-4 pt-0\">\n <PageBody className=\"px-0\">\n <EntityHeader\n icon={<IconBuilding className=\"size-5\" />}\n title=\"Tenants\"\n actions={\n hasAccessError ? null : (\n <EntityDrawerTrigger\n mode=\"new\"\n entity=\"Tenant\"\n open={createOpen}\n onOpenChange={setCreateOpen}\n >\n {(open, onClose) => (\n <TenantForm mode=\"new\" open={open} onClose={onClose} />\n )}\n </EntityDrawerTrigger>\n )\n }\n search={\n hasAccessError ? null : (\n <EntitySearch paramKey=\"search\" placeholder=\"Search tenants...\" />\n )\n }\n filter={\n hasAccessError ? null : (\n <EntityFilter\n options={[\n { label: 'All', value: '' },\n { label: 'Active', value: 'isActive:true' },\n { label: 'Inactive', value: 'isActive:false' },\n ]}\n placeholder=\"Filter\"\n />\n )\n }\n sort={\n hasAccessError ? null : (\n <EntitySort\n options={[\n { label: 'Created', value: 'createdAt' },\n { label: 'Updated', value: 'updatedAt' },\n { label: 'Name', value: 'name' },\n ]}\n />\n )\n }\n view={\n hasAccessError ? null : (\n <EntityViewToggle views={['table', 'card']} />\n )\n }\n />\n {hasError ? (\n <div className=\"rounded-[1.75rem] border border-border/60 bg-muted/20 p-8\">\n <div className=\"text-lg font-semibold\">\n {hasAccessError\n ? 'Tenant access denied'\n : 'Unable to load tenants'}\n </div>\n <p className=\"mt-2 text-sm text-muted-foreground\">\n {hasAccessError\n ? 'This account does not have permission to view or manage tenants.'\n : 'The tenants page returned an unexpected error. Retry after the API is healthy.'}\n </p>\n </div>\n ) : (\n <TenantsList\n data={tenants}\n isLoading={isLoading}\n view={(params.view || 'table') as 'table' | 'card'}\n pageIndex={params.page - 1}\n pageSize={params.pageSize}\n pageCount={pageCount}\n totalRows={total}\n onCreateNew={() => setCreateOpen(true)}\n onPageChange={(p) => setParams({ page: p + 1 })}\n onPageSizeChange={(size) => setParams({ pageSize: size, page: 1 })}\n />\n )}\n </PageBody>\n </PageContainer>\n );\n}\n","'use client';\n\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport {\n EntityDrawer,\n EntityFormActions,\n Input,\n Label,\n Skeleton,\n Textarea,\n} from '@mesob/ui/components';\nimport { useQueryClient } from '@tanstack/react-query';\nimport { useEffect } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { z } from 'zod';\nimport { authApi$ } from '../../shared/page-helpers';\nimport { str } from './tenants-data';\n\nconst schema = z.object({\n id: z.string().min(1).max(30),\n name: z.string().optional(),\n description: z.string().optional(),\n isActive: z.boolean(),\n});\n\ntype FormData = z.infer<typeof schema>;\n\nconst defaults: FormData = {\n id: '',\n name: '',\n description: '',\n isActive: true,\n};\n\ntype TenantFormProps = {\n mode: 'new' | 'edit';\n tenantId?: string;\n open: boolean;\n onClose: () => void;\n onSuccess?: () => void;\n};\n\nexport function TenantForm({\n mode,\n tenantId,\n open,\n onClose,\n onSuccess,\n}: TenantFormProps) {\n const qc = useQueryClient();\n const { data, isLoading } = authApi$.useQuery(\n 'get',\n '/tenants/{id}',\n { params: { path: { id: tenantId ?? '' } } },\n { enabled: mode === 'edit' && !!tenantId },\n );\n const create = authApi$.useMutation('post', '/tenants', {\n onSuccess: () => qc.invalidateQueries({ queryKey: ['get', '/tenants'] }),\n });\n const update = authApi$.useMutation('put', '/tenants/{id}', {\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: ['get', '/tenants'] });\n if (tenantId) {\n qc.invalidateQueries({ queryKey: ['get', '/tenants/{id}'] });\n }\n },\n });\n const del = authApi$.useMutation('delete', '/tenants/{id}', {\n onSuccess: () => qc.invalidateQueries({ queryKey: ['get', '/tenants'] }),\n });\n\n const form = useForm<FormData>({\n resolver: zodResolver(schema),\n defaultValues: defaults,\n });\n\n const { reset, formState, register } = form;\n\n useEffect(() => {\n if (!open) {\n return;\n }\n if (mode === 'edit' && data?.tenant && !isLoading) {\n const t = data.tenant;\n reset({\n id: t.id,\n name: str(t.name) || '',\n description: str(t.description) || '',\n isActive: t.isActive,\n });\n } else {\n reset(defaults);\n }\n }, [mode, data, open, isLoading, reset]);\n\n const onSubmit = form.handleSubmit(async (d) => {\n const body = {\n id: d.id,\n name: d.name || undefined,\n description: d.description || undefined,\n isActive: d.isActive,\n };\n if (mode === 'new') {\n await create.mutateAsync({ body });\n } else if (tenantId) {\n await update.mutateAsync({\n params: { path: { id: tenantId } },\n body: {\n name: d.name || undefined,\n description: d.description || undefined,\n isActive: d.isActive,\n },\n });\n }\n onSuccess?.();\n onClose();\n });\n\n const onDelete = async () => {\n if (!tenantId) {\n return;\n }\n await del.mutateAsync({ params: { path: { id: tenantId } } });\n onSuccess?.();\n onClose();\n };\n\n return (\n <EntityDrawer\n title={mode === 'new' ? 'New tenant' : 'Edit tenant'}\n open={open}\n onClose={onClose}\n isDirty={formState.isDirty}\n size=\"md\"\n form={\n isLoading ? (\n <FormSkeleton />\n ) : (\n <form onSubmit={onSubmit} className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"id\">\n ID <span className=\"text-destructive\">*</span>\n </Label>\n <Input\n id=\"id\"\n placeholder=\"e.g. acme\"\n {...register('id')}\n disabled={mode === 'edit'}\n />\n {formState.errors.id && (\n <p className=\"text-sm text-destructive\">\n {formState.errors.id.message}\n </p>\n )}\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"name\">Name</Label>\n <Input\n id=\"name\"\n placeholder=\"Display name\"\n {...register('name')}\n />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"description\">Description</Label>\n <Textarea\n id=\"description\"\n placeholder=\"Description\"\n rows={3}\n {...register('description')}\n />\n </div>\n {mode === 'edit' && (\n <div className=\"flex items-center gap-2\">\n <input\n type=\"checkbox\"\n id=\"isActive\"\n {...register('isActive', {\n setValueAs: (v) => v === true || v === 'on',\n })}\n className=\"h-4 w-4\"\n />\n <Label htmlFor=\"isActive\">Active</Label>\n </div>\n )}\n </form>\n )\n }\n actions={\n <EntityFormActions\n mode={mode}\n onSubmit={onSubmit}\n onReset={mode === 'new' ? () => reset(defaults) : undefined}\n onDelete={mode === 'edit' ? onDelete : undefined}\n isSubmitting={create.isPending || update.isPending}\n isDeleting={del.isPending}\n disabled={isLoading}\n itemName=\"tenant\"\n />\n }\n />\n );\n}\n\nfunction FormSkeleton() {\n return (\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Skeleton className=\"h-4 w-12\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n <div className=\"space-y-2\">\n <Skeleton className=\"h-4 w-16\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n <div className=\"space-y-2\">\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-20 w-full\" />\n </div>\n </div>\n );\n}\n","'use client';\n\nimport {\n Badge,\n DataTableAction,\n DataTablePagination,\n DisplayTable,\n EntityEmptyState,\n EntityLoadingState,\n Tbody,\n Td,\n Th,\n Thead,\n Tr,\n} from '@mesob/ui/components';\nimport { IconBuilding, IconCalendar } from '@tabler/icons-react';\nimport { useState } from 'react';\nimport { Link } from '../../shared/page-helpers';\nimport { TenantCard } from './tenant-card';\nimport { TenantForm } from './tenant-form';\nimport type { Tenant } from './tenants-data';\nimport { str } from './tenants-data';\n\nconst TABLE_COLUMN_COUNT = 5;\n\ntype TenantsListProps = {\n data: Tenant[];\n isLoading?: boolean;\n view: 'table' | 'card';\n pageIndex: number;\n pageSize: number;\n pageCount: number;\n totalRows: number;\n onPageChange: (page: number) => void;\n onPageSizeChange: (size: number) => void;\n onCreateNew?: () => void;\n};\n\nexport function TenantsList({\n data,\n isLoading,\n view,\n pageIndex,\n pageSize,\n pageCount,\n totalRows,\n onPageChange,\n onPageSizeChange,\n onCreateNew,\n}: TenantsListProps) {\n const [editingTenantId, setEditingTenantId] = useState<string | null>(null);\n\n if (isLoading) {\n return (\n <EntityLoadingState\n view={view}\n rowCount={pageSize}\n columnCount={TABLE_COLUMN_COUNT}\n cardCount={pageSize}\n />\n );\n }\n if (totalRows === 0) {\n return (\n <EntityEmptyState\n icon={IconBuilding}\n entityName=\"tenant\"\n title=\"No tenants yet\"\n description=\"Create your first tenant to get started.\"\n onAction={onCreateNew}\n />\n );\n }\n if (view === 'table') {\n return (\n <div className=\"space-y-4\">\n {editingTenantId && (\n <TenantForm\n mode=\"edit\"\n tenantId={editingTenantId}\n open\n onClose={() => setEditingTenantId(null)}\n />\n )}\n <DisplayTable withTableBorder>\n <Thead>\n <Tr>\n <Th>Tenant</Th>\n <Th>Description</Th>\n <Th>Status</Th>\n <Th>Created</Th>\n <Th className=\"w-[50px]\" />\n </Tr>\n </Thead>\n <Tbody>\n {data.map((tenant) => (\n <Tr key={tenant.id} className=\"group\">\n <Td>\n <Link\n href={`/iam/tenants/${tenant.id}`}\n className=\"block text-left font-medium hover:text-primary hover:underline cursor-pointer\"\n >\n <p>{str(tenant.name) || tenant.id}</p>\n <p className=\"text-sm text-muted-foreground\">{tenant.id}</p>\n </Link>\n </Td>\n <Td>\n <span className=\"text-muted-foreground line-clamp-1 max-w-[200px]\">\n {str(tenant.description) || '—'}\n </span>\n </Td>\n <Td>\n <Badge variant={tenant.isActive ? 'default' : 'secondary'}>\n {tenant.isActive ? 'Active' : 'Inactive'}\n </Badge>\n </Td>\n <Td>\n <div className=\"flex items-center gap-1 text-muted-foreground\">\n <IconCalendar className=\"h-4 w-4\" />\n {new Date(tenant.createdAt).toLocaleDateString()}\n </div>\n </Td>\n <Td>\n <DataTableAction\n onClick={() => setEditingTenantId(tenant.id)}\n />\n </Td>\n </Tr>\n ))}\n </Tbody>\n </DisplayTable>\n <DataTablePagination\n pageIndex={pageIndex}\n pageSize={pageSize}\n pageCount={pageCount}\n totalRows={totalRows}\n onPageChange={onPageChange}\n onPageSizeChange={onPageSizeChange}\n />\n </div>\n );\n }\n return (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\">\n {data.map((t) => (\n <TenantCard key={t.id} tenant={t} />\n ))}\n </div>\n <DataTablePagination\n pageIndex={pageIndex}\n pageSize={pageSize}\n pageCount={pageCount}\n totalRows={totalRows}\n onPageChange={onPageChange}\n onPageSizeChange={onPageSizeChange}\n />\n </div>\n );\n}\n","'use client';\n\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuPortal,\n DropdownMenuTrigger,\n} from '@mesob/ui/components';\nimport { IconDots, IconPencil } from '@tabler/icons-react';\nimport { useState } from 'react';\nimport { Link } from '../../shared/page-helpers';\nimport { TenantForm } from './tenant-form';\nimport { str, type Tenant } from './tenants-data';\n\ntype TenantCardProps = { tenant: Tenant };\n\nexport function TenantCard({ tenant }: TenantCardProps) {\n const [editOpen, setEditOpen] = useState(false);\n return (\n <>\n <Card className=\"group hover:shadow-md transition-shadow\">\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-start justify-between\">\n <Link\n href={`/iam/tenants/${tenant.id}`}\n className=\"text-left font-semibold hover:text-primary hover:underline\"\n >\n {str(tenant.name) || tenant.id}\n </Link>\n <DropdownMenu>\n <DropdownMenuTrigger\n render={\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 opacity-0 group-hover:opacity-100 transition-opacity\"\n />\n }\n >\n <IconDots className=\"h-4 w-4\" />\n </DropdownMenuTrigger>\n <DropdownMenuPortal>\n <DropdownMenuContent>\n <DropdownMenuItem onClick={() => setEditOpen(true)}>\n <IconPencil className=\"mr-2 h-4 w-4\" />\n Edit\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenuPortal>\n </DropdownMenu>\n </div>\n <p className=\"text-sm text-muted-foreground\">{tenant.id}</p>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n <Badge variant={tenant.isActive ? 'default' : 'secondary'}>\n {tenant.isActive ? 'Active' : 'Inactive'}\n </Badge>\n {str(tenant.description) ? (\n <p className=\"text-sm text-muted-foreground line-clamp-2\">\n {str(tenant.description)}\n </p>\n ) : null}\n <p className=\"text-xs text-muted-foreground\">\n Created {new Date(tenant.createdAt).toLocaleDateString()}\n </p>\n </CardContent>\n </Card>\n {editOpen ? (\n <TenantForm\n mode=\"edit\"\n tenantId={tenant.id}\n open={editOpen}\n onClose={() => setEditOpen(false)}\n />\n ) : null}\n </>\n );\n}\n"],"mappings":"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","names":["IconBuilding","useState","Badge","useState","jsx","jsxs","jsx","jsxs","useState","Badge","jsx","jsxs","useState","IconBuilding"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/iam/users-page.tsx","../src/pages/iam/users/_components/bulk-invite-user-form.tsx","../src/pages/iam/users/_components/invite-user-shared.tsx","../src/pages/iam/users/_components/invite-user-form.tsx","../src/pages/iam/users/_components/users-list.tsx"],"sourcesContent":["'use client';\n\nimport {\n EntityDrawerTrigger,\n EntityFilter,\n EntityHeader,\n EntitySearch,\n EntitySort,\n EntityViewToggle,\n PageBody,\n PageContainer,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n useBreadcrumbs,\n useEntityPagination,\n useEntityParams,\n} from '@mesob/ui/components';\nimport { cn } from '@mesob/ui/lib/utils';\nimport { IconFilter, IconUsers } from '@tabler/icons-react';\nimport { parseAsString, useQueryState } from 'nuqs';\nimport { useMemo, useState } from 'react';\nimport type { paths } from '../../data/openapi';\nimport { defaultEntityQueryOptions } from '../../lib/query-options';\nimport { BulkInviteUserForm } from '../../pages/iam/users/_components/bulk-invite-user-form';\nimport { InviteUserForm } from '../../pages/iam/users/_components/invite-user-form';\nimport { UsersList } from '../../pages/iam/users/_components/users-list';\nimport { useApi, useConfig } from '../../provider';\n\nfunction capitalize(s: string) {\n return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\nexport function UsersPage() {\n const { hooks } = useApi();\n const { config } = useConfig();\n const homeHref = config.navigation?.defaultRedirectUrl || '/';\n const defaultUserType = config.defaultUserType ?? 'employee';\n useBreadcrumbs({\n items: [\n { label: 'Home', href: homeHref },\n { label: 'IAM', href: '/iam/users' },\n { label: 'Users' },\n ],\n });\n const [inviteOpen, setInviteOpen] = useState(false);\n const [bulkInviteOpen, setBulkInviteOpen] = useState(false);\n\n const { queryConfig, params, setParams } = useEntityParams({\n searchKey: 'search',\n searchParamName: 'search',\n });\n const [userType, setUserType] = useQueryState(\n 'userType',\n parseAsString.withDefault(defaultUserType),\n );\n\n const usersQuery = useMemo(\n () =>\n ({\n params: {\n query: {\n ...queryConfig.params.query,\n userType: userType || defaultUserType,\n },\n },\n }) as {\n params: {\n query: NonNullable<paths['/users']['get']['parameters']['query']>;\n };\n },\n [queryConfig.params.query, userType, defaultUserType],\n );\n\n const { data, isPending, isFetching } = hooks.useQuery(\n 'get',\n '/users',\n usersQuery,\n defaultEntityQueryOptions,\n );\n\n const isLoading = isPending || isFetching;\n const users = data?.users ?? [];\n const { total, pageCount } = useEntityPagination({\n items: users,\n total: data?.total,\n pageSize: params.pageSize,\n });\n\n return (\n <PageContainer className=\"flex flex-1 flex-col gap-4 p-4 pt-0\">\n <PageBody className=\"px-0\">\n <EntityHeader\n icon={<IconUsers className=\"h-5 w-5\" />}\n title=\"Users\"\n actions={\n <div className=\"flex items-center gap-2\">\n <EntityDrawerTrigger\n mode=\"new\"\n entity=\"User\"\n label=\"Invite user\"\n open={inviteOpen}\n onOpenChange={setInviteOpen}\n >\n {(open, onClose) => (\n <InviteUserForm open={open} onClose={onClose} />\n )}\n </EntityDrawerTrigger>\n <EntityDrawerTrigger\n mode=\"new\"\n entity=\"User\"\n label=\"Bulk invite\"\n variant=\"outline\"\n open={bulkInviteOpen}\n onOpenChange={setBulkInviteOpen}\n >\n {(open, onClose) => (\n <BulkInviteUserForm open={open} onClose={onClose} />\n )}\n </EntityDrawerTrigger>\n </div>\n }\n search={\n <EntitySearch paramKey=\"search\" placeholder=\"Search users...\" />\n }\n filter={\n <div className=\"flex flex-none flex-nowrap items-center gap-2\">\n <Select\n value={userType}\n onValueChange={(v) => {\n setUserType(v);\n setParams({ page: 1 });\n }}\n >\n <SelectTrigger className=\"h-9 min-w-[150px] w-[150px]\">\n <IconFilter className=\"size-4 shrink-0\" />\n <span\n className={cn(\n 'line-clamp-1 flex items-center gap-2',\n !userType && 'text-muted-foreground',\n )}\n >\n {userType === 'all'\n ? 'All'\n : capitalize(userType ?? defaultUserType)}\n </span>\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">All</SelectItem>\n <SelectItem value={defaultUserType}>\n {capitalize(defaultUserType)}\n </SelectItem>\n </SelectContent>\n </Select>\n <EntityFilter\n options={[\n { label: 'All', value: '' },\n { label: 'Verified', value: 'verified' },\n { label: 'Unverified', value: 'unverified' },\n ]}\n placeholder=\"Verification\"\n />\n </div>\n }\n sort={\n <EntitySort\n defaultSort=\"createdAt\"\n defaultOrder=\"desc\"\n options={[\n { label: 'Name', value: 'fullName' },\n { label: 'Phone', value: 'phone' },\n { label: 'Email', value: 'email' },\n { label: 'Type', value: 'userType' },\n { label: 'Roles', value: 'roleCount' },\n { label: 'Last login', value: 'lastSignInAt' },\n { label: 'Session', value: 'activeSessionCount' },\n { label: 'Created', value: 'createdAt' },\n ]}\n />\n }\n view={<EntityViewToggle views={['table', 'card']} />}\n />\n <UsersList\n data={users}\n isLoading={isLoading}\n view={(params.view || 'table') as 'table' | 'card'}\n pageIndex={params.page - 1}\n pageSize={params.pageSize}\n pageCount={pageCount}\n totalRows={total}\n onCreateNew={() => setInviteOpen(true)}\n onPageChange={(p) => setParams({ page: p + 1 })}\n onPageSizeChange={(size) => setParams({ pageSize: size, page: 1 })}\n />\n </PageBody>\n </PageContainer>\n );\n}\n","'use client';\n\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n EntityDrawer,\n EntityFormActions,\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n Input,\n Textarea,\n} from '@mesob/ui/components';\nimport { IconDownload, IconUsers } from '@tabler/icons-react';\nimport { useQueryClient } from '@tanstack/react-query';\nimport type { ChangeEvent } from 'react';\nimport { useEffect, useState } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { toast } from 'sonner';\nimport { z } from 'zod';\nimport { authApi$ } from '../../shared/page-helpers';\nimport type {\n BulkInviteFailure,\n BulkInviteResponse,\n} from './invite-user-shared';\nimport {\n downloadInviteTemplate,\n InviteResultCard,\n inviteTemplateCsv,\n parseBulkInviteCsv,\n} from './invite-user-shared';\n\nconst schema = z.object({\n sourceFile: z.string().optional(),\n csvText: z.string().trim().min(1, 'CSV text is required'),\n});\n\ntype FormData = z.infer<typeof schema>;\n\ntype BulkInviteUserFormProps = {\n open: boolean;\n onClose: () => void;\n};\n\nconst defaults: FormData = {\n sourceFile: '',\n csvText: '',\n};\n\nexport function BulkInviteUserForm({ open, onClose }: BulkInviteUserFormProps) {\n const qc = useQueryClient();\n const [invited, setInvited] = useState<BulkInviteResponse['invited']>([]);\n const [failed, setFailed] = useState<BulkInviteFailure[]>([]);\n\n const form = useForm<FormData>({\n resolver: zodResolver(schema),\n defaultValues: defaults,\n });\n const { control, formState, getValues, reset, setValue } = form;\n\n const inviteBulk = authApi$.useMutation('post', '/users/invite/bulk', {\n onSuccess: async () => {\n await qc.invalidateQueries({ queryKey: ['get', '/users'] });\n },\n });\n\n useEffect(() => {\n if (open) {\n return;\n }\n\n reset(defaults);\n setInvited([]);\n setFailed([]);\n }, [open, reset]);\n\n const handleFileChange = async (\n event: ChangeEvent<HTMLInputElement>,\n onChange: (value: string) => void,\n ) => {\n const file = event.target.files?.[0];\n\n if (!file) {\n return;\n }\n\n try {\n const text = await file.text();\n onChange(file.name);\n setValue('csvText', text, {\n shouldDirty: true,\n shouldValidate: true,\n });\n toast.success(`Loaded ${file.name}`);\n } catch (error) {\n toast.error(\n error instanceof Error ? error.message : 'Failed to read CSV file',\n );\n } finally {\n event.target.value = '';\n }\n };\n\n const onSubmit = form.handleSubmit(async (values) => {\n try {\n const result = await inviteBulk.mutateAsync({\n body: {\n users: parseBulkInviteCsv(values.csvText),\n },\n });\n\n setInvited(result.invited);\n setFailed(result.failed);\n toast.success(\n `Bulk invite finished: ${result.invited.length} invited, ${result.failed.length} failed`,\n );\n } catch (error) {\n toast.error(\n error instanceof Error ? error.message : 'Failed to bulk invite users',\n );\n }\n });\n\n return (\n <EntityDrawer\n title=\"Bulk invite users\"\n open={open}\n onClose={onClose}\n isDirty={formState.isDirty}\n size=\"xl\"\n form={\n <Form {...form}>\n <form onSubmit={onSubmit} className=\"space-y-4\">\n <div className=\"space-y-2\">\n <p className=\"text-sm text-muted-foreground\">\n Download the CSV template, fill it with your users, then upload\n or paste the CSV below.\n </p>\n <Button\n variant=\"outline\"\n onClick={downloadInviteTemplate}\n leftIcon={<IconDownload className=\"size-4\" />}\n >\n Download template\n </Button>\n </div>\n\n <FormField\n control={control}\n name=\"sourceFile\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>Upload CSV</FormLabel>\n <FormControl>\n <Input\n type=\"file\"\n accept=\".csv,text/csv\"\n onChange={(event) =>\n handleFileChange(event, field.onChange)\n }\n />\n </FormControl>\n {field.value ? (\n <p className=\"text-sm text-muted-foreground\">\n Loaded file: {field.value}\n </p>\n ) : null}\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"csvText\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>CSV textarea</FormLabel>\n <FormControl>\n <Textarea\n className=\"min-h-[240px] font-mono text-xs\"\n placeholder={inviteTemplateCsv}\n {...field}\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n {(invited.length > 0 || failed.length > 0) && (\n <>\n <Card className=\"border-border/60\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <IconUsers className=\"size-4\" />\n Invited\n <Badge>{invited.length}</Badge>\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {invited.length ? (\n invited.map((result, index) => (\n <InviteResultCard\n key={`${result.user.id}-${index}`}\n result={result}\n index={index}\n />\n ))\n ) : (\n <p className=\"text-sm text-muted-foreground\">\n Successful invites will show here.\n </p>\n )}\n </CardContent>\n </Card>\n\n <Card className=\"border-border/60\">\n <CardHeader>\n <CardTitle className=\"text-base\">\n Failed rows\n <Badge className=\"ml-2\" variant=\"destructive\">\n {failed.length}\n </Badge>\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {failed.length ? (\n failed.map((failure) => (\n <div\n key={`${failure.index}-${failure.identifier}`}\n className=\"rounded-lg border border-destructive/30 bg-destructive/5 p-4\"\n >\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"font-medium\">\n row {failure.index + 1}\n </span>\n {failure.identifier ? (\n <Badge variant=\"outline\">\n {failure.identifier}\n </Badge>\n ) : null}\n </div>\n <p className=\"mt-2 text-sm text-muted-foreground\">\n {failure.error}\n </p>\n </div>\n ))\n ) : (\n <p className=\"text-sm text-muted-foreground\">\n Failed invites will show here.\n </p>\n )}\n </CardContent>\n </Card>\n </>\n )}\n </form>\n </Form>\n }\n actions={\n <EntityFormActions\n mode=\"new\"\n onSubmit={onSubmit}\n onReset={() => {\n reset(defaults);\n setInvited([]);\n setFailed([]);\n }}\n isSubmitting={inviteBulk.isPending}\n submitLabel=\"Invite\"\n disabled={!getValues('csvText').trim()}\n />\n }\n />\n );\n}\n","'use client';\n\nimport {\n Badge,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n} from '@mesob/ui/components';\nimport type { paths } from '../../../../data/openapi';\n\ntype InviteUserPayload = NonNullable<\n NonNullable<\n paths['/users/invite']['post']['requestBody']\n >['content']['application/json']\n>;\n\ntype InviteResult =\n paths['/users/invite']['post']['responses'][201]['content']['application/json'];\n\ntype BulkInviteResponse =\n paths['/users/invite/bulk']['post']['responses'][200]['content']['application/json'];\n\ntype BulkInviteFailure = BulkInviteResponse['failed'][number];\n\nconst inviteTemplateCsv = `fullName,email,phone,emailVerified,phoneVerified,sendVia,password\nLulit Demo,lulit@example.com,,true,false,email,\nAbel Demo,,+251911223344,false,true,sms|email,TempPass123!\nMarta Demo,marta@example.com,+251922334455,true,true,email|sms,`;\n\nconst defaultInviteUserValues = {\n fullName: '',\n email: '',\n phone: '',\n password: '',\n emailVerified: false,\n phoneVerified: false,\n viaEmail: false,\n viaSms: false,\n};\n\nfunction buildInviteUserPayload(\n values: typeof defaultInviteUserValues,\n): InviteUserPayload {\n return {\n fullName: values.fullName.trim(),\n email: values.email.trim() || undefined,\n phone: values.phone.trim() || undefined,\n password: values.password.trim() || undefined,\n emailVerified: values.emailVerified,\n phoneVerified: values.phoneVerified,\n sendVia: [\n values.viaEmail ? 'email' : null,\n values.viaSms ? 'sms' : null,\n ].filter(Boolean) as InviteUserPayload['sendVia'],\n };\n}\n\nfunction parseCsvLine(line: string) {\n const cells: string[] = [];\n let current = '';\n let quoted = false;\n\n for (let i = 0; i < line.length; i += 1) {\n const char = line[i];\n const next = line[i + 1];\n\n if (char === '\"' && quoted && next === '\"') {\n current += '\"';\n i += 1;\n continue;\n }\n\n if (char === '\"') {\n quoted = !quoted;\n continue;\n }\n\n if (char === ',' && !quoted) {\n cells.push(current.trim());\n current = '';\n continue;\n }\n\n current += char;\n }\n\n cells.push(current.trim());\n return cells;\n}\n\nfunction parseBoolean(value: string | undefined) {\n if (!value) {\n return false;\n }\n\n return ['true', '1', 'yes', 'y'].includes(value.trim().toLowerCase());\n}\n\nfunction parseSendVia(value: string | undefined) {\n if (!value) {\n return [];\n }\n\n return value\n .split('|')\n .map((item) => item.trim().toLowerCase())\n .filter(\n (item): item is NonNullable<InviteUserPayload['sendVia']>[number] =>\n item === 'email' || item === 'sms',\n );\n}\n\nfunction parseBulkInviteCsv(text: string): InviteUserPayload[] {\n const lines = text\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter(Boolean);\n\n if (!lines.length) {\n throw new Error('Paste at least one CSV row.');\n }\n\n const header = parseCsvLine(lines[0]).map((cell) => cell.toLowerCase());\n const hasHeader = header.includes('fullname');\n const rows = hasHeader ? lines.slice(1) : lines;\n\n if (!rows.length) {\n throw new Error('CSV only has a header row.');\n }\n\n const keys = hasHeader\n ? header\n : [\n 'fullName',\n 'email',\n 'phone',\n 'emailVerified',\n 'phoneVerified',\n 'sendVia',\n 'password',\n ];\n\n return rows.map((line, index) => {\n const values = parseCsvLine(line);\n const record = Object.fromEntries(\n keys.map((key, valueIndex) => [key, values[valueIndex] ?? '']),\n );\n const fullName = String(\n record.fullname || record.fullName || record.name || '',\n ).trim();\n const email = String(record.email || '').trim();\n const phone = String(record.phone || '').trim();\n\n if (!fullName) {\n throw new Error(`Row ${index + 1}: fullName is required.`);\n }\n\n if (!(email || phone)) {\n throw new Error(`Row ${index + 1}: email or phone is required.`);\n }\n\n return {\n fullName,\n email: email || undefined,\n phone: phone || undefined,\n password: String(record.password || '').trim() || undefined,\n emailVerified: parseBoolean(\n String(record.emailverified || record.emailVerified || ''),\n ),\n phoneVerified: parseBoolean(\n String(record.phoneverified || record.phoneVerified || ''),\n ),\n sendVia: parseSendVia(String(record.sendvia || record.sendVia || '')),\n };\n });\n}\n\nfunction downloadInviteTemplate() {\n const blob = new Blob([inviteTemplateCsv], {\n type: 'text/csv;charset=utf-8',\n });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n\n link.href = url;\n link.download = 'users-bulk-invite-template.csv';\n link.click();\n URL.revokeObjectURL(url);\n}\n\nfunction DeliveryBadges({ delivery }: { delivery: InviteResult['delivery'] }) {\n return (\n <div className=\"flex flex-wrap gap-2\">\n {delivery.email ? (\n <Badge\n variant={delivery.email === 'failed' ? 'destructive' : 'outline'}\n >\n email: {delivery.email}\n </Badge>\n ) : null}\n {delivery.sms ? (\n <Badge variant={delivery.sms === 'failed' ? 'destructive' : 'outline'}>\n sms: {delivery.sms}\n </Badge>\n ) : null}\n {delivery.email || delivery.sms ? null : (\n <Badge variant=\"secondary\">no delivery</Badge>\n )}\n </div>\n );\n}\n\nfunction InviteResultCard({\n result,\n index,\n}: {\n result: InviteResult;\n index?: number;\n}) {\n return (\n <Card className=\"border-border/60 bg-background/70\">\n <CardHeader className=\"pb-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div>\n <CardTitle className=\"text-base\">{result.user.fullName}</CardTitle>\n <CardDescription>\n {result.user.email || result.user.phone || 'No identifier'}\n </CardDescription>\n </div>\n <div className=\"flex gap-2\">\n {typeof index === 'number' ? (\n <Badge variant=\"outline\">row {index + 1}</Badge>\n ) : null}\n <Badge variant={result.hasPassword ? 'secondary' : 'default'}>\n {result.hasPassword ? 'password set' : 'set-password flow'}\n </Badge>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-3 text-sm\">\n <div className=\"flex flex-wrap gap-2\">\n <Badge variant={result.user.emailVerified ? 'default' : 'secondary'}>\n email {result.user.emailVerified ? 'verified' : 'pending'}\n </Badge>\n <Badge variant={result.user.phoneVerified ? 'default' : 'secondary'}>\n phone {result.user.phoneVerified ? 'verified' : 'pending'}\n </Badge>\n </div>\n <DeliveryBadges delivery={result.delivery} />\n {result.inviteUrl ? (\n <p className=\"rounded-md border border-dashed border-border/70 bg-muted/40 px-3 py-2 font-mono text-xs break-all\">\n {result.inviteUrl}\n </p>\n ) : null}\n </CardContent>\n </Card>\n );\n}\n\nexport {\n buildInviteUserPayload,\n defaultInviteUserValues,\n downloadInviteTemplate,\n inviteTemplateCsv,\n InviteResultCard,\n parseBulkInviteCsv,\n};\nexport type { BulkInviteFailure, BulkInviteResponse, InviteResult };\n","'use client';\n\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport {\n Checkbox,\n EntityDrawer,\n EntityFormActions,\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n Input,\n Stack,\n} from '@mesob/ui/components';\nimport { useQueryClient } from '@tanstack/react-query';\nimport type { ComponentProps } from 'react';\nimport { useEffect, useState } from 'react';\nimport { useForm, useWatch } from 'react-hook-form';\nimport { toast } from 'sonner';\nimport { z } from 'zod';\nimport { authApi$ } from '../../shared/page-helpers';\nimport {\n buildInviteUserPayload,\n defaultInviteUserValues,\n InviteResultCard,\n} from './invite-user-shared';\n\nconst schema = z\n .object({\n fullName: z.string().trim().min(1, 'Full name is required'),\n email: z.string().email('Invalid email').or(z.literal('')),\n phone: z.string(),\n password: z.string(),\n emailVerified: z.boolean(),\n phoneVerified: z.boolean(),\n viaEmail: z.boolean(),\n viaSms: z.boolean(),\n })\n .superRefine((value, ctx) => {\n if (!(value.email.trim() || value.phone.trim())) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['email'],\n message: 'Email or phone is required',\n });\n }\n });\n\ntype FormData = z.infer<typeof schema>;\n\ntype InviteUserFormProps = {\n open: boolean;\n onClose: () => void;\n};\n\nexport function InviteUserForm({ open, onClose }: InviteUserFormProps) {\n const qc = useQueryClient();\n const [result, setResult] = useState<\n ComponentProps<typeof InviteResultCard>['result'] | null\n >(null);\n\n const form = useForm<FormData>({\n resolver: zodResolver(schema),\n defaultValues: defaultInviteUserValues,\n });\n const { control, formState, reset, setValue } = form;\n const email = useWatch({ control, name: 'email' }) ?? '';\n const phone = useWatch({ control, name: 'phone' }) ?? '';\n const hasEmail = email.trim().length > 0;\n const hasPhone = phone.trim().length > 0;\n\n const inviteUser = authApi$.useMutation('post', '/users/invite', {\n onSuccess: async () => {\n await qc.invalidateQueries({ queryKey: ['get', '/users'] });\n },\n });\n\n useEffect(() => {\n if (!hasEmail) {\n setValue('emailVerified', false, { shouldDirty: false });\n setValue('viaEmail', false, { shouldDirty: false });\n }\n }, [hasEmail, setValue]);\n\n useEffect(() => {\n if (!hasPhone) {\n setValue('phoneVerified', false, { shouldDirty: false });\n setValue('viaSms', false, { shouldDirty: false });\n }\n }, [hasPhone, setValue]);\n\n useEffect(() => {\n if (open) {\n return;\n }\n\n reset(defaultInviteUserValues);\n setResult(null);\n }, [open, reset]);\n\n const onSubmit = form.handleSubmit(async (values) => {\n try {\n const inviteResult = await inviteUser.mutateAsync({\n body: buildInviteUserPayload(values),\n });\n\n setResult(inviteResult);\n reset(defaultInviteUserValues);\n toast.success('User invited');\n } catch (error) {\n toast.error(\n error instanceof Error ? error.message : 'Failed to invite user',\n );\n }\n });\n\n return (\n <EntityDrawer\n title=\"Invite user\"\n open={open}\n onClose={onClose}\n isDirty={formState.isDirty}\n size=\"lg\"\n form={\n <Form {...form}>\n <form onSubmit={onSubmit} className=\"space-y-4\">\n <Stack>\n <FormField\n control={control}\n name=\"fullName\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>\n Full name <span className=\"text-destructive\">*</span>\n </FormLabel>\n <FormControl>\n <Input placeholder=\"Aster Bekele\" {...field} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"email\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>Email</FormLabel>\n <FormControl>\n <Input\n type=\"email\"\n placeholder=\"aster@example.com\"\n {...field}\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"phone\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>Phone</FormLabel>\n <FormControl>\n <Input placeholder=\"+251911223344\" {...field} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"password\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>Password</FormLabel>\n <FormControl>\n <Input\n type=\"password\"\n placeholder=\"Optional\"\n {...field}\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"emailVerified\"\n render={({ field }) => (\n <FormItem>\n <div className=\"flex items-start gap-3\">\n <FormControl>\n <Checkbox\n checked={field.value}\n disabled={!hasEmail}\n onCheckedChange={(checked) =>\n field.onChange(checked === true)\n }\n />\n </FormControl>\n <div className=\"grid gap-1\">\n <FormLabel>Email verified</FormLabel>\n <FormMessage />\n </div>\n </div>\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"phoneVerified\"\n render={({ field }) => (\n <FormItem>\n <div className=\"flex items-start gap-3\">\n <FormControl>\n <Checkbox\n checked={field.value}\n disabled={!hasPhone}\n onCheckedChange={(checked) =>\n field.onChange(checked === true)\n }\n />\n </FormControl>\n <div className=\"grid gap-1\">\n <FormLabel>Phone verified</FormLabel>\n <FormMessage />\n </div>\n </div>\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"viaEmail\"\n render={({ field }) => (\n <FormItem>\n <div className=\"flex items-start gap-3\">\n <FormControl>\n <Checkbox\n checked={field.value}\n disabled={!hasEmail}\n onCheckedChange={(checked) =>\n field.onChange(checked === true)\n }\n />\n </FormControl>\n <div className=\"grid gap-1\">\n <FormLabel>Send email invite</FormLabel>\n <FormMessage />\n </div>\n </div>\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"viaSms\"\n render={({ field }) => (\n <FormItem>\n <div className=\"flex items-start gap-3\">\n <FormControl>\n <Checkbox\n checked={field.value}\n disabled={!hasPhone}\n onCheckedChange={(checked) =>\n field.onChange(checked === true)\n }\n />\n </FormControl>\n <div className=\"grid gap-1\">\n <FormLabel>Send SMS invite</FormLabel>\n <FormMessage />\n </div>\n </div>\n </FormItem>\n )}\n />\n\n {result ? <InviteResultCard result={result} /> : null}\n </Stack>\n </form>\n </Form>\n }\n actions={\n <EntityFormActions\n mode=\"new\"\n onSubmit={onSubmit}\n onReset={() => {\n reset(defaultInviteUserValues);\n setResult(null);\n }}\n isSubmitting={inviteUser.isPending}\n submitLabel=\"Invite\"\n />\n }\n />\n );\n}\n","'use client';\n\nimport {\n Badge,\n DataTableAction,\n DataTablePagination,\n DisplayTable,\n EntityEmptyState,\n EntityLoadingState,\n LocaleText,\n Tbody,\n Td,\n Th,\n Thead,\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n Tr,\n} from '@mesob/ui/components';\nimport { useLocaleConfig } from '@mesob/ui/providers';\nimport {\n IconCalendar,\n IconCircleCheck,\n IconDeviceDesktop,\n IconUserPlus,\n IconUsers,\n} from '@tabler/icons-react';\nimport { useLocale } from 'next-intl';\nimport { useState } from 'react';\nimport { Link } from '../../shared/page-helpers';\nimport { UserCard } from './user-card';\nimport { UserForm } from './user-form';\nimport type { User } from './users-data';\n\nfunction resolveRoleName(\n name: string | Record<string, string> | undefined,\n locale: string,\n defaultLanguage: string,\n): string {\n if (!name) {\n return '';\n }\n if (typeof name === 'string') {\n return name;\n }\n return name[locale] ?? name[defaultLanguage] ?? Object.values(name)[0] ?? '';\n}\n\nfunction roleInitials(name: string, maxWords = 2): string {\n const words = name.trim().split(/\\s+/).filter(Boolean);\n if (words.length === 0) {\n return '';\n }\n return words\n .slice(0, maxWords)\n .map((w) => w.charAt(0))\n .join('')\n .toUpperCase();\n}\n\nconst TABLE_COLUMN_COUNT = 6;\n\nfunction capitalize(s: string) {\n return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\nfunction UserTableRow({\n user,\n onEdit,\n locale,\n defaultLanguage,\n}: {\n user: User;\n onEdit: (id: string) => void;\n locale: string;\n defaultLanguage: string;\n}) {\n return (\n <Tr className=\"group\">\n <Td>\n <Link\n href={`/iam/users/${user.id}`}\n className=\"font-medium hover:text-primary hover:underline cursor-pointer\"\n >\n {user.fullName}\n </Link>\n </Td>\n <Td>\n <div className=\"space-y-1\">\n {user.email && (\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm\">{user.email}</span>\n {user.emailVerified && (\n <Tooltip>\n <TooltipTrigger>\n <IconCircleCheck className=\"size-4 text-muted-foreground\" />\n </TooltipTrigger>\n <TooltipContent>Email verified</TooltipContent>\n </Tooltip>\n )}\n </div>\n )}\n {user.phone && (\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm\">{user.phone}</span>\n {user.phoneVerified && (\n <Tooltip>\n <TooltipTrigger>\n <IconCircleCheck className=\"size-4 text-muted-foreground\" />\n </TooltipTrigger>\n <TooltipContent>Phone verified</TooltipContent>\n </Tooltip>\n )}\n </div>\n )}\n {!(user.email || user.phone) && (\n <span className=\"text-muted-foreground\">—</span>\n )}\n </div>\n </Td>\n <Td>\n {(user.userType?.length ?? 0) > 0 ? (\n <div className=\"flex flex-wrap gap-1\">\n {user.userType?.map((t) => (\n <Badge key={t} variant=\"secondary\" className=\"text-xs\">\n {capitalize(t)}\n </Badge>\n ))}\n </div>\n ) : (\n <span className=\"text-muted-foreground\">—</span>\n )}\n </Td>\n <Td>\n {(user.userRoles?.length ?? 0) > 0 ? (\n <div className=\"flex flex-wrap gap-1\">\n {user.userRoles?.map((r) => {\n const nameRecord =\n typeof r.name === 'object' && r.name !== null\n ? r.name\n : { en: typeof r.name === 'string' ? r.name : r.code };\n const label = resolveRoleName(r.name, locale, defaultLanguage);\n return (\n <Tooltip key={r.code}>\n <TooltipTrigger>\n <Badge\n variant=\"outline\"\n className=\"cursor-default px-1.5 py-0 text-xs font-medium\"\n >\n {roleInitials(label || r.code) ||\n r.code.slice(0, 2).toUpperCase()}\n </Badge>\n </TooltipTrigger>\n <TooltipContent>\n <LocaleText text={nameRecord} />\n </TooltipContent>\n </Tooltip>\n );\n })}\n </div>\n ) : (\n <span className=\"text-muted-foreground\">—</span>\n )}\n </Td>\n <Td>\n <div className=\"flex flex-wrap items-center gap-3 text-sm text-muted-foreground\">\n <Tooltip>\n <TooltipTrigger>\n <span className=\"flex min-w-[6.5rem] cursor-default items-center gap-1\">\n <IconCalendar className=\"h-4 w-4 shrink-0\" />\n {user.lastSignInAt\n ? new Date(user.lastSignInAt).toLocaleDateString()\n : 'Never'}\n </span>\n </TooltipTrigger>\n <TooltipContent>\n Last login\n {user.lastSignInAt\n ? `: ${new Date(user.lastSignInAt).toLocaleString()}`\n : ''}\n </TooltipContent>\n </Tooltip>\n {user.createdAt ? (\n <Tooltip>\n <TooltipTrigger>\n <span className=\"flex min-w-[6.5rem] cursor-default items-center gap-1\">\n <IconUserPlus className=\"h-4 w-4 shrink-0\" />\n {new Date(user.createdAt).toLocaleDateString()}\n </span>\n </TooltipTrigger>\n <TooltipContent>\n Registration date: {new Date(user.createdAt).toLocaleString()}\n </TooltipContent>\n </Tooltip>\n ) : (\n <span className=\"min-w-[6.5rem]\" />\n )}\n <Tooltip>\n <TooltipTrigger>\n <span className=\"flex min-w-[6.5rem] cursor-default items-center gap-1\">\n <IconDeviceDesktop className=\"h-4 w-4 shrink-0\" />\n {user.activeSessionCount ?? 0}\n </span>\n </TooltipTrigger>\n <TooltipContent>\n {user.activeSessionCount === 1\n ? '1 active session'\n : `${user.activeSessionCount ?? 0} active sessions`}\n </TooltipContent>\n </Tooltip>\n </div>\n </Td>\n <Td>\n <DataTableAction onClick={() => onEdit(user.id)} />\n </Td>\n </Tr>\n );\n}\n\ntype UsersListProps = {\n data: User[];\n isLoading?: boolean;\n view: 'table' | 'card';\n pageIndex: number;\n pageSize: number;\n pageCount: number;\n totalRows: number;\n onPageChange: (page: number) => void;\n onPageSizeChange: (size: number) => void;\n onCreateNew?: () => void;\n};\n\nexport function UsersList({\n data,\n isLoading,\n view,\n pageIndex,\n pageSize,\n pageCount,\n totalRows,\n onPageChange,\n onPageSizeChange,\n onCreateNew,\n}: UsersListProps) {\n const [editingUserId, setEditingUserId] = useState<string | null>(null);\n const locale = useLocale();\n const { defaultLanguage } = useLocaleConfig();\n\n if (isLoading) {\n return (\n <EntityLoadingState\n view={view}\n rowCount={pageSize}\n columnCount={TABLE_COLUMN_COUNT}\n cardCount={pageSize}\n />\n );\n }\n if (totalRows === 0) {\n return (\n <EntityEmptyState\n icon={IconUsers}\n entityName=\"user\"\n title=\"No users yet\"\n description=\"Invite your first user to get started.\"\n actionLabel=\"Invite user\"\n onAction={onCreateNew}\n />\n );\n }\n if (view === 'table') {\n return (\n <div className=\"space-y-4\">\n {editingUserId && (\n <UserForm\n mode=\"edit\"\n userId={editingUserId}\n open\n onClose={() => setEditingUserId(null)}\n />\n )}\n <DisplayTable withTableBorder>\n <Thead>\n <Tr>\n <Th>Name</Th>\n <Th>Contact</Th>\n <Th>Type</Th>\n <Th>Roles</Th>\n <Th>Activity</Th>\n <Th className=\"w-[50px]\" />\n </Tr>\n </Thead>\n <Tbody>\n {data.map((user) => (\n <UserTableRow\n key={user.id}\n user={user}\n onEdit={setEditingUserId}\n locale={locale}\n defaultLanguage={defaultLanguage}\n />\n ))}\n </Tbody>\n </DisplayTable>\n <DataTablePagination\n pageIndex={pageIndex}\n pageSize={pageSize}\n pageCount={pageCount}\n totalRows={totalRows}\n onPageChange={onPageChange}\n onPageSizeChange={onPageSizeChange}\n />\n </div>\n );\n }\n return (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\">\n {data.map((user) => (\n <UserCard key={user.id} user={user} />\n ))}\n </div>\n <DataTablePagination\n pageIndex={pageIndex}\n pageSize={pageSize}\n pageCount={pageCount}\n totalRows={totalRows}\n onPageChange={onPageChange}\n onPageSizeChange={onPageSizeChange}\n />\n </div>\n );\n}\n"],"mappings":"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","names":["IconUsers","useState","Badge","Card","CardContent","CardHeader","CardTitle","jsx","jsxs","Card","CardHeader","CardTitle","Badge","CardContent","zodResolver","EntityDrawer","EntityFormActions","Form","FormControl","FormField","FormItem","FormLabel","FormMessage","Input","useQueryClient","useEffect","useState","useForm","toast","z","jsx","jsxs","schema","z","useQueryClient","useState","useForm","zodResolver","useEffect","toast","EntityDrawer","Form","FormField","FormItem","FormLabel","FormControl","Input","FormMessage","EntityFormActions","Badge","IconUsers","useState","jsx","jsxs","Badge","useState","IconUsers","jsx","jsxs","capitalize","useState","IconUsers"]}