@famgia/omnify-react-sso 2.2.3 → 2.2.4

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 (55) hide show
  1. package/dist/ant/index.cjs +3235 -0
  2. package/dist/ant/index.cjs.map +1 -0
  3. package/dist/ant/index.d.cts +685 -0
  4. package/dist/ant/index.d.ts +685 -0
  5. package/dist/ant/index.js +3268 -0
  6. package/dist/ant/index.js.map +1 -0
  7. package/dist/core/index.cjs +2432 -0
  8. package/dist/core/index.cjs.map +1 -0
  9. package/dist/core/index.d.cts +112 -0
  10. package/dist/core/index.d.ts +112 -0
  11. package/dist/core/index.js +2360 -0
  12. package/dist/core/index.js.map +1 -0
  13. package/dist/{testing → core/testing}/index.cjs +1 -1
  14. package/dist/core/testing/index.cjs.map +1 -0
  15. package/dist/{testing → core/testing}/index.d.cts +1 -1
  16. package/dist/{testing → core/testing}/index.d.ts +1 -1
  17. package/dist/{testing → core/testing}/index.js +1 -1
  18. package/dist/core/testing/index.js.map +1 -0
  19. package/dist/index-CHuDTvHg.d.ts +2250 -0
  20. package/dist/index-DVssHZFD.d.cts +2250 -0
  21. package/dist/index.cjs +2464 -784
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +10 -1822
  24. package/dist/index.d.ts +10 -1822
  25. package/dist/index.js +2528 -771
  26. package/dist/index.js.map +1 -1
  27. package/dist/{types-bD5deLxs.d.cts → types-BxClyvTX.d.cts} +2 -3
  28. package/dist/{types-bD5deLxs.d.ts → types-BxClyvTX.d.ts} +2 -3
  29. package/dist/userService-DH9-vPSg.d.cts +269 -0
  30. package/dist/userService-DH9-vPSg.d.ts +269 -0
  31. package/package.json +27 -48
  32. package/dist/@omnify-base/package.json +0 -16
  33. package/dist/@omnify-base/schemas/Branch.ts +0 -131
  34. package/dist/@omnify-base/schemas/BranchCache.ts +0 -131
  35. package/dist/@omnify-base/schemas/OrganizationCache.ts +0 -117
  36. package/dist/@omnify-base/schemas/Permission.ts +0 -114
  37. package/dist/@omnify-base/schemas/Role.ts +0 -128
  38. package/dist/@omnify-base/schemas/RolePermission.ts +0 -97
  39. package/dist/@omnify-base/schemas/Team.ts +0 -110
  40. package/dist/@omnify-base/schemas/TeamCache.ts +0 -110
  41. package/dist/@omnify-base/schemas/TeamPermission.ts +0 -109
  42. package/dist/@omnify-base/schemas/User.ts +0 -135
  43. package/dist/@omnify-base/schemas/UserCache.ts +0 -142
  44. package/dist/@omnify-base/schemas/common.ts +0 -47
  45. package/dist/@omnify-base/schemas/i18n.ts +0 -118
  46. package/dist/schemas/index.cjs +0 -645
  47. package/dist/schemas/index.cjs.map +0 -1
  48. package/dist/schemas/index.d.cts +0 -260
  49. package/dist/schemas/index.d.ts +0 -260
  50. package/dist/schemas/index.js +0 -557
  51. package/dist/schemas/index.js.map +0 -1
  52. package/dist/testing/index.cjs.map +0 -1
  53. package/dist/testing/index.js.map +0 -1
  54. package/scripts/build-schemas.ts +0 -191
  55. package/scripts/postinstall.cjs +0 -43
@@ -0,0 +1,3268 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/ant/components/SsoCallback/SsoCallback.tsx
9
+ import { useEffect, useRef, useState } from "react";
10
+
11
+ // src/core/context/SsoContext.tsx
12
+ import { createContext, useContext } from "react";
13
+ var SsoContext = createContext(null);
14
+ function useSsoContext() {
15
+ const context = useContext(SsoContext);
16
+ if (!context) {
17
+ throw new Error("useSsoContext must be used within a SsoProvider");
18
+ }
19
+ return context;
20
+ }
21
+
22
+ // src/ant/components/SsoCallback/SsoCallback.tsx
23
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
24
+ function transformUser(data) {
25
+ return {
26
+ id: data.id,
27
+ consoleUserId: data.console_user_id,
28
+ email: data.email,
29
+ name: data.name
30
+ };
31
+ }
32
+ function transformOrganizations(data) {
33
+ return data.map((org) => ({
34
+ id: org.organization_id,
35
+ slug: org.organization_slug,
36
+ name: org.organization_name,
37
+ orgRole: org.org_role,
38
+ serviceRole: org.service_role
39
+ }));
40
+ }
41
+ function DefaultLoading() {
42
+ return /* @__PURE__ */ jsx("div", { style: {
43
+ display: "flex",
44
+ justifyContent: "center",
45
+ alignItems: "center",
46
+ minHeight: "200px"
47
+ }, children: /* @__PURE__ */ jsx("div", { children: "Authenticating..." }) });
48
+ }
49
+ function DefaultError({ error }) {
50
+ return /* @__PURE__ */ jsxs("div", { style: {
51
+ display: "flex",
52
+ flexDirection: "column",
53
+ justifyContent: "center",
54
+ alignItems: "center",
55
+ minHeight: "200px",
56
+ color: "red"
57
+ }, children: [
58
+ /* @__PURE__ */ jsx("div", { children: "Authentication Error" }),
59
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "0.875rem", marginTop: "0.5rem" }, children: error.message })
60
+ ] });
61
+ }
62
+ function SsoCallback({
63
+ onSuccess,
64
+ onError,
65
+ redirectTo = "/",
66
+ loadingComponent,
67
+ errorComponent
68
+ }) {
69
+ const { config, refreshUser } = useSsoContext();
70
+ const [error, setError] = useState(null);
71
+ const [isProcessing, setIsProcessing] = useState(true);
72
+ const isProcessingRef = useRef(false);
73
+ useEffect(() => {
74
+ if (isProcessingRef.current) {
75
+ return;
76
+ }
77
+ isProcessingRef.current = true;
78
+ const processCallback = async () => {
79
+ try {
80
+ const urlParams = new URLSearchParams(window.location.search);
81
+ const code = urlParams.get("code");
82
+ const redirectParam = urlParams.get("redirect");
83
+ if (!code) {
84
+ throw new Error("No authorization code received");
85
+ }
86
+ await fetch(`${config.apiUrl}/sanctum/csrf-cookie`, {
87
+ credentials: "include"
88
+ });
89
+ const xsrfToken = document.cookie.split("; ").find((row) => row.startsWith("XSRF-TOKEN="))?.split("=")[1];
90
+ const response = await fetch(`${config.apiUrl}/api/sso/callback`, {
91
+ method: "POST",
92
+ headers: {
93
+ "Content-Type": "application/json",
94
+ "Accept": "application/json",
95
+ ...xsrfToken ? { "X-XSRF-TOKEN": decodeURIComponent(xsrfToken) } : {}
96
+ },
97
+ credentials: "include",
98
+ body: JSON.stringify({ code })
99
+ });
100
+ if (!response.ok) {
101
+ const errorData = await response.json().catch(() => ({}));
102
+ throw new Error(errorData.message || "Failed to authenticate");
103
+ }
104
+ const data = await response.json();
105
+ const user = transformUser(data.user);
106
+ const organizations = transformOrganizations(data.organizations);
107
+ await refreshUser();
108
+ onSuccess?.(user, organizations);
109
+ const finalRedirect = redirectParam || redirectTo;
110
+ window.location.href = finalRedirect;
111
+ } catch (err) {
112
+ const error2 = err instanceof Error ? err : new Error("Authentication failed");
113
+ setError(error2);
114
+ onError?.(error2);
115
+ isProcessingRef.current = false;
116
+ } finally {
117
+ setIsProcessing(false);
118
+ }
119
+ };
120
+ processCallback();
121
+ }, []);
122
+ if (error) {
123
+ if (errorComponent) {
124
+ return /* @__PURE__ */ jsx(Fragment, { children: errorComponent(error) });
125
+ }
126
+ return /* @__PURE__ */ jsx(DefaultError, { error });
127
+ }
128
+ if (isProcessing) {
129
+ if (loadingComponent) {
130
+ return /* @__PURE__ */ jsx(Fragment, { children: loadingComponent });
131
+ }
132
+ return /* @__PURE__ */ jsx(DefaultLoading, {});
133
+ }
134
+ return null;
135
+ }
136
+
137
+ // src/ant/components/OrganizationSwitcher/OrganizationSwitcher.tsx
138
+ import React2, { useCallback as useCallback2, useMemo as useMemo2 } from "react";
139
+ import { Dropdown, Button, Space, Typography, Badge } from "antd";
140
+ import { SwapOutlined, CheckOutlined } from "@ant-design/icons";
141
+
142
+ // src/core/hooks/useOrganization.ts
143
+ import { useCallback, useMemo } from "react";
144
+ var ROLE_LEVELS = {
145
+ admin: 100,
146
+ manager: 50,
147
+ member: 10
148
+ };
149
+ function useOrganization() {
150
+ const { organizations, currentOrg, switchOrg } = useSsoContext();
151
+ const hasMultipleOrgs = organizations.length > 1;
152
+ const currentRole = currentOrg?.serviceRole ?? null;
153
+ const hasRole = useCallback(
154
+ (role) => {
155
+ if (!currentRole) return false;
156
+ const requiredLevel = ROLE_LEVELS[role] ?? 0;
157
+ const userLevel = ROLE_LEVELS[currentRole] ?? 0;
158
+ return userLevel >= requiredLevel;
159
+ },
160
+ [currentRole]
161
+ );
162
+ const handleSwitchOrg = useCallback(
163
+ (orgId) => {
164
+ switchOrg(orgId);
165
+ },
166
+ [switchOrg]
167
+ );
168
+ return useMemo(
169
+ () => ({
170
+ organizations,
171
+ currentOrg,
172
+ hasMultipleOrgs,
173
+ switchOrg: handleSwitchOrg,
174
+ currentRole,
175
+ hasRole
176
+ }),
177
+ [organizations, currentOrg, hasMultipleOrgs, handleSwitchOrg, currentRole, hasRole]
178
+ );
179
+ }
180
+
181
+ // src/ant/components/OrganizationSwitcher/OrganizationSwitcher.tsx
182
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
183
+ var { Text } = Typography;
184
+ function OrganizationSwitcher({
185
+ className,
186
+ renderTrigger,
187
+ renderOption,
188
+ onChange
189
+ }) {
190
+ const { organizations, currentOrg, hasMultipleOrgs, switchOrg } = useOrganization();
191
+ const [isOpen, setIsOpen] = React2.useState(false);
192
+ const handleSelect = useCallback2(
193
+ (org) => {
194
+ switchOrg(org.slug);
195
+ setIsOpen(false);
196
+ onChange?.(org);
197
+ },
198
+ [switchOrg, onChange]
199
+ );
200
+ const menuItems = useMemo2(() => {
201
+ return organizations.map((org) => {
202
+ const isSelected = currentOrg?.slug === org.slug;
203
+ if (renderOption) {
204
+ return {
205
+ key: org.slug,
206
+ label: /* @__PURE__ */ jsx2("div", { onClick: () => handleSelect(org), children: renderOption(org, isSelected) })
207
+ };
208
+ }
209
+ return {
210
+ key: org.slug,
211
+ label: /* @__PURE__ */ jsxs2(Space, { style: { width: "100%", justifyContent: "space-between" }, children: [
212
+ /* @__PURE__ */ jsxs2(Space, { direction: "vertical", size: 0, children: [
213
+ /* @__PURE__ */ jsx2(Text, { strong: isSelected, children: org.name }),
214
+ org.serviceRole && /* @__PURE__ */ jsx2(Text, { type: "secondary", style: { fontSize: 12 }, children: org.serviceRole })
215
+ ] }),
216
+ isSelected && /* @__PURE__ */ jsx2(CheckOutlined, { style: { color: "#1890ff" } })
217
+ ] }),
218
+ onClick: () => handleSelect(org)
219
+ };
220
+ });
221
+ }, [organizations, currentOrg, renderOption, handleSelect]);
222
+ if (!hasMultipleOrgs) {
223
+ return null;
224
+ }
225
+ if (renderTrigger) {
226
+ return /* @__PURE__ */ jsx2(
227
+ Dropdown,
228
+ {
229
+ menu: { items: menuItems },
230
+ trigger: ["click"],
231
+ open: isOpen,
232
+ onOpenChange: setIsOpen,
233
+ className,
234
+ children: /* @__PURE__ */ jsx2("div", { style: { cursor: "pointer" }, children: renderTrigger(currentOrg, isOpen) })
235
+ }
236
+ );
237
+ }
238
+ return /* @__PURE__ */ jsx2(
239
+ Dropdown,
240
+ {
241
+ menu: { items: menuItems },
242
+ trigger: ["click"],
243
+ open: isOpen,
244
+ onOpenChange: setIsOpen,
245
+ className,
246
+ children: /* @__PURE__ */ jsx2(Button, { children: /* @__PURE__ */ jsxs2(Space, { children: [
247
+ /* @__PURE__ */ jsx2(Badge, { status: "success" }),
248
+ /* @__PURE__ */ jsx2("span", { children: currentOrg?.name ?? "Select Organization" }),
249
+ /* @__PURE__ */ jsx2(SwapOutlined, {})
250
+ ] }) })
251
+ }
252
+ );
253
+ }
254
+
255
+ // src/ant/components/ProtectedRoute/ProtectedRoute.tsx
256
+ import { useEffect as useEffect2 } from "react";
257
+
258
+ // src/core/hooks/useAuth.ts
259
+ import { useCallback as useCallback3 } from "react";
260
+ function useAuth() {
261
+ const { user, isLoading, isAuthenticated, login, logout, globalLogout, refreshUser } = useSsoContext();
262
+ const handleLogin = useCallback3(
263
+ (redirectTo) => {
264
+ login(redirectTo);
265
+ },
266
+ [login]
267
+ );
268
+ const handleLogout = useCallback3(async () => {
269
+ await logout();
270
+ }, [logout]);
271
+ const handleGlobalLogout = useCallback3(
272
+ (redirectTo) => {
273
+ globalLogout(redirectTo);
274
+ },
275
+ [globalLogout]
276
+ );
277
+ return {
278
+ user,
279
+ isLoading,
280
+ isAuthenticated,
281
+ login: handleLogin,
282
+ logout: handleLogout,
283
+ globalLogout: handleGlobalLogout,
284
+ refreshUser
285
+ };
286
+ }
287
+
288
+ // src/ant/components/ProtectedRoute/ProtectedRoute.tsx
289
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
290
+ function DefaultLoading2() {
291
+ return /* @__PURE__ */ jsx3("div", { style: {
292
+ display: "flex",
293
+ justifyContent: "center",
294
+ alignItems: "center",
295
+ minHeight: "200px"
296
+ }, children: /* @__PURE__ */ jsx3("div", { children: "Loading..." }) });
297
+ }
298
+ function DefaultLoginFallback({ login }) {
299
+ return /* @__PURE__ */ jsxs3("div", { style: {
300
+ display: "flex",
301
+ flexDirection: "column",
302
+ justifyContent: "center",
303
+ alignItems: "center",
304
+ minHeight: "200px",
305
+ gap: "1rem"
306
+ }, children: [
307
+ /* @__PURE__ */ jsx3("div", { children: "Please log in to continue" }),
308
+ /* @__PURE__ */ jsx3(
309
+ "button",
310
+ {
311
+ onClick: login,
312
+ style: {
313
+ padding: "0.5rem 1rem",
314
+ background: "#0070f3",
315
+ color: "white",
316
+ border: "none",
317
+ borderRadius: "0.375rem",
318
+ cursor: "pointer"
319
+ },
320
+ children: "Log In"
321
+ }
322
+ )
323
+ ] });
324
+ }
325
+ function DefaultAccessDenied({ reason }) {
326
+ return /* @__PURE__ */ jsxs3("div", { style: {
327
+ display: "flex",
328
+ flexDirection: "column",
329
+ justifyContent: "center",
330
+ alignItems: "center",
331
+ minHeight: "200px",
332
+ color: "#dc2626"
333
+ }, children: [
334
+ /* @__PURE__ */ jsx3("div", { style: { fontSize: "1.5rem", fontWeight: 600 }, children: "Access Denied" }),
335
+ /* @__PURE__ */ jsx3("div", { style: { marginTop: "0.5rem" }, children: reason })
336
+ ] });
337
+ }
338
+ function ProtectedRoute({
339
+ children,
340
+ fallback,
341
+ loginFallback,
342
+ requiredRole,
343
+ requiredPermission,
344
+ onAccessDenied
345
+ }) {
346
+ const { user, isLoading, isAuthenticated, login } = useAuth();
347
+ const { hasRole, currentOrg } = useOrganization();
348
+ useEffect2(() => {
349
+ if (isLoading) return;
350
+ if (!isAuthenticated) {
351
+ onAccessDenied?.("unauthenticated");
352
+ } else if (requiredRole && !hasRole(requiredRole)) {
353
+ onAccessDenied?.("insufficient_role");
354
+ }
355
+ }, [isLoading, isAuthenticated, requiredRole, hasRole, onAccessDenied]);
356
+ if (isLoading) {
357
+ return /* @__PURE__ */ jsx3(Fragment2, { children: fallback ?? /* @__PURE__ */ jsx3(DefaultLoading2, {}) });
358
+ }
359
+ if (!isAuthenticated) {
360
+ if (loginFallback) {
361
+ return /* @__PURE__ */ jsx3(Fragment2, { children: loginFallback });
362
+ }
363
+ return /* @__PURE__ */ jsx3(DefaultLoginFallback, { login: () => login() });
364
+ }
365
+ if (requiredRole && !hasRole(requiredRole)) {
366
+ return /* @__PURE__ */ jsx3(
367
+ DefaultAccessDenied,
368
+ {
369
+ reason: `This page requires ${requiredRole} role. Your role: ${currentOrg?.serviceRole ?? "none"}`
370
+ }
371
+ );
372
+ }
373
+ return /* @__PURE__ */ jsx3(Fragment2, { children });
374
+ }
375
+
376
+ // src/ant/components/OrgBranchSelectorModal/OrgBranchSelectorModal.tsx
377
+ import { useCallback as useCallback4, useEffect as useEffect3, useMemo as useMemo3, useState as useState2 } from "react";
378
+ import { Modal, Select, Form, Space as Space2, Typography as Typography2, Spin, Alert, Badge as Badge2 } from "antd";
379
+ import { BankOutlined, ApartmentOutlined, CheckCircleFilled } from "@ant-design/icons";
380
+ import { useQuery } from "@tanstack/react-query";
381
+
382
+ // src/core/services/utils.ts
383
+ function getXsrfToken() {
384
+ if (typeof document === "undefined") return void 0;
385
+ return document.cookie.split("; ").find((row) => row.startsWith("XSRF-TOKEN="))?.split("=")[1];
386
+ }
387
+ function buildHeaders(orgId) {
388
+ const headers = {
389
+ "Content-Type": "application/json",
390
+ Accept: "application/json"
391
+ };
392
+ const xsrfToken = getXsrfToken();
393
+ if (xsrfToken) {
394
+ headers["X-XSRF-TOKEN"] = decodeURIComponent(xsrfToken);
395
+ }
396
+ if (orgId) {
397
+ headers["X-Organization-Id"] = orgId;
398
+ }
399
+ return headers;
400
+ }
401
+ async function request(apiUrl, path, options = {}) {
402
+ const response = await fetch(`${apiUrl}${path}`, {
403
+ ...options,
404
+ credentials: "include"
405
+ });
406
+ if (!response.ok) {
407
+ const error = await response.json().catch(() => ({}));
408
+ throw new Error(error.message || `HTTP ${response.status}`);
409
+ }
410
+ if (response.status === 204) {
411
+ return void 0;
412
+ }
413
+ return response.json();
414
+ }
415
+
416
+ // src/core/services/branchService.ts
417
+ function createBranchService(config) {
418
+ const { apiUrl } = config;
419
+ return {
420
+ /**
421
+ * Get branches for current user in organization
422
+ * GET /api/sso/branches
423
+ * @param orgId - Organization ID or slug (sent via X-Organization-Id header)
424
+ */
425
+ list: async (orgId) => {
426
+ return request(apiUrl, `/api/sso/branches`, {
427
+ headers: buildHeaders(orgId)
428
+ });
429
+ },
430
+ /**
431
+ * Get a specific branch by ID
432
+ * GET /api/sso/branches/{id}
433
+ */
434
+ get: async (branchId) => {
435
+ const response = await request(
436
+ apiUrl,
437
+ `/api/sso/branches/${branchId}`,
438
+ { headers: buildHeaders() }
439
+ );
440
+ return "data" in response ? response.data : response;
441
+ },
442
+ /**
443
+ * Get headquarters branch for organization
444
+ * @param orgId - Organization ID or slug (sent via X-Organization-Id header)
445
+ */
446
+ getHeadquarters: async (orgId) => {
447
+ try {
448
+ const data = await request(
449
+ apiUrl,
450
+ `/api/sso/branches`,
451
+ { headers: buildHeaders(orgId) }
452
+ );
453
+ return data.branches.find((b) => b.is_headquarters) ?? null;
454
+ } catch {
455
+ return null;
456
+ }
457
+ },
458
+ /**
459
+ * Get primary branch for current user
460
+ * @param orgId - Organization ID or slug (sent via X-Organization-Id header)
461
+ */
462
+ getPrimary: async (orgId) => {
463
+ try {
464
+ const data = await request(
465
+ apiUrl,
466
+ `/api/sso/branches`,
467
+ { headers: buildHeaders(orgId) }
468
+ );
469
+ if (data.primary_branch_id) {
470
+ return data.branches.find((b) => b.id === data.primary_branch_id) ?? null;
471
+ }
472
+ return null;
473
+ } catch {
474
+ return null;
475
+ }
476
+ }
477
+ };
478
+ }
479
+
480
+ // src/core/queryKeys.ts
481
+ var ssoQueryKeys = {
482
+ all: ["sso"],
483
+ // =========================================================================
484
+ // Auth (authService)
485
+ // =========================================================================
486
+ auth: {
487
+ all: () => [...ssoQueryKeys.all, "auth"],
488
+ user: () => [...ssoQueryKeys.auth.all(), "user"],
489
+ globalLogoutUrl: (redirectUri) => [...ssoQueryKeys.auth.all(), "global-logout-url", redirectUri]
490
+ },
491
+ // =========================================================================
492
+ // Tokens (tokenService)
493
+ // =========================================================================
494
+ tokens: {
495
+ all: () => [...ssoQueryKeys.all, "tokens"],
496
+ list: () => [...ssoQueryKeys.tokens.all(), "list"]
497
+ },
498
+ // =========================================================================
499
+ // Roles (roleService)
500
+ // =========================================================================
501
+ roles: {
502
+ all: () => [...ssoQueryKeys.all, "roles"],
503
+ list: () => [...ssoQueryKeys.roles.all(), "list"],
504
+ detail: (id) => [...ssoQueryKeys.roles.all(), "detail", id],
505
+ permissions: (id) => [...ssoQueryKeys.roles.all(), id, "permissions"]
506
+ },
507
+ // =========================================================================
508
+ // Permissions (permissionService)
509
+ // =========================================================================
510
+ permissions: {
511
+ all: () => [...ssoQueryKeys.all, "permissions"],
512
+ list: (params) => [...ssoQueryKeys.permissions.all(), "list", params],
513
+ detail: (id) => [...ssoQueryKeys.permissions.all(), "detail", id],
514
+ matrix: () => [...ssoQueryKeys.permissions.all(), "matrix"]
515
+ },
516
+ // =========================================================================
517
+ // Teams (teamService)
518
+ // =========================================================================
519
+ teams: {
520
+ all: () => [...ssoQueryKeys.all, "teams"],
521
+ list: () => [...ssoQueryKeys.teams.all(), "list"],
522
+ permissions: (teamId) => [...ssoQueryKeys.teams.all(), teamId, "permissions"],
523
+ orphaned: () => [...ssoQueryKeys.teams.all(), "orphaned"]
524
+ },
525
+ // =========================================================================
526
+ // User Roles (userRoleService) - Scoped Role Assignments
527
+ // =========================================================================
528
+ userRoles: {
529
+ all: () => [...ssoQueryKeys.all, "user-roles"],
530
+ list: (userId) => [...ssoQueryKeys.userRoles.all(), userId],
531
+ byBranch: (userId, orgId, branchId) => [...ssoQueryKeys.userRoles.all(), userId, orgId, branchId]
532
+ },
533
+ // =========================================================================
534
+ // Branches (branchService)
535
+ // =========================================================================
536
+ branches: {
537
+ all: () => [...ssoQueryKeys.all, "branches"],
538
+ list: (orgId) => [...ssoQueryKeys.branches.all(), "list", orgId],
539
+ detail: (branchId) => [...ssoQueryKeys.branches.all(), "detail", branchId],
540
+ headquarters: (orgId) => [...ssoQueryKeys.branches.all(), "headquarters", orgId],
541
+ primary: (orgId) => [...ssoQueryKeys.branches.all(), "primary", orgId]
542
+ },
543
+ // =========================================================================
544
+ // Admin variants (with org context)
545
+ // =========================================================================
546
+ admin: {
547
+ roles: {
548
+ all: (orgId) => [...ssoQueryKeys.all, "admin", orgId, "roles"],
549
+ list: (orgId) => [...ssoQueryKeys.admin.roles.all(orgId), "list"],
550
+ detail: (orgId, id) => [...ssoQueryKeys.admin.roles.all(orgId), "detail", id],
551
+ permissions: (orgId, id) => [...ssoQueryKeys.admin.roles.all(orgId), id, "permissions"]
552
+ },
553
+ permissions: {
554
+ all: (orgId) => [...ssoQueryKeys.all, "admin", orgId, "permissions"],
555
+ list: (orgId, params) => [...ssoQueryKeys.admin.permissions.all(orgId), "list", params],
556
+ detail: (orgId, id) => [...ssoQueryKeys.admin.permissions.all(orgId), "detail", id],
557
+ matrix: (orgId) => [...ssoQueryKeys.admin.permissions.all(orgId), "matrix"]
558
+ },
559
+ teams: {
560
+ all: (orgId) => [...ssoQueryKeys.all, "admin", orgId, "teams"],
561
+ list: (orgId) => [...ssoQueryKeys.admin.teams.all(orgId), "list"],
562
+ permissions: (orgId, teamId) => [...ssoQueryKeys.admin.teams.all(orgId), teamId, "permissions"],
563
+ orphaned: (orgId) => [...ssoQueryKeys.admin.teams.all(orgId), "orphaned"]
564
+ },
565
+ userRoles: {
566
+ all: (orgId) => [...ssoQueryKeys.all, "admin", orgId, "user-roles"],
567
+ list: (orgId, userId) => [...ssoQueryKeys.admin.userRoles.all(orgId), userId],
568
+ byBranch: (orgId, userId, consoleOrgId, branchId) => [...ssoQueryKeys.admin.userRoles.all(orgId), userId, consoleOrgId, branchId]
569
+ },
570
+ users: {
571
+ all: (orgId) => [...ssoQueryKeys.all, "admin", orgId, "users"],
572
+ list: (orgId, params) => [...ssoQueryKeys.admin.users.all(orgId), "list", params],
573
+ detail: (orgId, id) => [...ssoQueryKeys.admin.users.all(orgId), "detail", id],
574
+ permissions: (orgId, userId, consoleOrgId, branchId) => [...ssoQueryKeys.admin.users.all(orgId), userId, "permissions", consoleOrgId, branchId]
575
+ }
576
+ }
577
+ };
578
+
579
+ // src/ant/components/OrgBranchSelectorModal/OrgBranchSelectorModal.tsx
580
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
581
+ var { Text: Text2, Title } = Typography2;
582
+ function OrgBranchSelectorModal({
583
+ open,
584
+ onClose,
585
+ onConfirm,
586
+ title = "Select Organization & Branch",
587
+ requireBranch = true,
588
+ loadingComponent
589
+ }) {
590
+ const { config } = useSsoContext();
591
+ const { organizations, currentOrg, hasMultipleOrgs } = useOrganization();
592
+ const [form] = Form.useForm();
593
+ const [selectedOrgSlug, setSelectedOrgSlug] = useState2(
594
+ currentOrg?.slug ?? null
595
+ );
596
+ const branchService = useMemo3(
597
+ () => createBranchService({ apiUrl: config.apiUrl }),
598
+ [config.apiUrl]
599
+ );
600
+ const {
601
+ data: branchesData,
602
+ isLoading: branchesLoading,
603
+ error: branchesError
604
+ } = useQuery({
605
+ queryKey: ssoQueryKeys.branches.list(selectedOrgSlug ?? void 0),
606
+ queryFn: () => branchService.list(selectedOrgSlug ?? void 0),
607
+ enabled: open && !!selectedOrgSlug
608
+ });
609
+ const branches = branchesData?.branches ?? [];
610
+ const hasMultipleBranches = branches.length > 1;
611
+ const selectedOrg = useMemo3(
612
+ () => organizations.find((o) => o.slug === selectedOrgSlug) ?? null,
613
+ [organizations, selectedOrgSlug]
614
+ );
615
+ useEffect3(() => {
616
+ if (!open) return;
617
+ if (organizations.length === 1 && !selectedOrgSlug) {
618
+ setSelectedOrgSlug(organizations[0].slug);
619
+ form.setFieldValue("organization_id", organizations[0].id);
620
+ } else if (currentOrg && !selectedOrgSlug) {
621
+ setSelectedOrgSlug(currentOrg.slug);
622
+ form.setFieldValue("organization_id", currentOrg.id);
623
+ }
624
+ }, [open, organizations, currentOrg, selectedOrgSlug, form]);
625
+ useEffect3(() => {
626
+ if (!open || branchesLoading) return;
627
+ if (branches.length === 1) {
628
+ form.setFieldValue("branch_id", branches[0].id);
629
+ } else if (branches.length > 0) {
630
+ const primaryId = branchesData?.primary_branch_id;
631
+ if (primaryId) {
632
+ form.setFieldValue("branch_id", primaryId);
633
+ } else {
634
+ const hq = branches.find((b) => b.is_headquarters);
635
+ if (hq) {
636
+ form.setFieldValue("branch_id", hq.id);
637
+ }
638
+ }
639
+ }
640
+ }, [open, branches, branchesLoading, branchesData, form]);
641
+ useEffect3(() => {
642
+ if (!open || branchesLoading) return;
643
+ const orgId = form.getFieldValue("organization_id");
644
+ const branchId = form.getFieldValue("branch_id");
645
+ if (orgId && branchId && !hasMultipleOrgs && !hasMultipleBranches) {
646
+ const timer = setTimeout(() => {
647
+ onConfirm(orgId, branchId);
648
+ }, 100);
649
+ return () => clearTimeout(timer);
650
+ }
651
+ }, [open, branchesLoading, hasMultipleOrgs, hasMultipleBranches, form, onConfirm]);
652
+ const handleOrgChange = useCallback4((orgId) => {
653
+ const org = organizations.find((o) => o.id === orgId);
654
+ if (org) {
655
+ setSelectedOrgSlug(org.slug);
656
+ form.setFieldValue("branch_id", void 0);
657
+ }
658
+ }, [organizations, form]);
659
+ const handleSubmit = useCallback4(() => {
660
+ form.validateFields().then((values) => {
661
+ onConfirm(values.organization_id, values.branch_id);
662
+ });
663
+ }, [form, onConfirm]);
664
+ const handleClose = useCallback4(() => {
665
+ form.resetFields();
666
+ setSelectedOrgSlug(currentOrg?.slug ?? null);
667
+ onClose();
668
+ }, [form, currentOrg, onClose]);
669
+ const isInitialLoading = open && (!organizations.length || selectedOrgSlug && branchesLoading && !branches.length);
670
+ const needsSelection = hasMultipleOrgs || hasMultipleBranches;
671
+ return /* @__PURE__ */ jsx4(
672
+ Modal,
673
+ {
674
+ title: /* @__PURE__ */ jsxs4(Space2, { children: [
675
+ /* @__PURE__ */ jsx4(BankOutlined, {}),
676
+ /* @__PURE__ */ jsx4("span", { children: title })
677
+ ] }),
678
+ open,
679
+ onCancel: handleClose,
680
+ onOk: handleSubmit,
681
+ okText: "Confirm",
682
+ cancelText: "Cancel",
683
+ destroyOnHidden: true,
684
+ width: 480,
685
+ children: isInitialLoading ? /* @__PURE__ */ jsxs4("div", { style: { textAlign: "center", padding: 40 }, children: [
686
+ loadingComponent ?? /* @__PURE__ */ jsx4(Spin, { size: "large" }),
687
+ /* @__PURE__ */ jsx4("div", { style: { marginTop: 16 }, children: /* @__PURE__ */ jsx4(Text2, { type: "secondary", children: "Loading..." }) })
688
+ ] }) : /* @__PURE__ */ jsxs4(
689
+ Form,
690
+ {
691
+ form,
692
+ layout: "vertical",
693
+ style: { marginTop: 16 },
694
+ children: [
695
+ branchesError && /* @__PURE__ */ jsx4(
696
+ Alert,
697
+ {
698
+ type: "error",
699
+ message: "Failed to load branches",
700
+ description: branchesError.message,
701
+ style: { marginBottom: 16 }
702
+ }
703
+ ),
704
+ /* @__PURE__ */ jsx4(
705
+ Form.Item,
706
+ {
707
+ name: "organization_id",
708
+ label: /* @__PURE__ */ jsxs4(Space2, { children: [
709
+ /* @__PURE__ */ jsx4(BankOutlined, {}),
710
+ /* @__PURE__ */ jsx4("span", { children: "Organization" }),
711
+ !hasMultipleOrgs && selectedOrg && /* @__PURE__ */ jsx4(Badge2, { status: "success", text: "Auto-selected" })
712
+ ] }),
713
+ rules: [{ required: true, message: "Please select an organization" }],
714
+ children: hasMultipleOrgs ? /* @__PURE__ */ jsx4(
715
+ Select,
716
+ {
717
+ placeholder: "Select organization",
718
+ onChange: handleOrgChange,
719
+ size: "large",
720
+ optionLabelProp: "label",
721
+ children: organizations.map((org) => /* @__PURE__ */ jsx4(
722
+ Select.Option,
723
+ {
724
+ value: org.id,
725
+ label: org.name,
726
+ children: /* @__PURE__ */ jsxs4(Space2, { style: { width: "100%", justifyContent: "space-between" }, children: [
727
+ /* @__PURE__ */ jsxs4("div", { children: [
728
+ /* @__PURE__ */ jsx4(Text2, { strong: true, children: org.name }),
729
+ org.serviceRole && /* @__PURE__ */ jsxs4(Text2, { type: "secondary", style: { marginLeft: 8, fontSize: 12 }, children: [
730
+ "(",
731
+ org.serviceRole,
732
+ ")"
733
+ ] })
734
+ ] }),
735
+ org.slug === currentOrg?.slug && /* @__PURE__ */ jsx4(CheckCircleFilled, { style: { color: "#52c41a" } })
736
+ ] })
737
+ },
738
+ org.id
739
+ ))
740
+ }
741
+ ) : /* @__PURE__ */ jsx4(
742
+ "div",
743
+ {
744
+ style: {
745
+ padding: "8px 12px",
746
+ background: "#f5f5f5",
747
+ borderRadius: 6,
748
+ border: "1px solid #d9d9d9"
749
+ },
750
+ children: /* @__PURE__ */ jsxs4(Space2, { children: [
751
+ /* @__PURE__ */ jsx4(BankOutlined, { style: { color: "#1677ff" } }),
752
+ /* @__PURE__ */ jsx4(Text2, { strong: true, children: selectedOrg?.name })
753
+ ] })
754
+ }
755
+ )
756
+ }
757
+ ),
758
+ selectedOrgSlug && /* @__PURE__ */ jsx4(
759
+ Form.Item,
760
+ {
761
+ name: "branch_id",
762
+ label: /* @__PURE__ */ jsxs4(Space2, { children: [
763
+ /* @__PURE__ */ jsx4(ApartmentOutlined, {}),
764
+ /* @__PURE__ */ jsx4("span", { children: "Branch" }),
765
+ !hasMultipleBranches && branches.length === 1 && /* @__PURE__ */ jsx4(Badge2, { status: "success", text: "Auto-selected" })
766
+ ] }),
767
+ rules: requireBranch ? [{ required: true, message: "Please select a branch" }] : void 0,
768
+ children: branchesLoading ? /* @__PURE__ */ jsxs4("div", { style: { padding: "8px 12px", textAlign: "center" }, children: [
769
+ /* @__PURE__ */ jsx4(Spin, { size: "small" }),
770
+ /* @__PURE__ */ jsx4(Text2, { type: "secondary", style: { marginLeft: 8 }, children: "Loading branches..." })
771
+ ] }) : hasMultipleBranches ? /* @__PURE__ */ jsx4(
772
+ Select,
773
+ {
774
+ placeholder: "Select branch",
775
+ size: "large",
776
+ optionLabelProp: "label",
777
+ children: branches.map((branch) => /* @__PURE__ */ jsx4(
778
+ Select.Option,
779
+ {
780
+ value: branch.id,
781
+ label: branch.name,
782
+ children: /* @__PURE__ */ jsxs4(Space2, { style: { width: "100%", justifyContent: "space-between" }, children: [
783
+ /* @__PURE__ */ jsxs4("div", { children: [
784
+ /* @__PURE__ */ jsx4(Text2, { strong: true, children: branch.name }),
785
+ /* @__PURE__ */ jsx4(Text2, { type: "secondary", style: { marginLeft: 8, fontSize: 12 }, children: branch.code })
786
+ ] }),
787
+ /* @__PURE__ */ jsxs4(Space2, { size: 4, children: [
788
+ branch.is_headquarters && /* @__PURE__ */ jsx4(Badge2, { color: "blue", text: "HQ" }),
789
+ branch.is_primary && /* @__PURE__ */ jsx4(Badge2, { color: "green", text: "Primary" })
790
+ ] })
791
+ ] })
792
+ },
793
+ branch.id
794
+ ))
795
+ }
796
+ ) : branches.length === 1 ? /* @__PURE__ */ jsx4(
797
+ "div",
798
+ {
799
+ style: {
800
+ padding: "8px 12px",
801
+ background: "#f5f5f5",
802
+ borderRadius: 6,
803
+ border: "1px solid #d9d9d9"
804
+ },
805
+ children: /* @__PURE__ */ jsxs4(Space2, { children: [
806
+ /* @__PURE__ */ jsx4(ApartmentOutlined, { style: { color: "#1677ff" } }),
807
+ /* @__PURE__ */ jsx4(Text2, { strong: true, children: branches[0].name }),
808
+ /* @__PURE__ */ jsxs4(Text2, { type: "secondary", children: [
809
+ "(",
810
+ branches[0].code,
811
+ ")"
812
+ ] })
813
+ ] })
814
+ }
815
+ ) : /* @__PURE__ */ jsx4(
816
+ Alert,
817
+ {
818
+ type: "warning",
819
+ message: "No branches available",
820
+ description: "You don't have access to any branches in this organization."
821
+ }
822
+ )
823
+ }
824
+ ),
825
+ !needsSelection && selectedOrg && branches.length > 0 && /* @__PURE__ */ jsx4(
826
+ Alert,
827
+ {
828
+ type: "info",
829
+ message: "Auto-selected",
830
+ description: `Using ${selectedOrg.name} / ${branches[0]?.name ?? "Default"}`,
831
+ icon: /* @__PURE__ */ jsx4(CheckCircleFilled, {}),
832
+ showIcon: true
833
+ }
834
+ )
835
+ ]
836
+ }
837
+ )
838
+ }
839
+ );
840
+ }
841
+
842
+ // src/ant/components/BranchGate/BranchGate.tsx
843
+ import React5, { useEffect as useEffect4, useState as useState3 } from "react";
844
+ import { Select as Select2, Space as Space3, Typography as Typography3, Badge as Badge3, Spin as Spin2, Button as Button2, Alert as Alert2 } from "antd";
845
+ import { BankOutlined as BankOutlined2, ApartmentOutlined as ApartmentOutlined2, CheckCircleFilled as CheckCircleFilled2 } from "@ant-design/icons";
846
+ import { useQuery as useQuery2 } from "@tanstack/react-query";
847
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
848
+ var { Text: Text3, Title: Title2 } = Typography3;
849
+ var DEFAULT_STORAGE_KEY = "omnify_branch_gate_selection";
850
+ function BranchGate({
851
+ children,
852
+ onSelectionChange,
853
+ storageKey = DEFAULT_STORAGE_KEY,
854
+ loadingComponent,
855
+ title,
856
+ description
857
+ }) {
858
+ const { config, isAuthenticated } = useSsoContext();
859
+ const { organizations, currentOrg, hasMultipleOrgs } = useOrganization();
860
+ const [storedSelection, setStoredSelection] = useState3(null);
861
+ const [isInitialized, setIsInitialized] = useState3(false);
862
+ const [tempOrgId, setTempOrgId] = useState3(null);
863
+ const [tempBranchId, setTempBranchId] = useState3(null);
864
+ const branchService = React5.useMemo(
865
+ () => createBranchService({ apiUrl: config.apiUrl }),
866
+ [config.apiUrl]
867
+ );
868
+ const activeOrgSlug = React5.useMemo(() => {
869
+ if (tempOrgId) {
870
+ return organizations.find((o) => String(o.id) === tempOrgId)?.slug;
871
+ }
872
+ return storedSelection?.orgId ?? currentOrg?.slug;
873
+ }, [tempOrgId, organizations, storedSelection, currentOrg]);
874
+ const { data: branchesData, isLoading: branchesLoading } = useQuery2({
875
+ queryKey: ssoQueryKeys.branches.list(activeOrgSlug),
876
+ queryFn: () => branchService.list(activeOrgSlug),
877
+ enabled: isAuthenticated && !!activeOrgSlug
878
+ });
879
+ const branches = branchesData?.branches ?? [];
880
+ const hasMultipleBranches = branches.length > 1;
881
+ useEffect4(() => {
882
+ if (typeof window === "undefined") return;
883
+ const saved = localStorage.getItem(storageKey);
884
+ if (saved) {
885
+ try {
886
+ const parsed = JSON.parse(saved);
887
+ setStoredSelection(parsed);
888
+ onSelectionChange?.(parsed);
889
+ } catch {
890
+ localStorage.removeItem(storageKey);
891
+ }
892
+ }
893
+ setIsInitialized(true);
894
+ }, [storageKey, onSelectionChange]);
895
+ useEffect4(() => {
896
+ if (!isAuthenticated || !isInitialized || storedSelection) return;
897
+ if (organizations.length === 1 && !tempOrgId) {
898
+ setTempOrgId(String(organizations[0].id));
899
+ }
900
+ }, [isAuthenticated, isInitialized, organizations, storedSelection, tempOrgId]);
901
+ useEffect4(() => {
902
+ if (!tempOrgId || branchesLoading || storedSelection) return;
903
+ if (branches.length === 1 && !tempBranchId) {
904
+ setTempBranchId(String(branches[0].id));
905
+ } else if (branches.length > 0 && !tempBranchId) {
906
+ const primaryId = branchesData?.primary_branch_id;
907
+ if (primaryId) {
908
+ setTempBranchId(String(primaryId));
909
+ } else {
910
+ const hq = branches.find((b) => b.is_headquarters);
911
+ if (hq) {
912
+ setTempBranchId(String(hq.id));
913
+ }
914
+ }
915
+ }
916
+ }, [tempOrgId, branches, branchesLoading, branchesData, storedSelection, tempBranchId]);
917
+ useEffect4(() => {
918
+ if (storedSelection || !isInitialized) return;
919
+ if (!tempOrgId || !tempBranchId || branchesLoading) return;
920
+ if (!hasMultipleOrgs && !hasMultipleBranches) {
921
+ confirmSelection();
922
+ }
923
+ }, [tempOrgId, tempBranchId, branchesLoading, hasMultipleOrgs, hasMultipleBranches, storedSelection, isInitialized]);
924
+ const confirmSelection = React5.useCallback(() => {
925
+ if (!tempOrgId || !tempBranchId) return;
926
+ const org = organizations.find((o) => String(o.id) === tempOrgId);
927
+ const branch = branches.find((b) => String(b.id) === tempBranchId);
928
+ if (!org || !branch) return;
929
+ const selection = {
930
+ orgId: org.slug,
931
+ orgName: org.name,
932
+ branchId: String(branch.id),
933
+ branchName: branch.name,
934
+ branchCode: branch.code
935
+ };
936
+ localStorage.setItem(storageKey, JSON.stringify(selection));
937
+ setStoredSelection(selection);
938
+ onSelectionChange?.(selection);
939
+ setTempOrgId(null);
940
+ setTempBranchId(null);
941
+ }, [tempOrgId, tempBranchId, organizations, branches, storageKey, onSelectionChange]);
942
+ const clearSelection = React5.useCallback(() => {
943
+ localStorage.removeItem(storageKey);
944
+ setStoredSelection(null);
945
+ onSelectionChange?.(null);
946
+ }, [storageKey, onSelectionChange]);
947
+ const needsSelection = isAuthenticated && isInitialized && !storedSelection && (hasMultipleOrgs || hasMultipleBranches);
948
+ const isLoading = !isAuthenticated || !isInitialized || !!activeOrgSlug && branchesLoading && !storedSelection;
949
+ if (isLoading && !needsSelection) {
950
+ if (loadingComponent) {
951
+ return /* @__PURE__ */ jsx5(Fragment3, { children: loadingComponent });
952
+ }
953
+ return /* @__PURE__ */ jsx5("div", { style: {
954
+ display: "flex",
955
+ justifyContent: "center",
956
+ alignItems: "center",
957
+ minHeight: "100vh",
958
+ background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
959
+ }, children: /* @__PURE__ */ jsx5(Spin2, { size: "large" }) });
960
+ }
961
+ if (needsSelection) {
962
+ const canConfirm = tempOrgId && tempBranchId;
963
+ return /* @__PURE__ */ jsx5("div", { style: {
964
+ minHeight: "100vh",
965
+ background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
966
+ display: "flex",
967
+ alignItems: "center",
968
+ justifyContent: "center",
969
+ padding: 24
970
+ }, children: /* @__PURE__ */ jsxs5("div", { style: {
971
+ background: "#fff",
972
+ borderRadius: 16,
973
+ padding: 32,
974
+ maxWidth: 480,
975
+ width: "100%",
976
+ boxShadow: "0 20px 60px rgba(0,0,0,0.3)"
977
+ }, children: [
978
+ /* @__PURE__ */ jsxs5("div", { style: { textAlign: "center", marginBottom: 24 }, children: [
979
+ /* @__PURE__ */ jsx5("div", { style: {
980
+ width: 64,
981
+ height: 64,
982
+ borderRadius: "50%",
983
+ background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
984
+ display: "flex",
985
+ alignItems: "center",
986
+ justifyContent: "center",
987
+ margin: "0 auto 16px"
988
+ }, children: /* @__PURE__ */ jsx5(BankOutlined2, { style: { fontSize: 28, color: "#fff" } }) }),
989
+ /* @__PURE__ */ jsx5(Title2, { level: 3, style: { margin: 0 }, children: title ?? "Select Organization" }),
990
+ /* @__PURE__ */ jsx5(Text3, { type: "secondary", children: description ?? "Please select your organization and branch to continue" })
991
+ ] }),
992
+ /* @__PURE__ */ jsxs5("div", { style: { marginBottom: 20 }, children: [
993
+ /* @__PURE__ */ jsx5(Text3, { strong: true, style: { display: "block", marginBottom: 8 }, children: /* @__PURE__ */ jsxs5(Space3, { children: [
994
+ /* @__PURE__ */ jsx5(BankOutlined2, {}),
995
+ /* @__PURE__ */ jsx5("span", { children: "Organization" }),
996
+ !hasMultipleOrgs && /* @__PURE__ */ jsx5(Badge3, { status: "success", text: "Auto-selected" })
997
+ ] }) }),
998
+ hasMultipleOrgs ? /* @__PURE__ */ jsx5(
999
+ Select2,
1000
+ {
1001
+ value: tempOrgId,
1002
+ onChange: (value) => {
1003
+ setTempOrgId(String(value));
1004
+ setTempBranchId(null);
1005
+ },
1006
+ placeholder: "Select organization",
1007
+ size: "large",
1008
+ style: { width: "100%" },
1009
+ optionLabelProp: "label",
1010
+ children: organizations.map((org) => /* @__PURE__ */ jsx5(Select2.Option, { value: String(org.id), label: org.name, children: /* @__PURE__ */ jsx5(Space3, { style: { width: "100%", justifyContent: "space-between" }, children: /* @__PURE__ */ jsxs5("div", { children: [
1011
+ /* @__PURE__ */ jsx5(Text3, { strong: true, children: org.name }),
1012
+ org.serviceRole && /* @__PURE__ */ jsxs5(Text3, { type: "secondary", style: { marginLeft: 8, fontSize: 12 }, children: [
1013
+ "(",
1014
+ org.serviceRole,
1015
+ ")"
1016
+ ] })
1017
+ ] }) }) }, org.id))
1018
+ }
1019
+ ) : /* @__PURE__ */ jsx5("div", { style: {
1020
+ padding: "8px 12px",
1021
+ background: "#f5f5f5",
1022
+ borderRadius: 6,
1023
+ border: "1px solid #d9d9d9"
1024
+ }, children: /* @__PURE__ */ jsxs5(Space3, { children: [
1025
+ /* @__PURE__ */ jsx5(BankOutlined2, { style: { color: "#1677ff" } }),
1026
+ /* @__PURE__ */ jsx5(Text3, { strong: true, children: organizations[0]?.name })
1027
+ ] }) })
1028
+ ] }),
1029
+ tempOrgId && /* @__PURE__ */ jsxs5("div", { style: { marginBottom: 24 }, children: [
1030
+ /* @__PURE__ */ jsx5(Text3, { strong: true, style: { display: "block", marginBottom: 8 }, children: /* @__PURE__ */ jsxs5(Space3, { children: [
1031
+ /* @__PURE__ */ jsx5(ApartmentOutlined2, {}),
1032
+ /* @__PURE__ */ jsx5("span", { children: "Branch" }),
1033
+ !hasMultipleBranches && branches.length === 1 && /* @__PURE__ */ jsx5(Badge3, { status: "success", text: "Auto-selected" })
1034
+ ] }) }),
1035
+ branchesLoading ? /* @__PURE__ */ jsxs5("div", { style: { padding: "12px", textAlign: "center" }, children: [
1036
+ /* @__PURE__ */ jsx5(Spin2, { size: "small" }),
1037
+ /* @__PURE__ */ jsx5(Text3, { type: "secondary", style: { marginLeft: 8 }, children: "Loading..." })
1038
+ ] }) : hasMultipleBranches ? /* @__PURE__ */ jsx5(
1039
+ Select2,
1040
+ {
1041
+ value: tempBranchId,
1042
+ onChange: (value) => setTempBranchId(String(value)),
1043
+ placeholder: "Select branch",
1044
+ size: "large",
1045
+ style: { width: "100%" },
1046
+ optionLabelProp: "label",
1047
+ children: branches.map((branch) => /* @__PURE__ */ jsx5(Select2.Option, { value: String(branch.id), label: branch.name, children: /* @__PURE__ */ jsxs5(Space3, { style: { width: "100%", justifyContent: "space-between" }, children: [
1048
+ /* @__PURE__ */ jsxs5("div", { children: [
1049
+ /* @__PURE__ */ jsx5(Text3, { strong: true, children: branch.name }),
1050
+ /* @__PURE__ */ jsx5(Text3, { type: "secondary", style: { marginLeft: 8, fontSize: 12 }, children: branch.code })
1051
+ ] }),
1052
+ /* @__PURE__ */ jsxs5(Space3, { size: 4, children: [
1053
+ branch.is_headquarters && /* @__PURE__ */ jsx5(Badge3, { color: "blue", text: "HQ" }),
1054
+ branch.is_primary && /* @__PURE__ */ jsx5(Badge3, { color: "green", text: "Primary" })
1055
+ ] })
1056
+ ] }) }, branch.id))
1057
+ }
1058
+ ) : branches.length === 1 ? /* @__PURE__ */ jsx5("div", { style: {
1059
+ padding: "8px 12px",
1060
+ background: "#f5f5f5",
1061
+ borderRadius: 6,
1062
+ border: "1px solid #d9d9d9"
1063
+ }, children: /* @__PURE__ */ jsxs5(Space3, { children: [
1064
+ /* @__PURE__ */ jsx5(ApartmentOutlined2, { style: { color: "#1677ff" } }),
1065
+ /* @__PURE__ */ jsx5(Text3, { strong: true, children: branches[0].name }),
1066
+ /* @__PURE__ */ jsxs5(Text3, { type: "secondary", children: [
1067
+ "(",
1068
+ branches[0].code,
1069
+ ")"
1070
+ ] })
1071
+ ] }) }) : /* @__PURE__ */ jsx5(
1072
+ Alert2,
1073
+ {
1074
+ type: "warning",
1075
+ message: "No branches available",
1076
+ description: "You don't have access to any branches in this organization."
1077
+ }
1078
+ )
1079
+ ] }),
1080
+ /* @__PURE__ */ jsx5(
1081
+ Button2,
1082
+ {
1083
+ type: "primary",
1084
+ size: "large",
1085
+ block: true,
1086
+ disabled: !canConfirm,
1087
+ onClick: confirmSelection,
1088
+ icon: /* @__PURE__ */ jsx5(CheckCircleFilled2, {}),
1089
+ style: {
1090
+ height: 48,
1091
+ fontSize: 16,
1092
+ background: canConfirm ? "linear-gradient(135deg, #667eea 0%, #764ba2 100%)" : void 0,
1093
+ border: "none"
1094
+ },
1095
+ children: "Confirm"
1096
+ }
1097
+ )
1098
+ ] }) });
1099
+ }
1100
+ return /* @__PURE__ */ jsx5(Fragment3, { children });
1101
+ }
1102
+ function useBranchGate(storageKey = DEFAULT_STORAGE_KEY) {
1103
+ const [selection, setSelection] = useState3(null);
1104
+ useEffect4(() => {
1105
+ if (typeof window === "undefined") return;
1106
+ const saved = localStorage.getItem(storageKey);
1107
+ if (saved) {
1108
+ try {
1109
+ setSelection(JSON.parse(saved));
1110
+ } catch {
1111
+ }
1112
+ }
1113
+ const handleStorage = (e) => {
1114
+ if (e.key === storageKey) {
1115
+ if (e.newValue) {
1116
+ try {
1117
+ setSelection(JSON.parse(e.newValue));
1118
+ } catch {
1119
+ setSelection(null);
1120
+ }
1121
+ } else {
1122
+ setSelection(null);
1123
+ }
1124
+ }
1125
+ };
1126
+ window.addEventListener("storage", handleStorage);
1127
+ return () => window.removeEventListener("storage", handleStorage);
1128
+ }, [storageKey]);
1129
+ const clearSelection = React5.useCallback(() => {
1130
+ localStorage.removeItem(storageKey);
1131
+ setSelection(null);
1132
+ }, [storageKey]);
1133
+ return {
1134
+ selection,
1135
+ selectedOrg: selection ? { id: selection.orgId, slug: selection.orgId, name: selection.orgName } : null,
1136
+ selectedBranch: selection ? { id: selection.branchId, name: selection.branchName, code: selection.branchCode } : null,
1137
+ clearSelection
1138
+ };
1139
+ }
1140
+
1141
+ // src/ant/components/ProTable/ProTable.tsx
1142
+ import {
1143
+ PlusOutlined,
1144
+ ReloadOutlined,
1145
+ SettingOutlined,
1146
+ DownOutlined,
1147
+ UpOutlined
1148
+ } from "@ant-design/icons";
1149
+ import { useQuery as useQuery3 } from "@tanstack/react-query";
1150
+ import {
1151
+ Card,
1152
+ Table,
1153
+ Form as Form2,
1154
+ Input,
1155
+ Select as Select3,
1156
+ DatePicker,
1157
+ InputNumber,
1158
+ Button as Button3,
1159
+ Space as Space4,
1160
+ Row,
1161
+ Col,
1162
+ Tooltip,
1163
+ Divider,
1164
+ Typography as Typography4,
1165
+ Popconfirm,
1166
+ theme
1167
+ } from "antd";
1168
+ import { useState as useState4, useMemo as useMemo4, useCallback as useCallback5 } from "react";
1169
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1170
+ var { Link } = Typography4;
1171
+ var { RangePicker } = DatePicker;
1172
+ var InertiaLink = null;
1173
+ try {
1174
+ InertiaLink = __require("@inertiajs/react").Link;
1175
+ } catch {
1176
+ }
1177
+ var DEFAULT_TEXTS = {
1178
+ search: "\u691C\u7D22",
1179
+ reset: "\u30EA\u30BB\u30C3\u30C8",
1180
+ expand: "\u5C55\u958B",
1181
+ collapse: "\u53CE\u7D0D",
1182
+ add: "\u65B0\u898F",
1183
+ refresh: "\u66F4\u65B0",
1184
+ columnSettings: "\u5217\u8A2D\u5B9A",
1185
+ actions: "\u64CD\u4F5C",
1186
+ yes: "\u306F\u3044",
1187
+ no: "\u3044\u3044\u3048",
1188
+ cancel: "\u30AD\u30E3\u30F3\u30BB\u30EB",
1189
+ totalItems: (total) => `\u5168 ${total} \u4EF6`,
1190
+ selectPlaceholder: "\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044",
1191
+ inputPlaceholder: "\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044",
1192
+ startDate: "\u958B\u59CB\u65E5",
1193
+ endDate: "\u7D42\u4E86\u65E5"
1194
+ };
1195
+ var DEFAULT_STATUS_CONFIG = {
1196
+ active: { color: "#52c41a", text: "\u6709\u52B9" },
1197
+ Active: { color: "#52c41a", text: "\u6709\u52B9" },
1198
+ inactive: { color: "#d9d9d9", text: "\u7121\u52B9" },
1199
+ Inactive: { color: "#d9d9d9", text: "\u7121\u52B9" },
1200
+ pending: { color: "#faad14", text: "\u4FDD\u7559\u4E2D" },
1201
+ Pending: { color: "#faad14", text: "\u4FDD\u7559\u4E2D" },
1202
+ error: { color: "#ff4d4f", text: "\u30A8\u30E9\u30FC" },
1203
+ Error: { color: "#ff4d4f", text: "\u30A8\u30E9\u30FC" },
1204
+ closed: { color: "#ff4d4f", text: "\u9589\u9396" },
1205
+ Closed: { color: "#ff4d4f", text: "\u9589\u9396" }
1206
+ };
1207
+ function renderSearchField(field, texts) {
1208
+ switch (field.type) {
1209
+ case "select":
1210
+ return /* @__PURE__ */ jsx6(
1211
+ Select3,
1212
+ {
1213
+ allowClear: true,
1214
+ placeholder: field.placeholder || texts.selectPlaceholder,
1215
+ options: field.options,
1216
+ style: { width: "100%" }
1217
+ }
1218
+ );
1219
+ case "date":
1220
+ return /* @__PURE__ */ jsx6(
1221
+ DatePicker,
1222
+ {
1223
+ placeholder: field.placeholder,
1224
+ style: { width: "100%" }
1225
+ }
1226
+ );
1227
+ case "dateRange":
1228
+ return /* @__PURE__ */ jsx6(
1229
+ RangePicker,
1230
+ {
1231
+ placeholder: [texts.startDate, texts.endDate],
1232
+ style: { width: "100%" }
1233
+ }
1234
+ );
1235
+ case "number":
1236
+ return /* @__PURE__ */ jsx6(
1237
+ InputNumber,
1238
+ {
1239
+ placeholder: field.placeholder,
1240
+ style: { width: "100%" }
1241
+ }
1242
+ );
1243
+ default:
1244
+ return /* @__PURE__ */ jsx6(
1245
+ Input,
1246
+ {
1247
+ allowClear: true,
1248
+ placeholder: field.placeholder || texts.inputPlaceholder
1249
+ }
1250
+ );
1251
+ }
1252
+ }
1253
+ function SmartLink({ href, children }) {
1254
+ if (InertiaLink) {
1255
+ return /* @__PURE__ */ jsx6(InertiaLink, { href, children });
1256
+ }
1257
+ return /* @__PURE__ */ jsx6("a", { href, children });
1258
+ }
1259
+ function renderValue(value, valueType, statusConfig) {
1260
+ if (value === null || value === void 0) {
1261
+ return "-";
1262
+ }
1263
+ switch (valueType) {
1264
+ case "status": {
1265
+ const config = { ...DEFAULT_STATUS_CONFIG, ...statusConfig };
1266
+ const statusValue = String(value);
1267
+ const status = config[statusValue] || { color: "#d9d9d9", text: statusValue };
1268
+ return /* @__PURE__ */ jsxs6(Space4, { children: [
1269
+ /* @__PURE__ */ jsx6(
1270
+ "span",
1271
+ {
1272
+ style: {
1273
+ display: "inline-block",
1274
+ width: 6,
1275
+ height: 6,
1276
+ borderRadius: "50%",
1277
+ backgroundColor: status.color
1278
+ }
1279
+ }
1280
+ ),
1281
+ status.text
1282
+ ] });
1283
+ }
1284
+ case "date":
1285
+ return value ? new Date(String(value)).toLocaleDateString("ja-JP") : "-";
1286
+ case "datetime":
1287
+ return value ? new Date(String(value)).toLocaleString("ja-JP") : "-";
1288
+ case "number":
1289
+ return typeof value === "number" ? value.toLocaleString("ja-JP") : String(value);
1290
+ case "currency":
1291
+ return typeof value === "number" ? `\xA5${value.toLocaleString("ja-JP")}` : String(value);
1292
+ case "boolean":
1293
+ return value ? "\u306F\u3044" : "\u3044\u3044\u3048";
1294
+ default:
1295
+ return String(value);
1296
+ }
1297
+ }
1298
+ function ProTable({
1299
+ // Header
1300
+ title,
1301
+ icon,
1302
+ subTitle,
1303
+ // Search
1304
+ searchFields = [],
1305
+ defaultSearchValues = {},
1306
+ // Columns
1307
+ columns,
1308
+ // Data
1309
+ dataSource: externalDataSource,
1310
+ rowKey = "id",
1311
+ loading: externalLoading,
1312
+ // Query
1313
+ queryKey,
1314
+ queryFn,
1315
+ queryResult: externalQueryResult,
1316
+ queryEnabled = true,
1317
+ // Toolbar
1318
+ onAdd,
1319
+ addButtonLink,
1320
+ addLabel = "\u65B0\u898F",
1321
+ toolbarExtra,
1322
+ showRefresh = true,
1323
+ showColumnSettings = true,
1324
+ // Row actions
1325
+ rowActions,
1326
+ // Pagination
1327
+ pagination = true,
1328
+ defaultPageSize = 15,
1329
+ // Events
1330
+ onSearch,
1331
+ onReset,
1332
+ onChange,
1333
+ // Style
1334
+ className,
1335
+ style,
1336
+ cardStyle,
1337
+ tableProps,
1338
+ // i18n
1339
+ texts: customTexts
1340
+ }) {
1341
+ const { token } = theme.useToken();
1342
+ const texts = { ...DEFAULT_TEXTS, ...customTexts };
1343
+ const [searchForm] = Form2.useForm();
1344
+ const [expanded, setExpanded] = useState4(false);
1345
+ const [queryParams, setQueryParams] = useState4({
1346
+ page: 1,
1347
+ per_page: defaultPageSize,
1348
+ ...defaultSearchValues
1349
+ });
1350
+ const visibleFields = searchFields.filter((f) => !f.hidden);
1351
+ const hiddenFields = searchFields.filter((f) => f.hidden);
1352
+ const hasHiddenFields = hiddenFields.length > 0;
1353
+ const internalQuery = useQuery3({
1354
+ queryKey: queryKey ? [...queryKey, queryParams] : ["proTable", queryParams],
1355
+ queryFn: () => queryFn(queryParams),
1356
+ enabled: !!queryFn && queryEnabled
1357
+ });
1358
+ const queryResult = externalQueryResult || internalQuery;
1359
+ const dataSource = externalDataSource || queryResult.data?.data || [];
1360
+ const loading = externalLoading ?? queryResult.isLoading;
1361
+ const meta = queryResult.data?.meta;
1362
+ const handleSearch = useCallback5((values) => {
1363
+ const newParams = {
1364
+ ...queryParams,
1365
+ ...values,
1366
+ page: 1
1367
+ };
1368
+ setQueryParams(newParams);
1369
+ onSearch?.(values);
1370
+ }, [queryParams, onSearch]);
1371
+ const handleReset = useCallback5(() => {
1372
+ searchForm.resetFields();
1373
+ const newParams = {
1374
+ page: 1,
1375
+ per_page: defaultPageSize
1376
+ };
1377
+ setQueryParams(newParams);
1378
+ onReset?.();
1379
+ }, [searchForm, defaultPageSize, onReset]);
1380
+ const handleTableChange = useCallback5(
1381
+ (pag, _filters, sorter, _extra) => {
1382
+ const sortInfo = Array.isArray(sorter) ? sorter[0] : sorter;
1383
+ const newParams = {
1384
+ ...queryParams,
1385
+ page: pag.current || 1,
1386
+ per_page: pag.pageSize || defaultPageSize
1387
+ };
1388
+ if (sortInfo?.field && sortInfo?.order) {
1389
+ newParams.sort = String(sortInfo.field);
1390
+ newParams.order = sortInfo.order === "ascend" ? "asc" : "desc";
1391
+ } else {
1392
+ delete newParams.sort;
1393
+ delete newParams.order;
1394
+ }
1395
+ setQueryParams(newParams);
1396
+ onChange?.(pag, _filters, sorter, _extra);
1397
+ },
1398
+ [queryParams, defaultPageSize, onChange]
1399
+ );
1400
+ const tableColumns = useMemo4(() => {
1401
+ const cols = columns.filter((col) => !col.hidden).map((col) => ({
1402
+ ...col,
1403
+ key: col.key || (Array.isArray(col.dataIndex) ? col.dataIndex.join(".") : col.dataIndex),
1404
+ sorter: col.sortable ? true : void 0,
1405
+ render: col.render ? col.render : (value) => renderValue(value, col.valueType, col.statusConfig)
1406
+ }));
1407
+ if (rowActions) {
1408
+ cols.push({
1409
+ title: texts.actions,
1410
+ key: "_actions",
1411
+ width: 150,
1412
+ render: (_, record) => {
1413
+ const actions = rowActions(record).filter(
1414
+ (a) => !a.hidden?.(record)
1415
+ );
1416
+ return /* @__PURE__ */ jsx6(Space4, { size: 0, children: actions.map((action, idx) => {
1417
+ const isLast = idx === actions.length - 1;
1418
+ let actionElement;
1419
+ if (action.href) {
1420
+ actionElement = /* @__PURE__ */ jsx6(SmartLink, { href: action.href, children: /* @__PURE__ */ jsx6(Link, { style: action.danger ? { color: token.colorError } : void 0, children: action.label }) });
1421
+ } else {
1422
+ const linkElement = /* @__PURE__ */ jsx6(
1423
+ Link,
1424
+ {
1425
+ style: action.danger ? { color: token.colorError } : void 0,
1426
+ onClick: action.confirm ? void 0 : () => action.onClick?.(record),
1427
+ children: action.label
1428
+ }
1429
+ );
1430
+ if (action.confirm) {
1431
+ actionElement = /* @__PURE__ */ jsx6(
1432
+ Popconfirm,
1433
+ {
1434
+ title: typeof action.confirm === "string" ? action.confirm : `${action.label}\u3057\u307E\u3059\u304B\uFF1F`,
1435
+ onConfirm: () => action.onClick?.(record),
1436
+ okText: texts.yes,
1437
+ cancelText: texts.cancel,
1438
+ okButtonProps: action.danger ? { danger: true } : void 0,
1439
+ children: linkElement
1440
+ }
1441
+ );
1442
+ } else {
1443
+ actionElement = linkElement;
1444
+ }
1445
+ }
1446
+ return /* @__PURE__ */ jsxs6("span", { children: [
1447
+ actionElement,
1448
+ !isLast && /* @__PURE__ */ jsx6(Divider, { type: "vertical" })
1449
+ ] }, idx);
1450
+ }) });
1451
+ }
1452
+ });
1453
+ }
1454
+ return cols;
1455
+ }, [columns, rowActions, texts]);
1456
+ const paginationConfig = useMemo4(() => {
1457
+ if (pagination === false) return false;
1458
+ return {
1459
+ current: meta?.current_page || queryParams.page,
1460
+ pageSize: meta?.per_page || queryParams.per_page,
1461
+ total: meta?.total || 0,
1462
+ showSizeChanger: true,
1463
+ showTotal: texts.totalItems,
1464
+ ...typeof pagination === "object" ? pagination : {}
1465
+ };
1466
+ }, [pagination, meta, queryParams, texts]);
1467
+ return /* @__PURE__ */ jsxs6("div", { className, style, children: [
1468
+ searchFields.length > 0 && /* @__PURE__ */ jsx6(Card, { style: { marginBottom: 24, ...cardStyle }, children: /* @__PURE__ */ jsxs6(
1469
+ Form2,
1470
+ {
1471
+ form: searchForm,
1472
+ layout: "horizontal",
1473
+ onFinish: handleSearch,
1474
+ labelCol: { flex: "100px" },
1475
+ wrapperCol: { flex: 1 },
1476
+ initialValues: defaultSearchValues,
1477
+ children: [
1478
+ /* @__PURE__ */ jsxs6(Row, { gutter: 24, children: [
1479
+ visibleFields.map((field) => /* @__PURE__ */ jsx6(Col, { span: 8, children: /* @__PURE__ */ jsx6(Form2.Item, { name: field.name, label: field.label, children: renderSearchField(field, texts) }) }, field.name)),
1480
+ /* @__PURE__ */ jsx6(Col, { span: visibleFields.length === 1 ? 16 : 8, style: { textAlign: "right" }, children: /* @__PURE__ */ jsxs6(Space4, { children: [
1481
+ /* @__PURE__ */ jsx6(Button3, { onClick: handleReset, children: texts.reset }),
1482
+ /* @__PURE__ */ jsx6(Button3, { type: "primary", htmlType: "submit", children: texts.search }),
1483
+ hasHiddenFields && /* @__PURE__ */ jsxs6(
1484
+ Button3,
1485
+ {
1486
+ type: "link",
1487
+ onClick: () => setExpanded(!expanded),
1488
+ children: [
1489
+ expanded ? texts.collapse : texts.expand,
1490
+ expanded ? /* @__PURE__ */ jsx6(UpOutlined, {}) : /* @__PURE__ */ jsx6(DownOutlined, {})
1491
+ ]
1492
+ }
1493
+ )
1494
+ ] }) })
1495
+ ] }),
1496
+ expanded && hiddenFields.length > 0 && /* @__PURE__ */ jsx6(Row, { gutter: 24, style: { marginTop: 16 }, children: hiddenFields.map((field) => /* @__PURE__ */ jsx6(Col, { span: 8, children: /* @__PURE__ */ jsx6(Form2.Item, { name: field.name, label: field.label, children: renderSearchField(field, texts) }) }, field.name)) })
1497
+ ]
1498
+ }
1499
+ ) }),
1500
+ /* @__PURE__ */ jsx6(
1501
+ Card,
1502
+ {
1503
+ title: /* @__PURE__ */ jsxs6(Space4, { children: [
1504
+ icon,
1505
+ title,
1506
+ subTitle && /* @__PURE__ */ jsx6("span", { style: {
1507
+ fontWeight: "normal",
1508
+ fontSize: 14,
1509
+ color: token.colorTextSecondary
1510
+ }, children: subTitle })
1511
+ ] }),
1512
+ extra: /* @__PURE__ */ jsxs6(Space4, { size: "small", children: [
1513
+ toolbarExtra,
1514
+ addButtonLink && /* @__PURE__ */ jsx6(SmartLink, { href: addButtonLink, children: /* @__PURE__ */ jsx6(Button3, { type: "primary", icon: /* @__PURE__ */ jsx6(PlusOutlined, {}), children: addLabel || texts.add }) }),
1515
+ onAdd && !addButtonLink && /* @__PURE__ */ jsx6(Button3, { type: "primary", icon: /* @__PURE__ */ jsx6(PlusOutlined, {}), onClick: onAdd, children: addLabel || texts.add }),
1516
+ showRefresh && /* @__PURE__ */ jsx6(Tooltip, { title: texts.refresh, children: /* @__PURE__ */ jsx6(
1517
+ Button3,
1518
+ {
1519
+ icon: /* @__PURE__ */ jsx6(ReloadOutlined, {}),
1520
+ onClick: () => queryResult.refetch?.(),
1521
+ loading: queryResult.isFetching
1522
+ }
1523
+ ) }),
1524
+ showColumnSettings && /* @__PURE__ */ jsx6(Tooltip, { title: texts.columnSettings, children: /* @__PURE__ */ jsx6(Button3, { icon: /* @__PURE__ */ jsx6(SettingOutlined, {}) }) })
1525
+ ] }),
1526
+ style: cardStyle,
1527
+ children: /* @__PURE__ */ jsx6(
1528
+ Table,
1529
+ {
1530
+ ...tableProps,
1531
+ columns: tableColumns,
1532
+ dataSource,
1533
+ rowKey,
1534
+ loading,
1535
+ pagination: paginationConfig,
1536
+ onChange: handleTableChange
1537
+ }
1538
+ )
1539
+ }
1540
+ )
1541
+ ] });
1542
+ }
1543
+
1544
+ // src/ant/components/PageContainer/PageContainer.tsx
1545
+ import { Breadcrumb, theme as theme2 } from "antd";
1546
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1547
+ function PageContainer({
1548
+ title,
1549
+ subTitle,
1550
+ icon,
1551
+ extra,
1552
+ breadcrumb,
1553
+ children,
1554
+ showHeader = true,
1555
+ className,
1556
+ style
1557
+ }) {
1558
+ const { token } = theme2.useToken();
1559
+ const breadcrumbProps = breadcrumb ? Array.isArray(breadcrumb) ? { items: breadcrumb } : breadcrumb : void 0;
1560
+ const hasHeader = showHeader && (title || subTitle || breadcrumb);
1561
+ return /* @__PURE__ */ jsxs7("div", { className, style, children: [
1562
+ hasHeader && /* @__PURE__ */ jsxs7(
1563
+ "div",
1564
+ {
1565
+ style: {
1566
+ marginBottom: 24
1567
+ },
1568
+ children: [
1569
+ breadcrumbProps && /* @__PURE__ */ jsx7(
1570
+ Breadcrumb,
1571
+ {
1572
+ ...breadcrumbProps,
1573
+ style: {
1574
+ marginBottom: 12,
1575
+ ...breadcrumbProps.style
1576
+ }
1577
+ }
1578
+ ),
1579
+ (title || extra) && /* @__PURE__ */ jsxs7(
1580
+ "div",
1581
+ {
1582
+ style: {
1583
+ display: "flex",
1584
+ justifyContent: "space-between",
1585
+ alignItems: "flex-start"
1586
+ },
1587
+ children: [
1588
+ /* @__PURE__ */ jsxs7("div", { children: [
1589
+ title && /* @__PURE__ */ jsxs7(
1590
+ "h1",
1591
+ {
1592
+ style: {
1593
+ margin: 0,
1594
+ fontSize: 20,
1595
+ fontWeight: 600,
1596
+ lineHeight: 1.4,
1597
+ color: token.colorText,
1598
+ display: "flex",
1599
+ alignItems: "center",
1600
+ gap: 8
1601
+ },
1602
+ children: [
1603
+ icon && /* @__PURE__ */ jsx7("span", { style: { fontSize: 20 }, children: icon }),
1604
+ title
1605
+ ]
1606
+ }
1607
+ ),
1608
+ subTitle && /* @__PURE__ */ jsx7(
1609
+ "div",
1610
+ {
1611
+ style: {
1612
+ marginTop: 4,
1613
+ fontSize: 14,
1614
+ color: token.colorTextSecondary
1615
+ },
1616
+ children: subTitle
1617
+ }
1618
+ )
1619
+ ] }),
1620
+ extra && /* @__PURE__ */ jsx7("div", { style: { flexShrink: 0 }, children: extra })
1621
+ ]
1622
+ }
1623
+ )
1624
+ ]
1625
+ }
1626
+ ),
1627
+ children
1628
+ ] });
1629
+ }
1630
+
1631
+ // src/ant/components/LocaleSwitcher/LocaleSwitcher.tsx
1632
+ import { GlobalOutlined } from "@ant-design/icons";
1633
+ import { Select as Select4 } from "antd";
1634
+ import { useTranslation as useTranslation2 } from "react-i18next";
1635
+
1636
+ // src/core/i18n/index.tsx
1637
+ import { createContext as createContext2, useContext as useContext2, useCallback as useCallback6, useState as useState5, useEffect as useEffect5, useMemo as useMemo5 } from "react";
1638
+ import { useTranslation, I18nextProvider, initReactI18next } from "react-i18next";
1639
+ import i18n from "i18next";
1640
+ import { jsx as jsx8 } from "react/jsx-runtime";
1641
+ var locales = ["ja", "en", "vi"];
1642
+ var localeNames = {
1643
+ ja: "\u65E5\u672C\u8A9E",
1644
+ en: "English",
1645
+ vi: "Ti\u1EBFng Vi\u1EC7t"
1646
+ };
1647
+ var defaultLocale = "ja";
1648
+ var I18nContext = createContext2(null);
1649
+ function useLocale() {
1650
+ const context = useContext2(I18nContext);
1651
+ const { i18n: i18nInstance } = useTranslation();
1652
+ if (context) {
1653
+ return context.locale;
1654
+ }
1655
+ return i18nInstance?.language || defaultLocale;
1656
+ }
1657
+
1658
+ // src/ant/components/LocaleSwitcher/LocaleSwitcher.tsx
1659
+ import { jsx as jsx9 } from "react/jsx-runtime";
1660
+ function LocaleSwitcher() {
1661
+ const { i18n: i18n2 } = useTranslation2();
1662
+ const locale = i18n2.language || "ja";
1663
+ const handleChange = (newLocale) => {
1664
+ i18n2.changeLanguage(newLocale);
1665
+ document.cookie = `locale=${newLocale};path=/;max-age=31536000`;
1666
+ };
1667
+ return /* @__PURE__ */ jsx9(
1668
+ Select4,
1669
+ {
1670
+ value: locale,
1671
+ onChange: handleChange,
1672
+ style: { width: 100 },
1673
+ size: "small",
1674
+ suffixIcon: /* @__PURE__ */ jsx9(GlobalOutlined, {}),
1675
+ options: locales.map((l) => ({
1676
+ value: l,
1677
+ label: localeNames[l]
1678
+ }))
1679
+ }
1680
+ );
1681
+ }
1682
+
1683
+ // src/ant/components/UserRoleAssignModal/UserRoleAssignModal.tsx
1684
+ import {
1685
+ SafetyOutlined,
1686
+ BankOutlined as BankOutlined4
1687
+ } from "@ant-design/icons";
1688
+ import {
1689
+ Modal as Modal3,
1690
+ Form as Form3,
1691
+ Select as Select5,
1692
+ Radio,
1693
+ Button as Button4,
1694
+ Space as Space7,
1695
+ Tag as Tag2,
1696
+ Typography as Typography5
1697
+ } from "antd";
1698
+ import { useState as useState6 } from "react";
1699
+
1700
+ // src/ant/components/ScopeUtils/ScopeUtils.tsx
1701
+ import { GlobalOutlined as GlobalOutlined2, BankOutlined as BankOutlined3, BranchesOutlined } from "@ant-design/icons";
1702
+ import { Tag, Space as Space6 } from "antd";
1703
+ import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
1704
+ function getScopeIcon(scope) {
1705
+ switch (scope) {
1706
+ case "global":
1707
+ return /* @__PURE__ */ jsx10(GlobalOutlined2, {});
1708
+ case "org-wide":
1709
+ return /* @__PURE__ */ jsx10(BankOutlined3, {});
1710
+ case "branch":
1711
+ return /* @__PURE__ */ jsx10(BranchesOutlined, {});
1712
+ default:
1713
+ return null;
1714
+ }
1715
+ }
1716
+ function getScopeColor(scope) {
1717
+ switch (scope) {
1718
+ case "global":
1719
+ return "purple";
1720
+ case "org-wide":
1721
+ return "blue";
1722
+ case "branch":
1723
+ return "green";
1724
+ default:
1725
+ return "default";
1726
+ }
1727
+ }
1728
+ function ScopeTag({ scope, label, showIcon = true }) {
1729
+ return /* @__PURE__ */ jsx10(Tag, { color: getScopeColor(scope), icon: showIcon ? getScopeIcon(scope) : void 0, children: label || scope });
1730
+ }
1731
+ function ScopeLabel({ scope, label }) {
1732
+ return /* @__PURE__ */ jsxs8(Space6, { children: [
1733
+ getScopeIcon(scope),
1734
+ label
1735
+ ] });
1736
+ }
1737
+
1738
+ // src/ant/components/UserRoleAssignModal/UserRoleAssignModal.tsx
1739
+ import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
1740
+ var { Text: Text4 } = Typography5;
1741
+ var defaultTranslations = {
1742
+ title: "\u30ED\u30FC\u30EB\u5272\u308A\u5F53\u3066",
1743
+ selectRole: "\u30ED\u30FC\u30EB\u3092\u9078\u629E",
1744
+ scope: "\u30B9\u30B3\u30FC\u30D7",
1745
+ global: "\u30B0\u30ED\u30FC\u30D0\u30EB",
1746
+ orgWide: "\u7D44\u7E54\u5168\u4F53",
1747
+ branchSpecific: "\u62E0\u70B9\u9650\u5B9A",
1748
+ organization: "\u7D44\u7E54",
1749
+ selectBranches: "\u62E0\u70B9\u3092\u9078\u629E",
1750
+ assign: "\u5272\u308A\u5F53\u3066",
1751
+ cancel: "\u30AD\u30E3\u30F3\u30BB\u30EB",
1752
+ assignRole: "\u30ED\u30FC\u30EB\u5272\u308A\u5F53\u3066",
1753
+ required: "\u5FC5\u9808\u9805\u76EE\u3067\u3059"
1754
+ };
1755
+ function UserRoleAssignModal({
1756
+ open,
1757
+ userName,
1758
+ roles,
1759
+ organizations,
1760
+ branches,
1761
+ currentOrgId,
1762
+ loading = false,
1763
+ onAssign,
1764
+ onCancel,
1765
+ translations: t = {}
1766
+ }) {
1767
+ const [form] = Form3.useForm();
1768
+ const [isSubmitting, setIsSubmitting] = useState6(false);
1769
+ const labels = { ...defaultTranslations, ...t };
1770
+ const handleFinish = async (values) => {
1771
+ setIsSubmitting(true);
1772
+ try {
1773
+ await onAssign(values);
1774
+ form.resetFields();
1775
+ } finally {
1776
+ setIsSubmitting(false);
1777
+ }
1778
+ };
1779
+ const handleCancel = () => {
1780
+ form.resetFields();
1781
+ onCancel();
1782
+ };
1783
+ return /* @__PURE__ */ jsx11(
1784
+ Modal3,
1785
+ {
1786
+ title: /* @__PURE__ */ jsxs9(Space7, { children: [
1787
+ /* @__PURE__ */ jsx11(SafetyOutlined, {}),
1788
+ labels.title,
1789
+ " ",
1790
+ userName ? `- ${userName}` : ""
1791
+ ] }),
1792
+ open,
1793
+ onCancel: handleCancel,
1794
+ footer: null,
1795
+ destroyOnHidden: true,
1796
+ children: /* @__PURE__ */ jsxs9(
1797
+ Form3,
1798
+ {
1799
+ form,
1800
+ layout: "vertical",
1801
+ onFinish: handleFinish,
1802
+ initialValues: { scope: "org-wide", org_id: currentOrgId },
1803
+ children: [
1804
+ /* @__PURE__ */ jsx11(
1805
+ Form3.Item,
1806
+ {
1807
+ name: "role_id",
1808
+ label: labels.selectRole,
1809
+ rules: [{ required: true, message: labels.required }],
1810
+ children: /* @__PURE__ */ jsx11(Select5, { placeholder: labels.selectRole, children: roles.map((role) => /* @__PURE__ */ jsx11(Select5.Option, { value: role.id, children: role.name }, role.id)) })
1811
+ }
1812
+ ),
1813
+ /* @__PURE__ */ jsx11(Form3.Item, { name: "scope", label: labels.scope, children: /* @__PURE__ */ jsxs9(Radio.Group, { children: [
1814
+ /* @__PURE__ */ jsx11(Radio, { value: "global", children: /* @__PURE__ */ jsx11(ScopeLabel, { scope: "global", label: labels.global }) }),
1815
+ /* @__PURE__ */ jsx11(Radio, { value: "org-wide", children: /* @__PURE__ */ jsx11(ScopeLabel, { scope: "org-wide", label: labels.orgWide }) }),
1816
+ /* @__PURE__ */ jsx11(Radio, { value: "branch", children: /* @__PURE__ */ jsx11(ScopeLabel, { scope: "branch", label: labels.branchSpecific }) })
1817
+ ] }) }),
1818
+ /* @__PURE__ */ jsx11(Form3.Item, { noStyle: true, shouldUpdate: (prev, curr) => prev.scope !== curr.scope, children: ({ getFieldValue }) => (getFieldValue("scope") === "org-wide" || getFieldValue("scope") === "branch") && /* @__PURE__ */ jsx11(
1819
+ Form3.Item,
1820
+ {
1821
+ name: "org_id",
1822
+ label: labels.organization,
1823
+ rules: [{ required: true, message: labels.required }],
1824
+ children: /* @__PURE__ */ jsx11(Select5, { placeholder: labels.organization, children: organizations.map((org) => /* @__PURE__ */ jsx11(Select5.Option, { value: String(org.id), children: /* @__PURE__ */ jsxs9(Space7, { children: [
1825
+ /* @__PURE__ */ jsx11(BankOutlined4, {}),
1826
+ org.name
1827
+ ] }) }, org.id)) })
1828
+ }
1829
+ ) }),
1830
+ /* @__PURE__ */ jsx11(Form3.Item, { noStyle: true, shouldUpdate: (prev, curr) => prev.scope !== curr.scope, children: ({ getFieldValue }) => getFieldValue("scope") === "branch" && /* @__PURE__ */ jsx11(
1831
+ Form3.Item,
1832
+ {
1833
+ name: "branch_ids",
1834
+ label: labels.selectBranches,
1835
+ rules: [{ required: true, message: labels.required }],
1836
+ children: /* @__PURE__ */ jsx11(Select5, { mode: "multiple", placeholder: labels.selectBranches, children: branches?.map((branch) => /* @__PURE__ */ jsx11(Select5.Option, { value: String(branch.id), children: branch.name }, branch.id)) })
1837
+ }
1838
+ ) }),
1839
+ /* @__PURE__ */ jsx11(Form3.Item, { noStyle: true, shouldUpdate: true, children: ({ getFieldValue }) => {
1840
+ const scope = getFieldValue("scope");
1841
+ const selectedOrgId = getFieldValue("org_id");
1842
+ const selectedBranchIds = getFieldValue("branch_ids") || [];
1843
+ const selectedRole = roles.find((r) => r.id === getFieldValue("role_id"));
1844
+ const selectedOrg = organizations.find((o) => String(o.id) === selectedOrgId);
1845
+ const selectedBranches = branches?.filter((b) => selectedBranchIds.includes(String(b.id))) || [];
1846
+ if (!selectedRole) return null;
1847
+ let scopeText = "";
1848
+ if (scope === "global") {
1849
+ scopeText = labels.global;
1850
+ } else if (scope === "org-wide" && selectedOrg) {
1851
+ scopeText = `${selectedOrg.name} (${labels.orgWide})`;
1852
+ } else if (scope === "branch" && selectedBranches.length > 0) {
1853
+ scopeText = selectedBranches.map((b) => b.name).join(", ");
1854
+ }
1855
+ return scopeText ? /* @__PURE__ */ jsx11(
1856
+ "div",
1857
+ {
1858
+ style: {
1859
+ padding: "8px 12px",
1860
+ background: "#f5f5f5",
1861
+ borderRadius: 4,
1862
+ marginBottom: 16
1863
+ },
1864
+ children: /* @__PURE__ */ jsxs9(Text4, { type: "secondary", children: [
1865
+ labels.assignRole,
1866
+ ": ",
1867
+ /* @__PURE__ */ jsx11(Text4, { strong: true, children: selectedRole.name }),
1868
+ " \u2192 ",
1869
+ /* @__PURE__ */ jsx11(Tag2, { color: getScopeColor(scope), children: scopeText })
1870
+ ] })
1871
+ }
1872
+ ) : null;
1873
+ } }),
1874
+ /* @__PURE__ */ jsx11(Form3.Item, { children: /* @__PURE__ */ jsxs9(Space7, { children: [
1875
+ /* @__PURE__ */ jsx11(Button4, { type: "primary", htmlType: "submit", loading: loading || isSubmitting, children: labels.assign }),
1876
+ /* @__PURE__ */ jsx11(Button4, { onClick: handleCancel, children: labels.cancel })
1877
+ ] }) })
1878
+ ]
1879
+ }
1880
+ )
1881
+ }
1882
+ );
1883
+ }
1884
+
1885
+ // src/ant/components/UserPermissionsModal/UserPermissionsModal.tsx
1886
+ import {
1887
+ UserOutlined,
1888
+ SafetyOutlined as SafetyOutlined2,
1889
+ GlobalOutlined as GlobalOutlined4,
1890
+ BankOutlined as BankOutlined5,
1891
+ BranchesOutlined as BranchesOutlined3,
1892
+ TeamOutlined,
1893
+ PlusOutlined as PlusOutlined2,
1894
+ DeleteOutlined
1895
+ } from "@ant-design/icons";
1896
+ import {
1897
+ Modal as Modal4,
1898
+ Card as Card2,
1899
+ Tag as Tag3,
1900
+ Space as Space8,
1901
+ Collapse,
1902
+ Empty,
1903
+ Spin as Spin3,
1904
+ Button as Button5,
1905
+ Popconfirm as Popconfirm2,
1906
+ Typography as Typography6
1907
+ } from "antd";
1908
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
1909
+ var { Text: Text5 } = Typography6;
1910
+ var defaultTranslations2 = {
1911
+ permissionBreakdown: "\u6A29\u9650\u30D6\u30EC\u30FC\u30AF\u30C0\u30A6\u30F3",
1912
+ userInfo: "\u30E6\u30FC\u30B6\u30FC\u60C5\u5831",
1913
+ email: "\u30E1\u30FC\u30EB",
1914
+ primaryOrganization: "\u6240\u5C5E\u7D44\u7E54",
1915
+ global: "\u30B0\u30ED\u30FC\u30D0\u30EB",
1916
+ currentContext: "\u73FE\u5728\u306E\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8",
1917
+ roleAssignments: "\u30ED\u30FC\u30EB\u5272\u308A\u5F53\u3066",
1918
+ noRolesAssigned: "\u30ED\u30FC\u30EB\u304C\u5272\u308A\u5F53\u3066\u3089\u308C\u3066\u3044\u307E\u305B\u3093",
1919
+ add: "\u8FFD\u52A0",
1920
+ permissions: "\u6A29\u9650",
1921
+ teamMemberships: "\u30C1\u30FC\u30E0\u30E1\u30F3\u30D0\u30FC\u30B7\u30C3\u30D7",
1922
+ noTeamMemberships: "\u30C1\u30FC\u30E0\u306B\u6240\u5C5E\u3057\u3066\u3044\u307E\u305B\u3093",
1923
+ teamLeader: "\u30EA\u30FC\u30C0\u30FC",
1924
+ teamsFromConsole: "\u30C1\u30FC\u30E0\u306F\u30B3\u30F3\u30BD\u30FC\u30EB\u304B\u3089\u7BA1\u7406\u3057\u307E\u3059",
1925
+ aggregatedPermissions: "\u96C6\u7D04\u3055\u308C\u305F\u6A29\u9650",
1926
+ noData: "\u30C7\u30FC\u30BF\u304C\u3042\u308A\u307E\u305B\u3093",
1927
+ ungrouped: "\u672A\u5206\u985E",
1928
+ orgWide: "\u7D44\u7E54\u5168\u4F53",
1929
+ confirmRemoveRole: "\u3053\u306E\u30ED\u30FC\u30EB\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B\uFF1F"
1930
+ };
1931
+ function UserPermissionsModal({
1932
+ open,
1933
+ userName,
1934
+ permissions,
1935
+ loading = false,
1936
+ currentOrg,
1937
+ currentBranch,
1938
+ branches,
1939
+ onClose,
1940
+ onAddRole,
1941
+ onAddTeam,
1942
+ onRemoveRole,
1943
+ translations: t = {}
1944
+ }) {
1945
+ const labels = { ...defaultTranslations2, ...t };
1946
+ const getBranchName = (branchId) => {
1947
+ if (!branchId || !branches) return "";
1948
+ const branch = branches.find((b) => String(b.id) === branchId);
1949
+ return branch?.name || branchId;
1950
+ };
1951
+ return /* @__PURE__ */ jsx12(
1952
+ Modal4,
1953
+ {
1954
+ title: /* @__PURE__ */ jsxs10(Space8, { children: [
1955
+ /* @__PURE__ */ jsx12(UserOutlined, {}),
1956
+ userName,
1957
+ " - ",
1958
+ labels.permissionBreakdown
1959
+ ] }),
1960
+ open,
1961
+ onCancel: onClose,
1962
+ footer: null,
1963
+ width: 800,
1964
+ destroyOnHidden: true,
1965
+ children: loading ? /* @__PURE__ */ jsx12("div", { style: { textAlign: "center", padding: 40 }, children: /* @__PURE__ */ jsx12(Spin3, { size: "large" }) }) : permissions ? /* @__PURE__ */ jsxs10("div", { style: { display: "flex", flexDirection: "column", gap: 16 }, children: [
1966
+ /* @__PURE__ */ jsx12(Card2, { size: "small", title: labels.userInfo, children: /* @__PURE__ */ jsxs10("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
1967
+ /* @__PURE__ */ jsxs10("div", { children: [
1968
+ /* @__PURE__ */ jsxs10(Text5, { type: "secondary", children: [
1969
+ labels.email,
1970
+ ": "
1971
+ ] }),
1972
+ /* @__PURE__ */ jsx12(Text5, { children: permissions.user?.email })
1973
+ ] }),
1974
+ /* @__PURE__ */ jsxs10("div", { children: [
1975
+ /* @__PURE__ */ jsxs10(Text5, { type: "secondary", children: [
1976
+ labels.primaryOrganization,
1977
+ ": "
1978
+ ] }),
1979
+ permissions.user?.organization ? /* @__PURE__ */ jsx12(Tag3, { icon: /* @__PURE__ */ jsx12(BankOutlined5, {}), color: "blue", children: permissions.user.organization.name }) : /* @__PURE__ */ jsx12(Tag3, { icon: /* @__PURE__ */ jsx12(GlobalOutlined4, {}), color: "purple", children: labels.global })
1980
+ ] })
1981
+ ] }) }),
1982
+ /* @__PURE__ */ jsx12(Card2, { size: "small", title: labels.currentContext, children: /* @__PURE__ */ jsxs10(Space8, { wrap: true, children: [
1983
+ currentOrg && /* @__PURE__ */ jsx12(Tag3, { icon: /* @__PURE__ */ jsx12(BankOutlined5, {}), color: "blue", children: currentOrg.name }),
1984
+ currentBranch && /* @__PURE__ */ jsx12(Tag3, { icon: /* @__PURE__ */ jsx12(BranchesOutlined3, {}), color: "green", children: currentBranch.name })
1985
+ ] }) }),
1986
+ /* @__PURE__ */ jsx12(
1987
+ Card2,
1988
+ {
1989
+ size: "small",
1990
+ title: /* @__PURE__ */ jsxs10(Space8, { children: [
1991
+ /* @__PURE__ */ jsx12(SafetyOutlined2, {}),
1992
+ labels.roleAssignments,
1993
+ " (",
1994
+ permissions.role_assignments.length,
1995
+ ")"
1996
+ ] }),
1997
+ extra: onAddRole && /* @__PURE__ */ jsx12(Button5, { type: "primary", size: "small", icon: /* @__PURE__ */ jsx12(PlusOutlined2, {}), onClick: onAddRole, children: labels.add }),
1998
+ children: permissions.role_assignments.length === 0 ? /* @__PURE__ */ jsx12(Empty, { description: labels.noRolesAssigned }) : /* @__PURE__ */ jsx12(Collapse, { ghost: true, children: permissions.role_assignments.map((assignment, index) => /* @__PURE__ */ jsx12(
1999
+ Collapse.Panel,
2000
+ {
2001
+ header: /* @__PURE__ */ jsxs10(Space8, { wrap: true, children: [
2002
+ getScopeIcon(assignment.scope),
2003
+ /* @__PURE__ */ jsx12(Text5, { strong: true, children: assignment.role.name }),
2004
+ /* @__PURE__ */ jsx12(Tag3, { color: getScopeColor(assignment.scope), children: assignment.scope === "global" ? labels.global : assignment.scope === "org-wide" ? assignment.org_name || labels.orgWide : assignment.branch_name || getBranchName(assignment.console_branch_id) }),
2005
+ assignment.scope === "branch" && assignment.org_name && /* @__PURE__ */ jsx12(Tag3, { color: "blue", icon: /* @__PURE__ */ jsx12(BankOutlined5, {}), children: assignment.org_name }),
2006
+ /* @__PURE__ */ jsxs10(Tag3, { children: [
2007
+ assignment.permissions.length,
2008
+ " ",
2009
+ labels.permissions
2010
+ ] }),
2011
+ onRemoveRole && /* @__PURE__ */ jsx12(
2012
+ Popconfirm2,
2013
+ {
2014
+ title: labels.confirmRemoveRole,
2015
+ onConfirm: () => {
2016
+ onRemoveRole(
2017
+ assignment.role.id,
2018
+ assignment.console_org_id,
2019
+ assignment.console_branch_id
2020
+ );
2021
+ },
2022
+ children: /* @__PURE__ */ jsx12(
2023
+ Button5,
2024
+ {
2025
+ size: "small",
2026
+ danger: true,
2027
+ icon: /* @__PURE__ */ jsx12(DeleteOutlined, {}),
2028
+ onClick: (e) => e.stopPropagation()
2029
+ }
2030
+ )
2031
+ }
2032
+ )
2033
+ ] }),
2034
+ children: Object.entries(
2035
+ assignment.permissions.reduce(
2036
+ (groups, perm) => {
2037
+ const group = perm.group || labels.ungrouped;
2038
+ if (!groups[group]) groups[group] = [];
2039
+ groups[group].push({ slug: perm.slug, name: perm.name });
2040
+ return groups;
2041
+ },
2042
+ {}
2043
+ )
2044
+ ).map(([group, perms]) => /* @__PURE__ */ jsxs10("div", { style: { marginBottom: 8 }, children: [
2045
+ /* @__PURE__ */ jsx12(Text5, { type: "secondary", style: { fontSize: 12 }, children: group }),
2046
+ /* @__PURE__ */ jsx12("div", { style: { display: "flex", flexWrap: "wrap", gap: 4, marginTop: 4 }, children: perms.map((perm) => /* @__PURE__ */ jsx12(Tag3, { color: "blue", children: perm.name }, perm.slug)) })
2047
+ ] }, group))
2048
+ },
2049
+ index
2050
+ )) })
2051
+ }
2052
+ ),
2053
+ /* @__PURE__ */ jsx12(
2054
+ Card2,
2055
+ {
2056
+ size: "small",
2057
+ title: /* @__PURE__ */ jsxs10(Space8, { children: [
2058
+ /* @__PURE__ */ jsx12(TeamOutlined, {}),
2059
+ labels.teamMemberships,
2060
+ " (",
2061
+ permissions.team_memberships.length,
2062
+ ")"
2063
+ ] }),
2064
+ extra: onAddTeam && /* @__PURE__ */ jsx12(Button5, { size: "small", icon: /* @__PURE__ */ jsx12(PlusOutlined2, {}), onClick: onAddTeam, children: labels.add }),
2065
+ children: permissions.team_memberships.length === 0 ? /* @__PURE__ */ jsx12(Empty, { description: labels.noTeamMemberships }) : /* @__PURE__ */ jsx12(Collapse, { ghost: true, children: permissions.team_memberships.map((membership, index) => /* @__PURE__ */ jsx12(
2066
+ Collapse.Panel,
2067
+ {
2068
+ header: /* @__PURE__ */ jsxs10(Space8, { children: [
2069
+ /* @__PURE__ */ jsx12(TeamOutlined, {}),
2070
+ /* @__PURE__ */ jsx12(Text5, { strong: true, children: membership.team.name }),
2071
+ membership.is_leader && /* @__PURE__ */ jsx12(Tag3, { color: "gold", children: labels.teamLeader }),
2072
+ /* @__PURE__ */ jsxs10(Tag3, { children: [
2073
+ membership.permissions.length,
2074
+ " ",
2075
+ labels.permissions
2076
+ ] })
2077
+ ] }),
2078
+ children: Object.entries(
2079
+ membership.permissions.reduce(
2080
+ (groups, perm) => {
2081
+ const group = perm.group || labels.ungrouped;
2082
+ if (!groups[group]) groups[group] = [];
2083
+ groups[group].push({ slug: perm.slug, name: perm.name });
2084
+ return groups;
2085
+ },
2086
+ {}
2087
+ )
2088
+ ).map(([group, perms]) => /* @__PURE__ */ jsxs10("div", { style: { marginBottom: 8 }, children: [
2089
+ /* @__PURE__ */ jsx12(Text5, { type: "secondary", style: { fontSize: 12 }, children: group }),
2090
+ /* @__PURE__ */ jsx12("div", { style: { display: "flex", flexWrap: "wrap", gap: 4, marginTop: 4 }, children: perms.map((perm) => /* @__PURE__ */ jsx12(Tag3, { color: "cyan", children: perm.name }, perm.slug)) })
2091
+ ] }, group))
2092
+ },
2093
+ index
2094
+ )) })
2095
+ }
2096
+ ),
2097
+ /* @__PURE__ */ jsx12(
2098
+ Card2,
2099
+ {
2100
+ size: "small",
2101
+ title: /* @__PURE__ */ jsxs10(Space8, { children: [
2102
+ /* @__PURE__ */ jsx12(SafetyOutlined2, {}),
2103
+ labels.aggregatedPermissions,
2104
+ " (",
2105
+ permissions.aggregated_permissions.length,
2106
+ ")"
2107
+ ] }),
2108
+ children: permissions.aggregated_permissions.length === 0 ? /* @__PURE__ */ jsx12(Empty, { description: labels.noData }) : /* @__PURE__ */ jsx12(Collapse, { ghost: true, children: Object.entries(
2109
+ permissions.aggregated_permissions.reduce(
2110
+ (groups, perm) => {
2111
+ const parts = perm.split(".");
2112
+ const group = parts.length > 1 ? parts.slice(0, -1).join(".") : labels.ungrouped;
2113
+ if (!groups[group]) groups[group] = [];
2114
+ groups[group].push(perm);
2115
+ return groups;
2116
+ },
2117
+ {}
2118
+ )
2119
+ ).map(([group, perms]) => /* @__PURE__ */ jsx12(
2120
+ Collapse.Panel,
2121
+ {
2122
+ header: /* @__PURE__ */ jsxs10(Space8, { children: [
2123
+ /* @__PURE__ */ jsx12(SafetyOutlined2, {}),
2124
+ /* @__PURE__ */ jsx12(Text5, { strong: true, children: group }),
2125
+ /* @__PURE__ */ jsx12(Tag3, { color: "green", children: perms.length })
2126
+ ] }),
2127
+ children: /* @__PURE__ */ jsx12("div", { style: { display: "flex", flexWrap: "wrap", gap: 4 }, children: perms.map((perm) => /* @__PURE__ */ jsx12(Tag3, { color: "green", children: perm.split(".").pop() }, perm)) })
2128
+ },
2129
+ group
2130
+ )) })
2131
+ }
2132
+ )
2133
+ ] }) : null
2134
+ }
2135
+ );
2136
+ }
2137
+
2138
+ // src/ant/components/UserDetailCard/UserDetailCard.tsx
2139
+ import {
2140
+ SafetyOutlined as SafetyOutlined3,
2141
+ GlobalOutlined as GlobalOutlined5,
2142
+ BankOutlined as BankOutlined6,
2143
+ BranchesOutlined as BranchesOutlined4,
2144
+ TeamOutlined as TeamOutlined2,
2145
+ DeleteOutlined as DeleteOutlined2,
2146
+ PlusOutlined as PlusOutlined3,
2147
+ ReloadOutlined as ReloadOutlined2,
2148
+ KeyOutlined
2149
+ } from "@ant-design/icons";
2150
+ import {
2151
+ Card as Card3,
2152
+ Typography as Typography7,
2153
+ Button as Button6,
2154
+ Space as Space9,
2155
+ Tag as Tag4,
2156
+ Table as Table2,
2157
+ Tabs,
2158
+ Input as Input2,
2159
+ Select as Select6,
2160
+ Popconfirm as Popconfirm3,
2161
+ Empty as Empty2
2162
+ } from "antd";
2163
+ import { useState as useState7, useMemo as useMemo6 } from "react";
2164
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
2165
+ var { Title: Title3, Text: Text6, Link: AntLink } = Typography7;
2166
+ var defaultTranslations3 = {
2167
+ email: "\u30E1\u30FC\u30EB",
2168
+ primaryOrganization: "\u6240\u5C5E\u7D44\u7E54",
2169
+ currentContext: "\u73FE\u5728\u306E\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8",
2170
+ global: "\u30B0\u30ED\u30FC\u30D0\u30EB",
2171
+ created: "\u4F5C\u6210\u65E5",
2172
+ lastSignIn: "\u6700\u7D42\u30B5\u30A4\u30F3\u30A4\u30F3",
2173
+ roleAssignments: "\u30ED\u30FC\u30EB\u5272\u308A\u5F53\u3066",
2174
+ roles: "\u30ED\u30FC\u30EB",
2175
+ permissions: "\u6A29\u9650",
2176
+ teams: "\u30C1\u30FC\u30E0",
2177
+ aggregatedPermissions: "\u96C6\u7D04\u3055\u308C\u305F\u6A29\u9650",
2178
+ permissionPolicies: "\u6A29\u9650\u30DD\u30EA\u30B7\u30FC",
2179
+ permissionsDescription: "\u6A29\u9650\u306E\u8AAC\u660E",
2180
+ searchPermissions: "\u6A29\u9650\u3092\u691C\u7D22",
2181
+ allTypes: "\u3059\u3079\u3066\u306E\u30BF\u30A4\u30D7",
2182
+ viaRole: "\u30ED\u30FC\u30EB\u7D4C\u7531",
2183
+ viaTeam: "\u30C1\u30FC\u30E0\u7D4C\u7531",
2184
+ attachedVia: "\u4ED8\u4E0E\u5143",
2185
+ filterByType: "\u30BF\u30A4\u30D7\u3067\u30D5\u30A3\u30EB\u30BF",
2186
+ remove: "\u524A\u9664",
2187
+ addPermissions: "\u6A29\u9650\u3092\u8FFD\u52A0",
2188
+ assignRole: "\u30ED\u30FC\u30EB\u5272\u308A\u5F53\u3066",
2189
+ noRolesAssigned: "\u30ED\u30FC\u30EB\u304C\u5272\u308A\u5F53\u3066\u3089\u308C\u3066\u3044\u307E\u305B\u3093",
2190
+ level: "\u30EC\u30D9\u30EB",
2191
+ actions: "\u64CD\u4F5C",
2192
+ confirmRemoveRole: "\u3053\u306E\u30ED\u30FC\u30EB\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B\uFF1F",
2193
+ teamMemberships: "\u30C1\u30FC\u30E0\u30E1\u30F3\u30D0\u30FC\u30B7\u30C3\u30D7",
2194
+ noTeamMemberships: "\u30C1\u30FC\u30E0\u306B\u6240\u5C5E\u3057\u3066\u3044\u307E\u305B\u3093",
2195
+ teamLeader: "\u30EA\u30FC\u30C0\u30FC",
2196
+ noPermissions: "\u6A29\u9650\u304C\u3042\u308A\u307E\u305B\u3093",
2197
+ group: "\u30B0\u30EB\u30FC\u30D7"
2198
+ };
2199
+ function UserDetailCard({
2200
+ user,
2201
+ roleAssignments,
2202
+ teamMemberships,
2203
+ aggregatedPermissions,
2204
+ currentOrg,
2205
+ currentBranch,
2206
+ onRefresh,
2207
+ onAssignRole,
2208
+ onRemoveRole,
2209
+ onRoleClick,
2210
+ removeLoading = false,
2211
+ translations: t = {}
2212
+ }) {
2213
+ const labels = { ...defaultTranslations3, ...t };
2214
+ const [permissionSearch, setPermissionSearch] = useState7("");
2215
+ const [permissionTypeFilter, setPermissionTypeFilter] = useState7("all");
2216
+ const getScopeLabel = (assignment) => {
2217
+ if (assignment.scope === "global") return labels.global;
2218
+ if (assignment.scope === "org-wide") return assignment.org_name || labels.global;
2219
+ return assignment.branch_name || labels.global;
2220
+ };
2221
+ const permissionsTableData = roleAssignments.flatMap(
2222
+ (assignment) => assignment.permissions.map((perm) => ({
2223
+ key: `${assignment.role.id}-${perm.slug}`,
2224
+ permission: perm.slug,
2225
+ permissionName: perm.name,
2226
+ permissionGroup: perm.group,
2227
+ type: "role",
2228
+ attachedVia: assignment.role.name,
2229
+ scope: assignment.scope,
2230
+ roleId: assignment.role.id,
2231
+ consoleOrgId: assignment.console_org_id,
2232
+ consoleBranchId: assignment.console_branch_id
2233
+ }))
2234
+ );
2235
+ const teamPermissionsData = teamMemberships.flatMap(
2236
+ (membership) => membership.permissions.map((perm) => ({
2237
+ key: `team-${membership.team.id}-${perm.slug}`,
2238
+ permission: perm.slug,
2239
+ permissionName: perm.name,
2240
+ permissionGroup: perm.group,
2241
+ type: "team",
2242
+ attachedVia: membership.team.name,
2243
+ scope: "team"
2244
+ }))
2245
+ );
2246
+ const allPermissionsData = [...permissionsTableData, ...teamPermissionsData];
2247
+ const filteredPermissions = allPermissionsData.filter((p) => {
2248
+ const matchesSearch = !permissionSearch || p.permission.toLowerCase().includes(permissionSearch.toLowerCase());
2249
+ const matchesType = permissionTypeFilter === "all" || p.type === permissionTypeFilter;
2250
+ return matchesSearch && matchesType;
2251
+ });
2252
+ const groupedAggregatedPermissions = useMemo6(
2253
+ () => aggregatedPermissions.reduce((acc, perm) => {
2254
+ const group = perm.split(".").slice(0, -1).join(".") || "other";
2255
+ if (!acc[group]) acc[group] = [];
2256
+ acc[group].push(perm);
2257
+ return acc;
2258
+ }, {}),
2259
+ [aggregatedPermissions]
2260
+ );
2261
+ const tabItems = [
2262
+ {
2263
+ key: "permissions",
2264
+ label: /* @__PURE__ */ jsxs11("span", { children: [
2265
+ /* @__PURE__ */ jsx13(KeyOutlined, {}),
2266
+ " ",
2267
+ labels.permissions
2268
+ ] }),
2269
+ children: /* @__PURE__ */ jsxs11("div", { children: [
2270
+ /* @__PURE__ */ jsxs11(
2271
+ "div",
2272
+ {
2273
+ style: {
2274
+ display: "flex",
2275
+ justifyContent: "space-between",
2276
+ alignItems: "center",
2277
+ marginBottom: 16
2278
+ },
2279
+ children: [
2280
+ /* @__PURE__ */ jsxs11("div", { children: [
2281
+ /* @__PURE__ */ jsxs11(Title3, { level: 5, style: { margin: 0 }, children: [
2282
+ labels.permissionPolicies,
2283
+ " (",
2284
+ allPermissionsData.length,
2285
+ ")"
2286
+ ] }),
2287
+ /* @__PURE__ */ jsx13(Text6, { type: "secondary", style: { fontSize: 12 }, children: labels.permissionsDescription })
2288
+ ] }),
2289
+ /* @__PURE__ */ jsxs11(Space9, { children: [
2290
+ onRefresh && /* @__PURE__ */ jsx13(Button6, { icon: /* @__PURE__ */ jsx13(ReloadOutlined2, {}), onClick: onRefresh }),
2291
+ /* @__PURE__ */ jsx13(Button6, { type: "default", children: labels.remove }),
2292
+ /* @__PURE__ */ jsx13(Button6, { type: "primary", icon: /* @__PURE__ */ jsx13(PlusOutlined3, {}), children: labels.addPermissions })
2293
+ ] })
2294
+ ]
2295
+ }
2296
+ ),
2297
+ /* @__PURE__ */ jsxs11("div", { style: { display: "flex", gap: 16, marginBottom: 16 }, children: [
2298
+ /* @__PURE__ */ jsx13(
2299
+ Input2,
2300
+ {
2301
+ placeholder: labels.searchPermissions,
2302
+ prefix: /* @__PURE__ */ jsx13(KeyOutlined, {}),
2303
+ value: permissionSearch,
2304
+ onChange: (e) => setPermissionSearch(e.target.value),
2305
+ style: { width: 300 }
2306
+ }
2307
+ ),
2308
+ /* @__PURE__ */ jsx13(
2309
+ Select6,
2310
+ {
2311
+ value: permissionTypeFilter,
2312
+ onChange: setPermissionTypeFilter,
2313
+ style: { width: 200 },
2314
+ options: [
2315
+ { value: "all", label: labels.allTypes },
2316
+ { value: "role", label: labels.viaRole },
2317
+ { value: "team", label: labels.viaTeam }
2318
+ ]
2319
+ }
2320
+ )
2321
+ ] }),
2322
+ /* @__PURE__ */ jsx13(
2323
+ Table2,
2324
+ {
2325
+ dataSource: filteredPermissions,
2326
+ pagination: { pageSize: 10 },
2327
+ columns: [
2328
+ {
2329
+ title: labels.permissions,
2330
+ dataIndex: "permission",
2331
+ key: "permission",
2332
+ render: (perm) => /* @__PURE__ */ jsxs11(Space9, { children: [
2333
+ /* @__PURE__ */ jsx13(KeyOutlined, { style: { color: "#faad14" } }),
2334
+ /* @__PURE__ */ jsx13(AntLink, { children: perm })
2335
+ ] })
2336
+ },
2337
+ {
2338
+ title: labels.filterByType,
2339
+ dataIndex: "type",
2340
+ key: "type",
2341
+ width: 150,
2342
+ render: (type) => /* @__PURE__ */ jsx13(Tag4, { color: type === "role" ? "blue" : "green", children: type === "role" ? labels.viaRole : labels.viaTeam })
2343
+ },
2344
+ {
2345
+ title: labels.attachedVia,
2346
+ dataIndex: "attachedVia",
2347
+ key: "attachedVia",
2348
+ width: 200,
2349
+ render: (via, record) => /* @__PURE__ */ jsxs11(Space9, { children: [
2350
+ record.type === "role" ? /* @__PURE__ */ jsx13(SafetyOutlined3, {}) : /* @__PURE__ */ jsx13(TeamOutlined2, {}),
2351
+ /* @__PURE__ */ jsx13(Text6, { children: via }),
2352
+ record.scope && record.scope !== "team" && /* @__PURE__ */ jsx13(Tag4, { color: getScopeColor(record.scope), style: { fontSize: 12 }, children: record.scope })
2353
+ ] })
2354
+ }
2355
+ ]
2356
+ }
2357
+ )
2358
+ ] })
2359
+ },
2360
+ {
2361
+ key: "roles",
2362
+ label: /* @__PURE__ */ jsxs11("span", { children: [
2363
+ /* @__PURE__ */ jsx13(SafetyOutlined3, {}),
2364
+ " ",
2365
+ labels.roles,
2366
+ " (",
2367
+ roleAssignments.length,
2368
+ ")"
2369
+ ] }),
2370
+ children: /* @__PURE__ */ jsxs11("div", { children: [
2371
+ /* @__PURE__ */ jsxs11(
2372
+ "div",
2373
+ {
2374
+ style: {
2375
+ display: "flex",
2376
+ justifyContent: "space-between",
2377
+ alignItems: "center",
2378
+ marginBottom: 16
2379
+ },
2380
+ children: [
2381
+ /* @__PURE__ */ jsx13(Title3, { level: 5, style: { margin: 0 }, children: labels.roleAssignments }),
2382
+ onAssignRole && /* @__PURE__ */ jsx13(Button6, { type: "primary", icon: /* @__PURE__ */ jsx13(PlusOutlined3, {}), onClick: onAssignRole, children: labels.assignRole })
2383
+ ]
2384
+ }
2385
+ ),
2386
+ roleAssignments.length === 0 ? /* @__PURE__ */ jsx13(Empty2, { description: labels.noRolesAssigned }) : /* @__PURE__ */ jsx13(
2387
+ Table2,
2388
+ {
2389
+ dataSource: roleAssignments,
2390
+ rowKey: (r) => `${r.role.id}-${r.console_org_id}-${r.console_branch_id}`,
2391
+ columns: [
2392
+ {
2393
+ title: labels.roles,
2394
+ key: "role",
2395
+ render: (_, record) => /* @__PURE__ */ jsxs11(Space9, { children: [
2396
+ /* @__PURE__ */ jsx13(SafetyOutlined3, { style: { color: "#1890ff" } }),
2397
+ /* @__PURE__ */ jsx13(
2398
+ Text6,
2399
+ {
2400
+ strong: true,
2401
+ style: { color: "#1890ff", cursor: onRoleClick ? "pointer" : "default" },
2402
+ onClick: () => onRoleClick?.(record.role.id),
2403
+ children: record.role.name
2404
+ }
2405
+ ),
2406
+ /* @__PURE__ */ jsx13(Tag4, { color: "default", children: record.role.slug })
2407
+ ] })
2408
+ },
2409
+ {
2410
+ title: labels.global,
2411
+ key: "scope",
2412
+ width: 200,
2413
+ render: (_, record) => /* @__PURE__ */ jsx13(Tag4, { color: getScopeColor(record.scope), children: getScopeLabel(record) })
2414
+ },
2415
+ {
2416
+ title: labels.level,
2417
+ dataIndex: ["role", "level"],
2418
+ key: "level",
2419
+ width: 100
2420
+ },
2421
+ {
2422
+ title: labels.permissions,
2423
+ key: "permissions",
2424
+ width: 150,
2425
+ render: (_, record) => /* @__PURE__ */ jsxs11(Text6, { children: [
2426
+ record.permissions.length,
2427
+ " ",
2428
+ labels.permissions.toLowerCase()
2429
+ ] })
2430
+ },
2431
+ {
2432
+ title: labels.actions,
2433
+ key: "actions",
2434
+ width: 100,
2435
+ render: (_, record) => onRemoveRole && /* @__PURE__ */ jsx13(
2436
+ Popconfirm3,
2437
+ {
2438
+ title: labels.confirmRemoveRole,
2439
+ onConfirm: () => onRemoveRole(
2440
+ record.role.id,
2441
+ record.console_org_id,
2442
+ record.console_branch_id
2443
+ ),
2444
+ children: /* @__PURE__ */ jsx13(
2445
+ Button6,
2446
+ {
2447
+ type: "text",
2448
+ danger: true,
2449
+ icon: /* @__PURE__ */ jsx13(DeleteOutlined2, {}),
2450
+ loading: removeLoading
2451
+ }
2452
+ )
2453
+ }
2454
+ )
2455
+ }
2456
+ ]
2457
+ }
2458
+ )
2459
+ ] })
2460
+ },
2461
+ {
2462
+ key: "teams",
2463
+ label: /* @__PURE__ */ jsxs11("span", { children: [
2464
+ /* @__PURE__ */ jsx13(TeamOutlined2, {}),
2465
+ " ",
2466
+ labels.teams,
2467
+ " (",
2468
+ teamMemberships.length,
2469
+ ")"
2470
+ ] }),
2471
+ children: /* @__PURE__ */ jsxs11("div", { children: [
2472
+ /* @__PURE__ */ jsx13(Title3, { level: 5, style: { marginBottom: 16 }, children: labels.teamMemberships }),
2473
+ teamMemberships.length === 0 ? /* @__PURE__ */ jsx13(Empty2, { description: labels.noTeamMemberships }) : /* @__PURE__ */ jsx13(
2474
+ Table2,
2475
+ {
2476
+ dataSource: teamMemberships,
2477
+ rowKey: (m) => m.team.id,
2478
+ columns: [
2479
+ {
2480
+ title: labels.teams,
2481
+ key: "team",
2482
+ render: (_, record) => /* @__PURE__ */ jsxs11(Space9, { children: [
2483
+ /* @__PURE__ */ jsx13(TeamOutlined2, { style: { color: "#52c41a" } }),
2484
+ /* @__PURE__ */ jsx13(Text6, { strong: true, children: record.team.name }),
2485
+ record.team.path && /* @__PURE__ */ jsxs11(Text6, { type: "secondary", children: [
2486
+ "(",
2487
+ record.team.path,
2488
+ ")"
2489
+ ] })
2490
+ ] })
2491
+ },
2492
+ {
2493
+ title: labels.teamLeader,
2494
+ key: "leader",
2495
+ width: 150,
2496
+ render: (_, record) => record.is_leader ? /* @__PURE__ */ jsx13(Tag4, { color: "gold", children: labels.teamLeader }) : /* @__PURE__ */ jsx13(Text6, { type: "secondary", children: "-" })
2497
+ },
2498
+ {
2499
+ title: labels.permissions,
2500
+ key: "permissions",
2501
+ width: 150,
2502
+ render: (_, record) => /* @__PURE__ */ jsxs11(Text6, { children: [
2503
+ record.permissions.length,
2504
+ " ",
2505
+ labels.permissions.toLowerCase()
2506
+ ] })
2507
+ }
2508
+ ]
2509
+ }
2510
+ )
2511
+ ] })
2512
+ },
2513
+ {
2514
+ key: "aggregated",
2515
+ label: /* @__PURE__ */ jsxs11("span", { children: [
2516
+ /* @__PURE__ */ jsx13(SafetyOutlined3, {}),
2517
+ " ",
2518
+ labels.aggregatedPermissions,
2519
+ " (",
2520
+ aggregatedPermissions.length,
2521
+ ")"
2522
+ ] }),
2523
+ children: /* @__PURE__ */ jsxs11("div", { children: [
2524
+ /* @__PURE__ */ jsx13(Title3, { level: 5, style: { marginBottom: 16 }, children: labels.aggregatedPermissions }),
2525
+ /* @__PURE__ */ jsx13(Text6, { type: "secondary", style: { display: "block", marginBottom: 16 }, children: "\u3059\u3079\u3066\u306E\u30ED\u30FC\u30EB\u3068\u30C1\u30FC\u30E0\u304B\u3089\u96C6\u7D04\u3055\u308C\u305F\u6A29\u9650\u306E\u4E00\u89A7\u3067\u3059\u3002" }),
2526
+ aggregatedPermissions.length === 0 ? /* @__PURE__ */ jsx13(Empty2, { description: labels.noPermissions }) : /* @__PURE__ */ jsx13(
2527
+ Table2,
2528
+ {
2529
+ dataSource: aggregatedPermissions.map((perm) => ({
2530
+ key: perm,
2531
+ permission: perm,
2532
+ group: perm.split(".").slice(0, -1).join(".") || "other",
2533
+ action: perm.split(".").pop() || perm
2534
+ })),
2535
+ pagination: { pageSize: 20 },
2536
+ size: "small",
2537
+ columns: [
2538
+ {
2539
+ title: labels.group,
2540
+ dataIndex: "group",
2541
+ key: "group",
2542
+ width: 200,
2543
+ filters: Object.keys(groupedAggregatedPermissions).map((g) => ({
2544
+ text: g,
2545
+ value: g
2546
+ })),
2547
+ onFilter: (value, record) => record.group === value,
2548
+ render: (group) => /* @__PURE__ */ jsx13(Tag4, { icon: /* @__PURE__ */ jsx13(SafetyOutlined3, {}), color: "blue", children: group })
2549
+ },
2550
+ {
2551
+ title: labels.permissions,
2552
+ dataIndex: "permission",
2553
+ key: "permission",
2554
+ render: (perm) => /* @__PURE__ */ jsxs11(Space9, { children: [
2555
+ /* @__PURE__ */ jsx13(KeyOutlined, { style: { color: "#faad14" } }),
2556
+ /* @__PURE__ */ jsx13(Text6, { children: perm })
2557
+ ] })
2558
+ },
2559
+ {
2560
+ title: "Action",
2561
+ dataIndex: "action",
2562
+ key: "action",
2563
+ width: 150,
2564
+ render: (action) => /* @__PURE__ */ jsx13(Tag4, { color: "green", children: action })
2565
+ }
2566
+ ]
2567
+ }
2568
+ )
2569
+ ] })
2570
+ }
2571
+ ];
2572
+ return /* @__PURE__ */ jsxs11("div", { children: [
2573
+ /* @__PURE__ */ jsx13(Card3, { size: "small", style: { marginBottom: 24 }, styles: { body: { padding: "16px 24px" } }, children: /* @__PURE__ */ jsxs11(
2574
+ "div",
2575
+ {
2576
+ style: {
2577
+ display: "grid",
2578
+ gridTemplateColumns: "repeat(3, 1fr)",
2579
+ gap: "20px 48px"
2580
+ },
2581
+ children: [
2582
+ /* @__PURE__ */ jsxs11("div", { children: [
2583
+ /* @__PURE__ */ jsx13(Text6, { type: "secondary", style: { fontSize: 12, display: "block", marginBottom: 4 }, children: labels.email }),
2584
+ /* @__PURE__ */ jsx13(Text6, { copyable: true, style: { fontSize: 14 }, children: user?.email || "-" })
2585
+ ] }),
2586
+ /* @__PURE__ */ jsxs11("div", { children: [
2587
+ /* @__PURE__ */ jsx13(Text6, { type: "secondary", style: { fontSize: 12, display: "block", marginBottom: 4 }, children: labels.primaryOrganization }),
2588
+ user?.organization ? /* @__PURE__ */ jsxs11(Space9, { size: 4, children: [
2589
+ /* @__PURE__ */ jsx13(BankOutlined6, { style: { color: "#1890ff" } }),
2590
+ /* @__PURE__ */ jsx13(Text6, { style: { fontSize: 14 }, children: user.organization.name })
2591
+ ] }) : /* @__PURE__ */ jsxs11(Space9, { size: 4, children: [
2592
+ /* @__PURE__ */ jsx13(GlobalOutlined5, { style: { color: "#722ed1" } }),
2593
+ /* @__PURE__ */ jsx13(Text6, { style: { fontSize: 14 }, children: labels.global })
2594
+ ] })
2595
+ ] }),
2596
+ /* @__PURE__ */ jsxs11("div", { children: [
2597
+ /* @__PURE__ */ jsx13(Text6, { type: "secondary", style: { fontSize: 12, display: "block", marginBottom: 4 }, children: labels.currentContext }),
2598
+ /* @__PURE__ */ jsxs11(Space9, { size: 16, wrap: true, children: [
2599
+ currentOrg && /* @__PURE__ */ jsxs11(Space9, { size: 4, children: [
2600
+ /* @__PURE__ */ jsx13(BankOutlined6, { style: { color: "#1890ff" } }),
2601
+ /* @__PURE__ */ jsx13(Text6, { style: { fontSize: 14 }, children: currentOrg.name })
2602
+ ] }),
2603
+ currentBranch && /* @__PURE__ */ jsxs11(Space9, { size: 4, children: [
2604
+ /* @__PURE__ */ jsx13(BranchesOutlined4, { style: { color: "#52c41a" } }),
2605
+ /* @__PURE__ */ jsx13(Text6, { style: { fontSize: 14 }, children: currentBranch.name })
2606
+ ] })
2607
+ ] })
2608
+ ] }),
2609
+ /* @__PURE__ */ jsxs11("div", { children: [
2610
+ /* @__PURE__ */ jsx13(Text6, { type: "secondary", style: { fontSize: 12, display: "block", marginBottom: 4 }, children: labels.created }),
2611
+ /* @__PURE__ */ jsx13(Text6, { style: { fontSize: 14 }, children: user?.created_at ? new Date(user.created_at).toLocaleDateString() : "-" })
2612
+ ] }),
2613
+ /* @__PURE__ */ jsxs11("div", { children: [
2614
+ /* @__PURE__ */ jsx13(Text6, { type: "secondary", style: { fontSize: 12, display: "block", marginBottom: 4 }, children: labels.lastSignIn }),
2615
+ /* @__PURE__ */ jsx13(Text6, { style: { fontSize: 14 }, children: "-" })
2616
+ ] }),
2617
+ /* @__PURE__ */ jsxs11("div", { children: [
2618
+ /* @__PURE__ */ jsx13(Text6, { type: "secondary", style: { fontSize: 12, display: "block", marginBottom: 4 }, children: labels.roleAssignments }),
2619
+ /* @__PURE__ */ jsxs11(Text6, { style: { fontSize: 14 }, children: [
2620
+ /* @__PURE__ */ jsx13(Text6, { strong: true, children: roleAssignments.length }),
2621
+ " ",
2622
+ labels.roles.toLowerCase()
2623
+ ] })
2624
+ ] })
2625
+ ]
2626
+ }
2627
+ ) }),
2628
+ /* @__PURE__ */ jsx13(Card3, { children: /* @__PURE__ */ jsx13(Tabs, { defaultActiveKey: "permissions", items: tabItems }) })
2629
+ ] });
2630
+ }
2631
+
2632
+ // src/ant/components/RoleCreateModal/RoleCreateModal.tsx
2633
+ import { PlusOutlined as PlusOutlined4, GlobalOutlined as GlobalOutlined6, BankOutlined as BankOutlined7 } from "@ant-design/icons";
2634
+ import { Modal as Modal5, Form as Form4, Input as Input3, InputNumber as InputNumber2, Select as Select7, Radio as Radio2, Button as Button7, Space as Space10 } from "antd";
2635
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
2636
+ var defaultTranslations4 = {
2637
+ title: "\u30ED\u30FC\u30EB\u4F5C\u6210",
2638
+ name: "\u540D\u524D",
2639
+ slug: "\u30B9\u30E9\u30C3\u30B0",
2640
+ description: "\u8AAC\u660E",
2641
+ level: "\u30EC\u30D9\u30EB",
2642
+ scope: "\u30B9\u30B3\u30FC\u30D7",
2643
+ global: "\u30B0\u30ED\u30FC\u30D0\u30EB",
2644
+ orgRole: "\u7D44\u7E54\u30ED\u30FC\u30EB",
2645
+ organization: "\u7D44\u7E54",
2646
+ create: "\u4F5C\u6210",
2647
+ cancel: "\u30AD\u30E3\u30F3\u30BB\u30EB",
2648
+ required: "\u5FC5\u9808\u9805\u76EE\u3067\u3059"
2649
+ };
2650
+ function RoleCreateModal({
2651
+ open,
2652
+ organizations,
2653
+ currentOrgId,
2654
+ loading = false,
2655
+ onSubmit,
2656
+ onCancel,
2657
+ translations: t = {}
2658
+ }) {
2659
+ const [form] = Form4.useForm();
2660
+ const labels = { ...defaultTranslations4, ...t };
2661
+ const handleFinish = async (values) => {
2662
+ await onSubmit(values);
2663
+ form.resetFields();
2664
+ };
2665
+ const handleCancel = () => {
2666
+ form.resetFields();
2667
+ onCancel();
2668
+ };
2669
+ return /* @__PURE__ */ jsx14(
2670
+ Modal5,
2671
+ {
2672
+ title: /* @__PURE__ */ jsxs12(Space10, { children: [
2673
+ /* @__PURE__ */ jsx14(PlusOutlined4, {}),
2674
+ labels.title
2675
+ ] }),
2676
+ open,
2677
+ onCancel: handleCancel,
2678
+ footer: null,
2679
+ destroyOnHidden: true,
2680
+ children: /* @__PURE__ */ jsxs12(
2681
+ Form4,
2682
+ {
2683
+ form,
2684
+ layout: "vertical",
2685
+ onFinish: handleFinish,
2686
+ initialValues: { level: 50, scope: "org", org_id: currentOrgId },
2687
+ children: [
2688
+ /* @__PURE__ */ jsx14(
2689
+ Form4.Item,
2690
+ {
2691
+ name: "scope",
2692
+ label: labels.scope,
2693
+ rules: [{ required: true, message: labels.required }],
2694
+ children: /* @__PURE__ */ jsxs12(Radio2.Group, { children: [
2695
+ /* @__PURE__ */ jsx14(Radio2, { value: "global", children: /* @__PURE__ */ jsxs12(Space10, { children: [
2696
+ /* @__PURE__ */ jsx14(GlobalOutlined6, {}),
2697
+ labels.global
2698
+ ] }) }),
2699
+ /* @__PURE__ */ jsx14(Radio2, { value: "org", children: /* @__PURE__ */ jsxs12(Space10, { children: [
2700
+ /* @__PURE__ */ jsx14(BankOutlined7, {}),
2701
+ labels.orgRole
2702
+ ] }) })
2703
+ ] })
2704
+ }
2705
+ ),
2706
+ /* @__PURE__ */ jsx14(Form4.Item, { noStyle: true, shouldUpdate: (prev, curr) => prev.scope !== curr.scope, children: ({ getFieldValue }) => getFieldValue("scope") === "org" && /* @__PURE__ */ jsx14(
2707
+ Form4.Item,
2708
+ {
2709
+ name: "org_id",
2710
+ label: labels.organization,
2711
+ rules: [{ required: true, message: labels.required }],
2712
+ children: /* @__PURE__ */ jsx14(Select7, { placeholder: labels.organization, children: organizations.map((org) => /* @__PURE__ */ jsx14(Select7.Option, { value: String(org.id), children: /* @__PURE__ */ jsxs12(Space10, { children: [
2713
+ /* @__PURE__ */ jsx14(BankOutlined7, {}),
2714
+ org.name
2715
+ ] }) }, org.id)) })
2716
+ }
2717
+ ) }),
2718
+ /* @__PURE__ */ jsx14(
2719
+ Form4.Item,
2720
+ {
2721
+ name: "name",
2722
+ label: labels.name,
2723
+ rules: [{ required: true, message: labels.required }],
2724
+ children: /* @__PURE__ */ jsx14(Input3, {})
2725
+ }
2726
+ ),
2727
+ /* @__PURE__ */ jsx14(
2728
+ Form4.Item,
2729
+ {
2730
+ name: "slug",
2731
+ label: labels.slug,
2732
+ rules: [{ required: true, message: labels.required }],
2733
+ children: /* @__PURE__ */ jsx14(Input3, {})
2734
+ }
2735
+ ),
2736
+ /* @__PURE__ */ jsx14(Form4.Item, { name: "description", label: labels.description, children: /* @__PURE__ */ jsx14(Input3.TextArea, { rows: 3 }) }),
2737
+ /* @__PURE__ */ jsx14(
2738
+ Form4.Item,
2739
+ {
2740
+ name: "level",
2741
+ label: labels.level,
2742
+ rules: [{ required: true, message: labels.required }],
2743
+ children: /* @__PURE__ */ jsx14(InputNumber2, { min: 1, max: 100, style: { width: "100%" } })
2744
+ }
2745
+ ),
2746
+ /* @__PURE__ */ jsx14(Form4.Item, { children: /* @__PURE__ */ jsxs12(Space10, { children: [
2747
+ /* @__PURE__ */ jsx14(Button7, { type: "primary", htmlType: "submit", loading, children: labels.create }),
2748
+ /* @__PURE__ */ jsx14(Button7, { onClick: handleCancel, children: labels.cancel })
2749
+ ] }) })
2750
+ ]
2751
+ }
2752
+ )
2753
+ }
2754
+ );
2755
+ }
2756
+
2757
+ // src/ant/components/RolesListCard/RolesListCard.tsx
2758
+ import {
2759
+ SafetyOutlined as SafetyOutlined4,
2760
+ PlusOutlined as PlusOutlined5,
2761
+ EyeOutlined,
2762
+ DeleteOutlined as DeleteOutlined3,
2763
+ GlobalOutlined as GlobalOutlined7,
2764
+ BankOutlined as BankOutlined8
2765
+ } from "@ant-design/icons";
2766
+ import { Card as Card4, Typography as Typography8, Button as Button8, Space as Space11, Tag as Tag5, Select as Select8, Table as Table3, Popconfirm as Popconfirm4 } from "antd";
2767
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
2768
+ var { Text: Text7 } = Typography8;
2769
+ var defaultTranslations5 = {
2770
+ name: "\u540D\u524D",
2771
+ scope: "\u30B9\u30B3\u30FC\u30D7",
2772
+ level: "\u30EC\u30D9\u30EB",
2773
+ description: "\u8AAC\u660E",
2774
+ actions: "\u64CD\u4F5C",
2775
+ detail: "\u8A73\u7D30",
2776
+ global: "\u30B0\u30ED\u30FC\u30D0\u30EB",
2777
+ orgRole: "\u7D44\u7E54\u30ED\u30FC\u30EB",
2778
+ all: "\u3059\u3079\u3066",
2779
+ confirmDeleteRole: "\u3053\u306E\u30ED\u30FC\u30EB\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B\uFF1F"
2780
+ };
2781
+ function RolesListCard({
2782
+ roles,
2783
+ loading = false,
2784
+ scopeFilter,
2785
+ onScopeFilterChange,
2786
+ onCreateClick,
2787
+ onViewClick,
2788
+ onDeleteClick,
2789
+ translations: t = {}
2790
+ }) {
2791
+ const labels = { ...defaultTranslations5, ...t };
2792
+ const columns = [
2793
+ {
2794
+ title: labels.name,
2795
+ dataIndex: "name",
2796
+ key: "name",
2797
+ render: (name, record) => /* @__PURE__ */ jsxs13(Space11, { children: [
2798
+ /* @__PURE__ */ jsx15(SafetyOutlined4, { style: { color: "#1890ff" } }),
2799
+ /* @__PURE__ */ jsx15(Text7, { strong: true, children: name }),
2800
+ /* @__PURE__ */ jsx15(Tag5, { children: record.slug })
2801
+ ] })
2802
+ },
2803
+ {
2804
+ title: labels.scope,
2805
+ dataIndex: "console_org_id",
2806
+ key: "scope",
2807
+ width: 180,
2808
+ render: (_, record) => record.console_org_id ? /* @__PURE__ */ jsx15(Tag5, { icon: /* @__PURE__ */ jsx15(BankOutlined8, {}), color: "blue", children: record.organization?.name || record.console_org_id }) : /* @__PURE__ */ jsx15(Tag5, { icon: /* @__PURE__ */ jsx15(GlobalOutlined7, {}), color: "purple", children: labels.global })
2809
+ },
2810
+ {
2811
+ title: labels.level,
2812
+ dataIndex: "level",
2813
+ key: "level",
2814
+ width: 100,
2815
+ render: (level) => /* @__PURE__ */ jsx15(Tag5, { color: "blue", children: level })
2816
+ },
2817
+ {
2818
+ title: labels.description,
2819
+ dataIndex: "description",
2820
+ key: "description",
2821
+ ellipsis: true
2822
+ },
2823
+ {
2824
+ title: labels.actions,
2825
+ key: "actions",
2826
+ width: 180,
2827
+ render: (_, record) => /* @__PURE__ */ jsxs13(Space11, { children: [
2828
+ /* @__PURE__ */ jsx15(Button8, { size: "small", icon: /* @__PURE__ */ jsx15(EyeOutlined, {}), onClick: () => onViewClick(record), children: labels.detail }),
2829
+ /* @__PURE__ */ jsx15(Popconfirm4, { title: labels.confirmDeleteRole, onConfirm: () => onDeleteClick(record), children: /* @__PURE__ */ jsx15(Button8, { size: "small", danger: true, icon: /* @__PURE__ */ jsx15(DeleteOutlined3, {}) }) })
2830
+ ] })
2831
+ }
2832
+ ];
2833
+ return /* @__PURE__ */ jsxs13(
2834
+ Card4,
2835
+ {
2836
+ title: /* @__PURE__ */ jsxs13(Space11, { children: [
2837
+ /* @__PURE__ */ jsx15(SafetyOutlined4, {}),
2838
+ "Roles"
2839
+ ] }),
2840
+ extra: /* @__PURE__ */ jsx15(Button8, { type: "primary", icon: /* @__PURE__ */ jsx15(PlusOutlined5, {}), onClick: onCreateClick, children: "Create" }),
2841
+ children: [
2842
+ /* @__PURE__ */ jsx15("div", { style: { marginBottom: 16, display: "flex", gap: 16 }, children: /* @__PURE__ */ jsxs13(
2843
+ Select8,
2844
+ {
2845
+ value: scopeFilter,
2846
+ onChange: onScopeFilterChange,
2847
+ style: { minWidth: 200 },
2848
+ children: [
2849
+ /* @__PURE__ */ jsx15(Select8.Option, { value: "all", children: /* @__PURE__ */ jsxs13(Space11, { children: [
2850
+ /* @__PURE__ */ jsx15(SafetyOutlined4, {}),
2851
+ labels.all
2852
+ ] }) }),
2853
+ /* @__PURE__ */ jsx15(Select8.Option, { value: "global", children: /* @__PURE__ */ jsxs13(Space11, { children: [
2854
+ /* @__PURE__ */ jsx15(GlobalOutlined7, {}),
2855
+ labels.global
2856
+ ] }) }),
2857
+ /* @__PURE__ */ jsx15(Select8.Option, { value: "org", children: /* @__PURE__ */ jsxs13(Space11, { children: [
2858
+ /* @__PURE__ */ jsx15(BankOutlined8, {}),
2859
+ labels.orgRole
2860
+ ] }) })
2861
+ ]
2862
+ }
2863
+ ) }),
2864
+ /* @__PURE__ */ jsx15(
2865
+ Table3,
2866
+ {
2867
+ columns,
2868
+ dataSource: roles,
2869
+ rowKey: "id",
2870
+ loading,
2871
+ pagination: { pageSize: 10 }
2872
+ }
2873
+ )
2874
+ ]
2875
+ }
2876
+ );
2877
+ }
2878
+
2879
+ // src/ant/components/PermissionsListCard/PermissionsListCard.tsx
2880
+ import { KeyOutlined as KeyOutlined2, AppstoreOutlined } from "@ant-design/icons";
2881
+ import { Card as Card5, Typography as Typography9, Tag as Tag6, Table as Table4, Input as Input4, Space as Space12, Collapse as Collapse2 } from "antd";
2882
+ import { useState as useState8, useMemo as useMemo7 } from "react";
2883
+ import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
2884
+ var { Text: Text8 } = Typography9;
2885
+ var defaultTranslations6 = {
2886
+ searchPermissions: "\u6A29\u9650\u3092\u691C\u7D22",
2887
+ name: "\u540D\u524D",
2888
+ slug: "\u30B9\u30E9\u30C3\u30B0",
2889
+ group: "\u30B0\u30EB\u30FC\u30D7",
2890
+ noData: "\u30C7\u30FC\u30BF\u304C\u3042\u308A\u307E\u305B\u3093"
2891
+ };
2892
+ function PermissionsListCard({
2893
+ permissions,
2894
+ groups,
2895
+ loading = false,
2896
+ translations: t = {},
2897
+ onGroupLabelRender
2898
+ }) {
2899
+ const [search, setSearch] = useState8("");
2900
+ const labels = { ...defaultTranslations6, ...t };
2901
+ const filteredPermissions = useMemo7(() => {
2902
+ if (!search) return permissions;
2903
+ const lowerSearch = search.toLowerCase();
2904
+ return permissions.filter(
2905
+ (p) => p.name.toLowerCase().includes(lowerSearch) || p.slug.toLowerCase().includes(lowerSearch) || (p.group || "").toLowerCase().includes(lowerSearch)
2906
+ );
2907
+ }, [permissions, search]);
2908
+ const groupedPermissions = useMemo7(() => {
2909
+ const grouped = {};
2910
+ filteredPermissions.forEach((perm) => {
2911
+ const group = perm.group || "other";
2912
+ if (!grouped[group]) grouped[group] = [];
2913
+ grouped[group].push(perm);
2914
+ });
2915
+ return grouped;
2916
+ }, [filteredPermissions]);
2917
+ const getGroupLabel = (group) => {
2918
+ if (onGroupLabelRender) return onGroupLabelRender(group);
2919
+ return group;
2920
+ };
2921
+ const columns = [
2922
+ {
2923
+ title: labels.name,
2924
+ dataIndex: "name",
2925
+ key: "name",
2926
+ render: (name) => /* @__PURE__ */ jsxs14(Space12, { children: [
2927
+ /* @__PURE__ */ jsx16(KeyOutlined2, { style: { color: "#52c41a" } }),
2928
+ /* @__PURE__ */ jsx16(Text8, { strong: true, children: name })
2929
+ ] })
2930
+ },
2931
+ {
2932
+ title: labels.slug,
2933
+ dataIndex: "slug",
2934
+ key: "slug",
2935
+ render: (slug) => /* @__PURE__ */ jsx16(Tag6, { color: "blue", children: slug })
2936
+ },
2937
+ {
2938
+ title: labels.group,
2939
+ dataIndex: "group",
2940
+ key: "group",
2941
+ render: (group) => /* @__PURE__ */ jsx16(Tag6, { icon: /* @__PURE__ */ jsx16(AppstoreOutlined, {}), color: "purple", children: getGroupLabel(group || "other") })
2942
+ }
2943
+ ];
2944
+ return /* @__PURE__ */ jsxs14(Card5, { children: [
2945
+ /* @__PURE__ */ jsx16("div", { style: { marginBottom: 16 }, children: /* @__PURE__ */ jsx16(
2946
+ Input4.Search,
2947
+ {
2948
+ placeholder: labels.searchPermissions,
2949
+ allowClear: true,
2950
+ onSearch: setSearch,
2951
+ onChange: (e) => !e.target.value && setSearch(""),
2952
+ style: { maxWidth: 300 }
2953
+ }
2954
+ ) }),
2955
+ /* @__PURE__ */ jsx16(Collapse2, { defaultActiveKey: groups, ghost: true, children: Object.entries(groupedPermissions).map(([group, perms]) => /* @__PURE__ */ jsx16(
2956
+ Collapse2.Panel,
2957
+ {
2958
+ header: /* @__PURE__ */ jsxs14(Space12, { children: [
2959
+ /* @__PURE__ */ jsx16(AppstoreOutlined, { style: { color: "#722ed1" } }),
2960
+ /* @__PURE__ */ jsx16(Text8, { strong: true, children: getGroupLabel(group) }),
2961
+ /* @__PURE__ */ jsx16(Tag6, { children: perms.length })
2962
+ ] }),
2963
+ children: /* @__PURE__ */ jsx16(
2964
+ Table4,
2965
+ {
2966
+ columns,
2967
+ dataSource: perms,
2968
+ rowKey: "id",
2969
+ loading,
2970
+ pagination: false,
2971
+ size: "small"
2972
+ }
2973
+ )
2974
+ },
2975
+ group
2976
+ )) }),
2977
+ filteredPermissions.length === 0 && !loading && /* @__PURE__ */ jsx16("div", { style: { textAlign: "center", padding: 40 }, children: /* @__PURE__ */ jsx16(Text8, { type: "secondary", children: labels.noData }) })
2978
+ ] });
2979
+ }
2980
+
2981
+ // src/ant/components/TeamsListCard/TeamsListCard.tsx
2982
+ import { TeamOutlined as TeamOutlined3, KeyOutlined as KeyOutlined3, UserOutlined as UserOutlined2 } from "@ant-design/icons";
2983
+ import { Card as Card6, Typography as Typography10, Tag as Tag7, Table as Table5, Empty as Empty3 } from "antd";
2984
+ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
2985
+ var { Text: Text9 } = Typography10;
2986
+ var defaultTranslations7 = {
2987
+ name: "\u540D\u524D",
2988
+ memberCount: "\u30E1\u30F3\u30D0\u30FC\u6570",
2989
+ permissions: "\u6A29\u9650",
2990
+ noTeams: "\u30C1\u30FC\u30E0\u304C\u3042\u308A\u307E\u305B\u3093",
2991
+ teamsFromConsole: "\u30C1\u30FC\u30E0\u306F\u30B3\u30F3\u30BD\u30FC\u30EB\u304B\u3089\u7BA1\u7406\u3055\u308C\u307E\u3059",
2992
+ teamPermissions: "\u30C1\u30FC\u30E0\u6A29\u9650",
2993
+ noData: "\u30C7\u30FC\u30BF\u304C\u3042\u308A\u307E\u305B\u3093"
2994
+ };
2995
+ function TeamsListCard({
2996
+ teams,
2997
+ loading = false,
2998
+ translations: t = {}
2999
+ }) {
3000
+ const labels = { ...defaultTranslations7, ...t };
3001
+ const columns = [
3002
+ {
3003
+ title: labels.name,
3004
+ dataIndex: "name",
3005
+ key: "name",
3006
+ render: (name) => /* @__PURE__ */ jsxs15("span", { children: [
3007
+ /* @__PURE__ */ jsx17(TeamOutlined3, { style: { marginRight: 8, color: "#1890ff" } }),
3008
+ /* @__PURE__ */ jsx17(Text9, { strong: true, children: name })
3009
+ ] })
3010
+ },
3011
+ {
3012
+ title: labels.memberCount,
3013
+ dataIndex: "member_count",
3014
+ key: "member_count",
3015
+ width: 120,
3016
+ render: (count) => /* @__PURE__ */ jsx17(Tag7, { icon: /* @__PURE__ */ jsx17(UserOutlined2, {}), children: count })
3017
+ },
3018
+ {
3019
+ title: labels.permissions,
3020
+ dataIndex: "permissions",
3021
+ key: "permissions",
3022
+ render: (permissions) => /* @__PURE__ */ jsx17("span", { children: permissions.length > 0 ? /* @__PURE__ */ jsxs15(Tag7, { color: "blue", children: [
3023
+ permissions.length,
3024
+ " ",
3025
+ labels.permissions
3026
+ ] }) : /* @__PURE__ */ jsxs15(Tag7, { children: [
3027
+ "0 ",
3028
+ labels.permissions
3029
+ ] }) })
3030
+ }
3031
+ ];
3032
+ return /* @__PURE__ */ jsx17(Card6, { children: teams.length === 0 ? /* @__PURE__ */ jsx17(
3033
+ Empty3,
3034
+ {
3035
+ description: /* @__PURE__ */ jsxs15("span", { children: [
3036
+ labels.noTeams,
3037
+ /* @__PURE__ */ jsx17("br", {}),
3038
+ /* @__PURE__ */ jsx17(Text9, { type: "secondary", style: { fontSize: 12 }, children: labels.teamsFromConsole })
3039
+ ] })
3040
+ }
3041
+ ) : /* @__PURE__ */ jsx17(
3042
+ Table5,
3043
+ {
3044
+ columns,
3045
+ dataSource: teams,
3046
+ rowKey: "id",
3047
+ loading,
3048
+ pagination: { pageSize: 10 },
3049
+ expandable: {
3050
+ expandedRowRender: (record) => /* @__PURE__ */ jsxs15("div", { style: { padding: "8px 0" }, children: [
3051
+ /* @__PURE__ */ jsxs15(Text9, { strong: true, style: { marginBottom: 8, display: "block" }, children: [
3052
+ /* @__PURE__ */ jsx17(KeyOutlined3, { style: { marginRight: 4 } }),
3053
+ labels.teamPermissions,
3054
+ ":"
3055
+ ] }),
3056
+ record.permissions.length === 0 ? /* @__PURE__ */ jsx17(Text9, { type: "secondary", children: labels.noData }) : /* @__PURE__ */ jsx17("div", { style: { display: "flex", flexWrap: "wrap", gap: 4 }, children: record.permissions.map((perm) => /* @__PURE__ */ jsx17(Tag7, { color: "cyan", children: perm }, perm)) })
3057
+ ] })
3058
+ }
3059
+ }
3060
+ ) });
3061
+ }
3062
+
3063
+ // src/ant/theme/AntdThemeProvider.tsx
3064
+ import { App, ConfigProvider, theme as theme3 } from "antd";
3065
+ import enUS from "antd/locale/en_US";
3066
+ import jaJP from "antd/locale/ja_JP";
3067
+ import viVN from "antd/locale/vi_VN";
3068
+ import { useEffect as useEffect6 } from "react";
3069
+ import { jsx as jsx18 } from "react/jsx-runtime";
3070
+ var antdLocales = {
3071
+ ja: jaJP,
3072
+ en: enUS,
3073
+ vi: viVN
3074
+ };
3075
+ var fontFamilies = {
3076
+ // Japanese - CJK optimized fonts
3077
+ ja: "'Noto Sans JP', 'Hiragino Sans', 'Hiragino Kaku Gothic ProN', Meiryo, sans-serif",
3078
+ // English - Modern western fonts
3079
+ en: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
3080
+ // Vietnamese - Light, clean font with good diacritics
3081
+ vi: "'Inter', 'Nunito Sans', -apple-system, BlinkMacSystemFont, sans-serif"
3082
+ };
3083
+ var themeColors = {
3084
+ dashboard: {
3085
+ primary: "#7C3AED",
3086
+ // Violet
3087
+ siderBg: "#7C3AED",
3088
+ menuDarkItemBg: "#7C3AED",
3089
+ menuDarkSubMenuItemBg: "#6D28D9",
3090
+ menuDarkItemSelectedBg: "#9061F9",
3091
+ menuDarkItemHoverBg: "rgba(144, 97, 249, 0.6)"
3092
+ },
3093
+ admin: {
3094
+ primary: "#64748B",
3095
+ // Slate gray - professional admin look
3096
+ siderBg: "#475569",
3097
+ menuDarkItemBg: "#475569",
3098
+ menuDarkSubMenuItemBg: "#334155",
3099
+ menuDarkItemSelectedBg: "#64748B",
3100
+ menuDarkItemHoverBg: "rgba(100, 116, 139, 0.6)"
3101
+ }
3102
+ };
3103
+ function AntdThemeProvider({ children, variant = "dashboard", setDayjsLocale }) {
3104
+ const locale = useLocale();
3105
+ const antdLocale = antdLocales[locale] ?? jaJP;
3106
+ const fontFamily = fontFamilies[locale] ?? fontFamilies.ja;
3107
+ const colors = themeColors[variant];
3108
+ useEffect6(() => {
3109
+ setDayjsLocale?.(locale);
3110
+ }, [locale, setDayjsLocale]);
3111
+ return /* @__PURE__ */ jsx18(
3112
+ ConfigProvider,
3113
+ {
3114
+ locale: antdLocale,
3115
+ theme: {
3116
+ algorithm: theme3.defaultAlgorithm,
3117
+ token: {
3118
+ // ===========================================
3119
+ // Tempofast Design System (HSL-based harmony)
3120
+ // ===========================================
3121
+ // Primary - Dynamic based on variant
3122
+ colorPrimary: colors.primary,
3123
+ colorInfo: colors.primary,
3124
+ // Semantic Colors (Complementary harmony)
3125
+ colorSuccess: "#10B981",
3126
+ // HSL(160, 84%, 39%) - Teal-green, cool tone
3127
+ colorWarning: "#F59E0B",
3128
+ // HSL(38, 92%, 50%) - Amber, warm accent
3129
+ colorError: "#EF4444",
3130
+ // HSL(0, 84%, 60%) - Red, same saturation
3131
+ // Text - Neutral with slight violet undertone
3132
+ colorText: "#1E1B2E",
3133
+ // Near black with violet tint
3134
+ colorTextSecondary: "#4B5563",
3135
+ // Cool gray
3136
+ colorTextTertiary: "#9CA3AF",
3137
+ // Light cool gray
3138
+ // Background - Cool neutrals
3139
+ colorBgLayout: "#F8F7FA",
3140
+ // Very light violet-gray
3141
+ colorBgContainer: "#FFFFFF",
3142
+ colorBgElevated: "#FFFFFF",
3143
+ // Border - Subtle
3144
+ colorBorder: "#E5E7EB",
3145
+ colorBorderSecondary: "#F3F4F6",
3146
+ // Border Radius - Compact
3147
+ borderRadius: 4,
3148
+ borderRadiusSM: 2,
3149
+ borderRadiusLG: 6,
3150
+ // Control Heights - Compact
3151
+ controlHeight: 32,
3152
+ controlHeightLG: 36,
3153
+ controlHeightSM: 28,
3154
+ // Font - Dynamic based on locale
3155
+ fontFamily,
3156
+ fontSize: 13,
3157
+ fontSizeLG: 14,
3158
+ fontSizeHeading1: 24,
3159
+ fontSizeHeading2: 20,
3160
+ fontSizeHeading3: 16,
3161
+ fontSizeHeading4: 14,
3162
+ fontSizeHeading5: 13,
3163
+ // Spacing - Tight
3164
+ padding: 12,
3165
+ paddingLG: 16,
3166
+ paddingSM: 8,
3167
+ paddingXS: 4,
3168
+ margin: 12,
3169
+ marginLG: 16,
3170
+ marginSM: 8,
3171
+ marginXS: 4,
3172
+ // Shadows - Almost flat (Japanese style)
3173
+ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.03)",
3174
+ boxShadowSecondary: "0 1px 3px rgba(0, 0, 0, 0.04)",
3175
+ // Line Height
3176
+ lineHeight: 1.5
3177
+ },
3178
+ components: {
3179
+ // Global icon margin in Space component
3180
+ Space: {
3181
+ marginXS: 6
3182
+ },
3183
+ Button: {
3184
+ controlHeight: 32,
3185
+ paddingInline: 12,
3186
+ fontWeight: 500
3187
+ },
3188
+ Statistic: {
3189
+ contentFontSize: 24,
3190
+ titleFontSize: 13
3191
+ },
3192
+ Input: {
3193
+ controlHeight: 32,
3194
+ paddingInline: 8
3195
+ },
3196
+ Select: {
3197
+ controlHeight: 32
3198
+ },
3199
+ Table: {
3200
+ cellPaddingBlock: 8,
3201
+ cellPaddingInline: 8,
3202
+ headerBg: "#F8F7FA"
3203
+ },
3204
+ Card: {
3205
+ paddingLG: 16
3206
+ },
3207
+ Form: {
3208
+ itemMarginBottom: 16,
3209
+ verticalLabelPadding: "0 0 4px"
3210
+ },
3211
+ Menu: {
3212
+ itemHeight: 36,
3213
+ itemMarginBlock: 2,
3214
+ itemMarginInline: 4,
3215
+ darkItemBg: colors.menuDarkItemBg,
3216
+ darkSubMenuItemBg: colors.menuDarkSubMenuItemBg,
3217
+ darkItemSelectedBg: colors.menuDarkItemSelectedBg,
3218
+ darkItemSelectedColor: "#FFFFFF",
3219
+ darkItemColor: "rgba(255, 255, 255, 0.9)",
3220
+ darkItemHoverBg: colors.menuDarkItemHoverBg,
3221
+ darkItemHoverColor: "#FFFFFF"
3222
+ },
3223
+ Layout: {
3224
+ siderBg: colors.siderBg,
3225
+ headerPadding: "0 16px",
3226
+ headerHeight: 48
3227
+ },
3228
+ Typography: {
3229
+ titleMarginBottom: 8,
3230
+ titleMarginTop: 0
3231
+ },
3232
+ Modal: {
3233
+ paddingContentHorizontalLG: 16
3234
+ },
3235
+ Descriptions: {
3236
+ itemPaddingBottom: 8
3237
+ }
3238
+ }
3239
+ },
3240
+ children: /* @__PURE__ */ jsx18(App, { children })
3241
+ }
3242
+ );
3243
+ }
3244
+ export {
3245
+ AntdThemeProvider,
3246
+ BranchGate,
3247
+ LocaleSwitcher,
3248
+ OrgBranchSelectorModal,
3249
+ OrganizationSwitcher,
3250
+ DEFAULT_TEXTS as PROTABLE_DEFAULT_TEXTS,
3251
+ PageContainer,
3252
+ PermissionsListCard,
3253
+ ProTable,
3254
+ ProtectedRoute,
3255
+ RoleCreateModal,
3256
+ RolesListCard,
3257
+ ScopeLabel,
3258
+ ScopeTag,
3259
+ SsoCallback,
3260
+ TeamsListCard,
3261
+ UserDetailCard,
3262
+ UserPermissionsModal,
3263
+ UserRoleAssignModal,
3264
+ getScopeColor,
3265
+ getScopeIcon,
3266
+ useBranchGate
3267
+ };
3268
+ //# sourceMappingURL=index.js.map