@nsxbet/admin-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +680 -0
- package/dist/auth/client/in-memory.d.ts +27 -0
- package/dist/auth/client/in-memory.d.ts.map +1 -0
- package/dist/auth/client/in-memory.js +242 -0
- package/dist/auth/client/index.d.ts +7 -0
- package/dist/auth/client/index.d.ts.map +1 -0
- package/dist/auth/client/index.js +7 -0
- package/dist/auth/client/interface.d.ts +115 -0
- package/dist/auth/client/interface.d.ts.map +1 -0
- package/dist/auth/client/interface.js +7 -0
- package/dist/auth/client/keycloak.d.ts +19 -0
- package/dist/auth/client/keycloak.d.ts.map +1 -0
- package/dist/auth/client/keycloak.js +126 -0
- package/dist/auth/components/UserSelector.d.ts +19 -0
- package/dist/auth/components/UserSelector.d.ts.map +1 -0
- package/dist/auth/components/UserSelector.js +100 -0
- package/dist/auth/components/index.d.ts +5 -0
- package/dist/auth/components/index.d.ts.map +1 -0
- package/dist/auth/components/index.js +4 -0
- package/dist/auth/index.d.ts +7 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +7 -0
- package/dist/components/AuthProvider.d.ts +48 -0
- package/dist/components/AuthProvider.d.ts.map +1 -0
- package/dist/components/AuthProvider.js +117 -0
- package/dist/hooks/useAuth.d.ts +21 -0
- package/dist/hooks/useAuth.d.ts.map +1 -0
- package/dist/hooks/useAuth.js +34 -0
- package/dist/hooks/useFetch.d.ts +8 -0
- package/dist/hooks/useFetch.d.ts.map +1 -0
- package/dist/hooks/useFetch.js +31 -0
- package/dist/hooks/useI18n.d.ts +46 -0
- package/dist/hooks/useI18n.d.ts.map +1 -0
- package/dist/hooks/useI18n.js +95 -0
- package/dist/hooks/usePlatformAPI.d.ts +12 -0
- package/dist/hooks/usePlatformAPI.d.ts.map +1 -0
- package/dist/hooks/usePlatformAPI.js +10 -0
- package/dist/hooks/useTelemetry.d.ts +17 -0
- package/dist/hooks/useTelemetry.d.ts.map +1 -0
- package/dist/hooks/useTelemetry.js +36 -0
- package/dist/i18n/config.d.ts +26 -0
- package/dist/i18n/config.d.ts.map +1 -0
- package/dist/i18n/config.js +92 -0
- package/dist/i18n/index.d.ts +6 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +4 -0
- package/dist/i18n/locales/en-US.json +144 -0
- package/dist/i18n/locales/es.json +144 -0
- package/dist/i18n/locales/pt-BR.json +144 -0
- package/dist/i18n/locales/ro.json +144 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/registry/AdminShellRegistry.d.ts +140 -0
- package/dist/registry/AdminShellRegistry.d.ts.map +1 -0
- package/dist/registry/AdminShellRegistry.js +237 -0
- package/dist/registry/client/http.d.ts +21 -0
- package/dist/registry/client/http.d.ts.map +1 -0
- package/dist/registry/client/http.js +107 -0
- package/dist/registry/client/in-memory.d.ts +36 -0
- package/dist/registry/client/in-memory.d.ts.map +1 -0
- package/dist/registry/client/in-memory.js +242 -0
- package/dist/registry/client/index.d.ts +7 -0
- package/dist/registry/client/index.d.ts.map +1 -0
- package/dist/registry/client/index.js +5 -0
- package/dist/registry/client/interface.d.ts +96 -0
- package/dist/registry/client/interface.d.ts.map +1 -0
- package/dist/registry/client/interface.js +7 -0
- package/dist/registry/index.d.ts +12 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +8 -0
- package/dist/registry/types/index.d.ts +9 -0
- package/dist/registry/types/index.d.ts.map +1 -0
- package/dist/registry/types/index.js +6 -0
- package/dist/registry/types/manifest.d.ts +98 -0
- package/dist/registry/types/manifest.d.ts.map +1 -0
- package/dist/registry/types/manifest.js +81 -0
- package/dist/registry/types/module.d.ts +115 -0
- package/dist/registry/types/module.d.ts.map +1 -0
- package/dist/registry/types/module.js +6 -0
- package/dist/router/DynamicModule.d.ts +50 -0
- package/dist/router/DynamicModule.d.ts.map +1 -0
- package/dist/router/DynamicModule.js +141 -0
- package/dist/router/index.d.ts +2 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/router/index.js +1 -0
- package/dist/shell/AdminShell.d.ts +38 -0
- package/dist/shell/AdminShell.d.ts.map +1 -0
- package/dist/shell/AdminShell.js +299 -0
- package/dist/shell/BackofficeShell.d.ts +38 -0
- package/dist/shell/BackofficeShell.d.ts.map +1 -0
- package/dist/shell/BackofficeShell.js +299 -0
- package/dist/shell/components/CommandPalette.d.ts +8 -0
- package/dist/shell/components/CommandPalette.d.ts.map +1 -0
- package/dist/shell/components/CommandPalette.js +197 -0
- package/dist/shell/components/HomePage.d.ts +2 -0
- package/dist/shell/components/HomePage.d.ts.map +1 -0
- package/dist/shell/components/HomePage.js +32 -0
- package/dist/shell/components/LeftNav.d.ts +7 -0
- package/dist/shell/components/LeftNav.d.ts.map +1 -0
- package/dist/shell/components/LeftNav.js +247 -0
- package/dist/shell/components/MainContent.d.ts +9 -0
- package/dist/shell/components/MainContent.d.ts.map +1 -0
- package/dist/shell/components/MainContent.js +88 -0
- package/dist/shell/components/ModuleOverview.d.ts +7 -0
- package/dist/shell/components/ModuleOverview.d.ts.map +1 -0
- package/dist/shell/components/ModuleOverview.js +40 -0
- package/dist/shell/components/ProfilePage.d.ts +2 -0
- package/dist/shell/components/ProfilePage.d.ts.map +1 -0
- package/dist/shell/components/ProfilePage.js +30 -0
- package/dist/shell/components/RegistryPage.d.ts +8 -0
- package/dist/shell/components/RegistryPage.d.ts.map +1 -0
- package/dist/shell/components/RegistryPage.js +129 -0
- package/dist/shell/components/SettingsPage.d.ts +2 -0
- package/dist/shell/components/SettingsPage.d.ts.map +1 -0
- package/dist/shell/components/SettingsPage.js +60 -0
- package/dist/shell/components/TopBar.d.ts +8 -0
- package/dist/shell/components/TopBar.d.ts.map +1 -0
- package/dist/shell/components/TopBar.js +61 -0
- package/dist/shell/components/index.d.ts +10 -0
- package/dist/shell/components/index.d.ts.map +1 -0
- package/dist/shell/components/index.js +7 -0
- package/dist/shell/components/theme-provider.d.ts +15 -0
- package/dist/shell/components/theme-provider.d.ts.map +1 -0
- package/dist/shell/components/theme-provider.js +39 -0
- package/dist/shell/index.d.ts +9 -0
- package/dist/shell/index.d.ts.map +1 -0
- package/dist/shell/index.js +8 -0
- package/dist/shell/search/fuzzy.d.ts +18 -0
- package/dist/shell/search/fuzzy.d.ts.map +1 -0
- package/dist/shell/search/fuzzy.js +121 -0
- package/dist/shell/search/index.d.ts +3 -0
- package/dist/shell/search/index.d.ts.map +1 -0
- package/dist/shell/search/index.js +1 -0
- package/dist/shell/telemetry.d.ts +7 -0
- package/dist/shell/telemetry.d.ts.map +1 -0
- package/dist/shell/telemetry.js +25 -0
- package/dist/shell/types.d.ts +110 -0
- package/dist/shell/types.d.ts.map +1 -0
- package/dist/shell/types.js +4 -0
- package/dist/tailwind/index.d.ts +20 -0
- package/dist/tailwind/index.d.ts.map +1 -0
- package/dist/tailwind/index.js +42 -0
- package/dist/types/keycloak.d.ts +26 -0
- package/dist/types/keycloak.d.ts.map +1 -0
- package/dist/types/keycloak.js +1 -0
- package/dist/types/platform.d.ts +83 -0
- package/dist/types/platform.d.ts.map +1 -0
- package/dist/types/platform.js +5 -0
- package/dist/vite/config.d.ts +71 -0
- package/dist/vite/config.d.ts.map +1 -0
- package/dist/vite/config.js +87 -0
- package/dist/vite/index.d.ts +18 -0
- package/dist/vite/index.d.ts.map +1 -0
- package/dist/vite/index.js +17 -0
- package/dist/vite/plugins.d.ts +44 -0
- package/dist/vite/plugins.d.ts.map +1 -0
- package/dist/vite/plugins.js +74 -0
- package/package.json +86 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/auth/components/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication module exports
|
|
3
|
+
*/
|
|
4
|
+
export type { AuthClient, InMemoryAuthClient, MockUser, AuthState, AuthStateCallback, } from './client';
|
|
5
|
+
export { createInMemoryAuthClient, clearInMemoryAuth, createKeycloakAuthClient, type InMemoryAuthClientOptions, type KeycloakAuthClientOptions, } from './client';
|
|
6
|
+
export { UserSelector } from './components';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,YAAY,EACV,UAAU,EACV,kBAAkB,EAClB,QAAQ,EACR,SAAS,EACT,iBAAiB,GAClB,MAAM,UAAU,CAAC;AAGlB,OAAO,EACL,wBAAwB,EACxB,iBAAiB,EACjB,wBAAwB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,yBAAyB,GAC/B,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AuthProvider - Manages authentication state using AuthClient
|
|
3
|
+
*
|
|
4
|
+
* Works with both in-memory (mock) and Keycloak auth clients.
|
|
5
|
+
* Shows user selection screen when in-memory client has no selected user.
|
|
6
|
+
*/
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import type { AuthClient } from '../auth/client/interface';
|
|
9
|
+
import type { User } from '../types/platform';
|
|
10
|
+
/**
|
|
11
|
+
* Auth context value
|
|
12
|
+
*/
|
|
13
|
+
interface AuthContextValue {
|
|
14
|
+
/** Whether user is authenticated */
|
|
15
|
+
isAuthenticated: boolean;
|
|
16
|
+
/** Current user (null if not authenticated) */
|
|
17
|
+
user: User | null;
|
|
18
|
+
/** Get access token for API calls */
|
|
19
|
+
getAccessToken: () => Promise<string>;
|
|
20
|
+
/** Check if user has a permission */
|
|
21
|
+
hasPermission: (permission: string) => boolean;
|
|
22
|
+
/** Log out current user */
|
|
23
|
+
logout: () => void;
|
|
24
|
+
/** The underlying auth client */
|
|
25
|
+
authClient: AuthClient;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* AuthProvider props
|
|
29
|
+
*/
|
|
30
|
+
interface AuthProviderProps {
|
|
31
|
+
children: React.ReactNode;
|
|
32
|
+
/** The auth client to use */
|
|
33
|
+
authClient: AuthClient;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* AuthProvider manages authentication state and renders appropriate UI
|
|
37
|
+
*/
|
|
38
|
+
export declare function AuthProvider({ children, authClient }: AuthProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
39
|
+
/**
|
|
40
|
+
* Hook to access auth context
|
|
41
|
+
*/
|
|
42
|
+
export declare function useAuthContext(): AuthContextValue;
|
|
43
|
+
/**
|
|
44
|
+
* Check if component is within AuthProvider
|
|
45
|
+
*/
|
|
46
|
+
export declare function useOptionalAuthContext(): AuthContextValue | null;
|
|
47
|
+
export {};
|
|
48
|
+
//# sourceMappingURL=AuthProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthProvider.d.ts","sourceRoot":"","sources":["../../src/components/AuthProvider.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAsE,MAAM,OAAO,CAAC;AAC3F,OAAO,KAAK,EAAE,UAAU,EAAiC,MAAM,0BAA0B,CAAC;AAE1F,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAE9C;;GAEG;AACH,UAAU,gBAAgB;IACxB,oCAAoC;IACpC,eAAe,EAAE,OAAO,CAAC;IACzB,+CAA+C;IAC/C,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,qCAAqC;IACrC,cAAc,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACtC,qCAAqC;IACrC,aAAa,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;IAC/C,2BAA2B;IAC3B,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,iCAAiC;IACjC,UAAU,EAAE,UAAU,CAAC;CACxB;AAID;;GAEG;AACH,UAAU,iBAAiB;IACzB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,6BAA6B;IAC7B,UAAU,EAAE,UAAU,CAAC;CACxB;AAqBD;;GAEG;AACH,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,iBAAiB,2CAiGvE;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,gBAAgB,CAMjD;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,gBAAgB,GAAG,IAAI,CAEhE"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* AuthProvider - Manages authentication state using AuthClient
|
|
4
|
+
*
|
|
5
|
+
* Works with both in-memory (mock) and Keycloak auth clients.
|
|
6
|
+
* Shows user selection screen when in-memory client has no selected user.
|
|
7
|
+
*/
|
|
8
|
+
import { createContext, useContext, useEffect, useState, useCallback } from 'react';
|
|
9
|
+
import { UserSelector } from '../auth/components/UserSelector';
|
|
10
|
+
const AuthContext = createContext(null);
|
|
11
|
+
/**
|
|
12
|
+
* Loading screen component - uses Brasa Design System tokens
|
|
13
|
+
*/
|
|
14
|
+
function LoadingScreen() {
|
|
15
|
+
return (_jsx("div", { className: "min-h-screen bg-background flex items-center justify-center", children: _jsxs("div", { className: "text-center", children: [_jsx("div", { className: "inline-flex items-center justify-center w-12 h-12 rounded-xl bg-primary/20 mb-4 animate-pulse", children: _jsxs("svg", { className: "w-6 h-6 text-primary animate-spin", fill: "none", viewBox: "0 0 24 24", children: [_jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), _jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })] }) }), _jsx("p", { className: "text-muted-foreground", children: "Loading..." })] }) }));
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* AuthProvider manages authentication state and renders appropriate UI
|
|
19
|
+
*/
|
|
20
|
+
export function AuthProvider({ children, authClient }) {
|
|
21
|
+
const [authState, setAuthState] = useState({
|
|
22
|
+
isAuthenticated: false,
|
|
23
|
+
user: null,
|
|
24
|
+
});
|
|
25
|
+
const [isInitializing, setIsInitializing] = useState(true);
|
|
26
|
+
const [needsUserSelection, setNeedsUserSelection] = useState(false);
|
|
27
|
+
// Initialize auth client
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
let mounted = true;
|
|
30
|
+
const initialize = async () => {
|
|
31
|
+
try {
|
|
32
|
+
const isAuthenticated = await authClient.initialize();
|
|
33
|
+
if (!mounted)
|
|
34
|
+
return;
|
|
35
|
+
if (isAuthenticated) {
|
|
36
|
+
setAuthState({
|
|
37
|
+
isAuthenticated: true,
|
|
38
|
+
user: authClient.getUser(),
|
|
39
|
+
});
|
|
40
|
+
setNeedsUserSelection(false);
|
|
41
|
+
}
|
|
42
|
+
else if (authClient.type === 'in-memory') {
|
|
43
|
+
// In-memory client needs user selection
|
|
44
|
+
setNeedsUserSelection(true);
|
|
45
|
+
}
|
|
46
|
+
// Keycloak will redirect to login page, so we don't need to handle it here
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
console.error('[AuthProvider] Initialization failed:', error);
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
if (mounted) {
|
|
53
|
+
setIsInitializing(false);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
initialize();
|
|
58
|
+
// Subscribe to auth state changes
|
|
59
|
+
const unsubscribe = authClient.subscribe((state) => {
|
|
60
|
+
if (mounted) {
|
|
61
|
+
setAuthState(state);
|
|
62
|
+
if (!state.isAuthenticated && authClient.type === 'in-memory') {
|
|
63
|
+
setNeedsUserSelection(true);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
setNeedsUserSelection(false);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
return () => {
|
|
71
|
+
mounted = false;
|
|
72
|
+
unsubscribe();
|
|
73
|
+
};
|
|
74
|
+
}, [authClient]);
|
|
75
|
+
// Handle user selection
|
|
76
|
+
const handleUserSelected = useCallback(() => {
|
|
77
|
+
setAuthState({
|
|
78
|
+
isAuthenticated: authClient.isAuthenticated(),
|
|
79
|
+
user: authClient.getUser(),
|
|
80
|
+
});
|
|
81
|
+
setNeedsUserSelection(false);
|
|
82
|
+
}, [authClient]);
|
|
83
|
+
// Context value
|
|
84
|
+
const contextValue = {
|
|
85
|
+
isAuthenticated: authState.isAuthenticated,
|
|
86
|
+
user: authState.user,
|
|
87
|
+
getAccessToken: () => authClient.getAccessToken(),
|
|
88
|
+
hasPermission: (permission) => authClient.hasPermission(permission),
|
|
89
|
+
logout: () => authClient.logout(),
|
|
90
|
+
authClient,
|
|
91
|
+
};
|
|
92
|
+
// Show loading during initialization
|
|
93
|
+
if (isInitializing) {
|
|
94
|
+
return _jsx(LoadingScreen, {});
|
|
95
|
+
}
|
|
96
|
+
// Show user selector for in-memory auth when no user selected
|
|
97
|
+
if (needsUserSelection && authClient.type === 'in-memory') {
|
|
98
|
+
return (_jsx(UserSelector, { authClient: authClient, onUserSelected: handleUserSelected }));
|
|
99
|
+
}
|
|
100
|
+
return (_jsx(AuthContext.Provider, { value: contextValue, children: children }));
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Hook to access auth context
|
|
104
|
+
*/
|
|
105
|
+
export function useAuthContext() {
|
|
106
|
+
const context = useContext(AuthContext);
|
|
107
|
+
if (!context) {
|
|
108
|
+
throw new Error('useAuthContext must be used within AuthProvider');
|
|
109
|
+
}
|
|
110
|
+
return context;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Check if component is within AuthProvider
|
|
114
|
+
*/
|
|
115
|
+
export function useOptionalAuthContext() {
|
|
116
|
+
return useContext(AuthContext);
|
|
117
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { User } from '../types/platform';
|
|
2
|
+
/**
|
|
3
|
+
* Authentication methods available in all modes
|
|
4
|
+
*/
|
|
5
|
+
export interface UseAuthResult {
|
|
6
|
+
/** Get the current access token */
|
|
7
|
+
getAccessToken: () => Promise<string>;
|
|
8
|
+
/** Check if user has a specific permission */
|
|
9
|
+
hasPermission: (permission: string) => boolean;
|
|
10
|
+
/** Get current user information */
|
|
11
|
+
getUser: () => User;
|
|
12
|
+
/** Log out the current user */
|
|
13
|
+
logout: () => void;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* useAuth provides authentication methods that work seamlessly across:
|
|
17
|
+
* - Shell mode (using platform API)
|
|
18
|
+
* - Standalone mode with AuthClient (Keycloak or in-memory)
|
|
19
|
+
*/
|
|
20
|
+
export declare function useAuth(): UseAuthResult;
|
|
21
|
+
//# sourceMappingURL=useAuth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAuth.d.ts","sourceRoot":"","sources":["../../src/hooks/useAuth.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,mCAAmC;IACnC,cAAc,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAEtC,8CAA8C;IAC9C,aAAa,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;IAE/C,mCAAmC;IACnC,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,OAAO,IAAI,aAAa,CA4BvC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified authentication hook that works in shell, standalone, and mock modes
|
|
3
|
+
*/
|
|
4
|
+
import { usePlatformAPI } from './usePlatformAPI';
|
|
5
|
+
import { useOptionalAuthContext } from '../components/AuthProvider';
|
|
6
|
+
/**
|
|
7
|
+
* useAuth provides authentication methods that work seamlessly across:
|
|
8
|
+
* - Shell mode (using platform API)
|
|
9
|
+
* - Standalone mode with AuthClient (Keycloak or in-memory)
|
|
10
|
+
*/
|
|
11
|
+
export function useAuth() {
|
|
12
|
+
const { isShellMode, api } = usePlatformAPI();
|
|
13
|
+
const authContext = useOptionalAuthContext();
|
|
14
|
+
// In shell mode, use the platform API
|
|
15
|
+
if (isShellMode && api) {
|
|
16
|
+
return {
|
|
17
|
+
getAccessToken: api.auth.getAccessToken,
|
|
18
|
+
hasPermission: api.auth.hasPermission,
|
|
19
|
+
getUser: api.auth.getUser,
|
|
20
|
+
logout: api.auth.logout,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
// Use AuthProvider context (new AuthClient-based system)
|
|
24
|
+
if (authContext) {
|
|
25
|
+
return {
|
|
26
|
+
getAccessToken: authContext.getAccessToken,
|
|
27
|
+
hasPermission: authContext.hasPermission,
|
|
28
|
+
getUser: () => authContext.user || { id: '', email: '', displayName: '' },
|
|
29
|
+
logout: authContext.logout,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
throw new Error('useAuth must be used within AuthProvider. ' +
|
|
33
|
+
'Wrap your app with <AuthProvider authClient={...}> from @nsxbet/admin-sdk');
|
|
34
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useFetch provides an authenticated fetch function
|
|
3
|
+
*
|
|
4
|
+
* In shell mode: Uses platform API's fetch (automatically includes auth)
|
|
5
|
+
* In standalone mode: Manually adds Authorization header with token
|
|
6
|
+
*/
|
|
7
|
+
export declare function useFetch(): (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
8
|
+
//# sourceMappingURL=useFetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFetch.d.ts","sourceRoot":"","sources":["../../src/hooks/useFetch.ts"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,wBAAgB,QAAQ,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAqB9F"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authenticated fetch hook that works in both shell and standalone modes
|
|
3
|
+
*/
|
|
4
|
+
import { useCallback } from 'react';
|
|
5
|
+
import { usePlatformAPI } from './usePlatformAPI';
|
|
6
|
+
import { useAuth } from './useAuth';
|
|
7
|
+
/**
|
|
8
|
+
* useFetch provides an authenticated fetch function
|
|
9
|
+
*
|
|
10
|
+
* In shell mode: Uses platform API's fetch (automatically includes auth)
|
|
11
|
+
* In standalone mode: Manually adds Authorization header with token
|
|
12
|
+
*/
|
|
13
|
+
export function useFetch() {
|
|
14
|
+
const { isShellMode, api } = usePlatformAPI();
|
|
15
|
+
const { getAccessToken } = useAuth();
|
|
16
|
+
return useCallback(async (input, init) => {
|
|
17
|
+
if (isShellMode && api) {
|
|
18
|
+
// In shell mode, use platform fetch (handles auth automatically)
|
|
19
|
+
return api.fetch(input, init);
|
|
20
|
+
}
|
|
21
|
+
// In standalone mode, add auth header manually
|
|
22
|
+
const token = await getAccessToken();
|
|
23
|
+
return fetch(input, {
|
|
24
|
+
...init,
|
|
25
|
+
headers: {
|
|
26
|
+
...init?.headers,
|
|
27
|
+
Authorization: `Bearer ${token}`,
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
}, [isShellMode, api, getAccessToken]);
|
|
31
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { TFunction, i18n as I18nInstance } from 'i18next';
|
|
2
|
+
/**
|
|
3
|
+
* i18n methods and translation utilities
|
|
4
|
+
*/
|
|
5
|
+
export interface UseI18nResult {
|
|
6
|
+
/** Current locale */
|
|
7
|
+
locale: string;
|
|
8
|
+
/** Change the locale */
|
|
9
|
+
setLocale: (locale: string) => void;
|
|
10
|
+
/** Translation function - use t('key') or t('namespace:key') */
|
|
11
|
+
t: TFunction;
|
|
12
|
+
/** i18next instance for advanced use cases */
|
|
13
|
+
i18n: I18nInstance;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* useI18n provides internationalization methods and translation access
|
|
17
|
+
*
|
|
18
|
+
* In shell mode: Uses platform API's i18n and subscribes to changes
|
|
19
|
+
* In standalone mode: Manages locale in local state
|
|
20
|
+
*
|
|
21
|
+
* @param namespace - Optional namespace for translations (default: 'shell')
|
|
22
|
+
* @returns Object with locale, setLocale, t (translation function), and i18n instance
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* // Basic usage
|
|
27
|
+
* const { locale, setLocale, t } = useI18n();
|
|
28
|
+
*
|
|
29
|
+
* return (
|
|
30
|
+
* <div>
|
|
31
|
+
* <p>{t('common.loading')}</p>
|
|
32
|
+
* <button onClick={() => setLocale('en-US')}>English</button>
|
|
33
|
+
* </div>
|
|
34
|
+
* );
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```tsx
|
|
39
|
+
* // With custom namespace (for modules)
|
|
40
|
+
* const { t } = useI18n('@admin/tasks');
|
|
41
|
+
*
|
|
42
|
+
* return <h1>{t('listTitle')}</h1>;
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare function useI18n(namespace?: string): UseI18nResult;
|
|
46
|
+
//# sourceMappingURL=useI18n.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useI18n.d.ts","sourceRoot":"","sources":["../../src/hooks/useI18n.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,IAAI,YAAY,EAAE,MAAM,SAAS,CAAC;AAI/D;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,qBAAqB;IACrB,MAAM,EAAE,MAAM,CAAC;IAEf,wBAAwB;IACxB,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAEpC,gEAAgE;IAChE,CAAC,EAAE,SAAS,CAAC;IAEb,8CAA8C;IAC9C,IAAI,EAAE,YAAY,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,OAAO,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,aAAa,CAmEzD"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internationalization hook for locale management and translations
|
|
3
|
+
*/
|
|
4
|
+
import { useEffect, useState, useCallback } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
import { usePlatformAPI } from './usePlatformAPI';
|
|
7
|
+
import { saveLocale, isSupportedLocale, i18n } from '../i18n';
|
|
8
|
+
/**
|
|
9
|
+
* useI18n provides internationalization methods and translation access
|
|
10
|
+
*
|
|
11
|
+
* In shell mode: Uses platform API's i18n and subscribes to changes
|
|
12
|
+
* In standalone mode: Manages locale in local state
|
|
13
|
+
*
|
|
14
|
+
* @param namespace - Optional namespace for translations (default: 'shell')
|
|
15
|
+
* @returns Object with locale, setLocale, t (translation function), and i18n instance
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* // Basic usage
|
|
20
|
+
* const { locale, setLocale, t } = useI18n();
|
|
21
|
+
*
|
|
22
|
+
* return (
|
|
23
|
+
* <div>
|
|
24
|
+
* <p>{t('common.loading')}</p>
|
|
25
|
+
* <button onClick={() => setLocale('en-US')}>English</button>
|
|
26
|
+
* </div>
|
|
27
|
+
* );
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```tsx
|
|
32
|
+
* // With custom namespace (for modules)
|
|
33
|
+
* const { t } = useI18n('@admin/tasks');
|
|
34
|
+
*
|
|
35
|
+
* return <h1>{t('listTitle')}</h1>;
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export function useI18n(namespace) {
|
|
39
|
+
const { isShellMode, api } = usePlatformAPI();
|
|
40
|
+
const [standaloneLocale, setStandaloneLocale] = useState(i18n.language || 'pt-BR');
|
|
41
|
+
// Use react-i18next's useTranslation for reactive updates
|
|
42
|
+
const { t, i18n: i18nInstance } = useTranslation(namespace || 'shell');
|
|
43
|
+
// Subscribe to platform locale changes in shell mode
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (isShellMode && api) {
|
|
46
|
+
// Sync initial locale
|
|
47
|
+
const platformLocale = api.i18n.locale;
|
|
48
|
+
if (platformLocale !== i18nInstance.language) {
|
|
49
|
+
i18nInstance.changeLanguage(platformLocale);
|
|
50
|
+
}
|
|
51
|
+
setStandaloneLocale(platformLocale);
|
|
52
|
+
// Subscribe to changes
|
|
53
|
+
const unsubscribe = api.i18n.onLocaleChange((newLocale) => {
|
|
54
|
+
if (isSupportedLocale(newLocale)) {
|
|
55
|
+
i18nInstance.changeLanguage(newLocale);
|
|
56
|
+
setStandaloneLocale(newLocale);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
return unsubscribe;
|
|
60
|
+
}
|
|
61
|
+
}, [isShellMode, api, i18nInstance]);
|
|
62
|
+
// Sync standalone mode with i18n language changes
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
const handleLanguageChanged = (lng) => {
|
|
65
|
+
setStandaloneLocale(lng);
|
|
66
|
+
};
|
|
67
|
+
i18nInstance.on('languageChanged', handleLanguageChanged);
|
|
68
|
+
return () => {
|
|
69
|
+
i18nInstance.off('languageChanged', handleLanguageChanged);
|
|
70
|
+
};
|
|
71
|
+
}, [i18nInstance]);
|
|
72
|
+
const setLocale = useCallback((locale) => {
|
|
73
|
+
if (!isSupportedLocale(locale)) {
|
|
74
|
+
console.warn(`[useI18n] Unsupported locale: ${locale}`);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
// Always update i18next
|
|
78
|
+
i18nInstance.changeLanguage(locale);
|
|
79
|
+
// Persist to localStorage
|
|
80
|
+
saveLocale(locale);
|
|
81
|
+
if (isShellMode && api) {
|
|
82
|
+
// Notify platform API
|
|
83
|
+
api.i18n.setLocale(locale);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
setStandaloneLocale(locale);
|
|
87
|
+
}
|
|
88
|
+
}, [isShellMode, api, i18nInstance]);
|
|
89
|
+
return {
|
|
90
|
+
locale: isShellMode && api ? api.i18n.locale : standaloneLocale,
|
|
91
|
+
setLocale,
|
|
92
|
+
t,
|
|
93
|
+
i18n: i18nInstance,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook to access the platform API
|
|
3
|
+
*/
|
|
4
|
+
import type { PlatformAPI } from '../types/platform';
|
|
5
|
+
/**
|
|
6
|
+
* Returns the platform API and whether the module is running in shell mode
|
|
7
|
+
*/
|
|
8
|
+
export declare function usePlatformAPI(): {
|
|
9
|
+
isShellMode: boolean;
|
|
10
|
+
api: PlatformAPI | undefined;
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=usePlatformAPI.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePlatformAPI.d.ts","sourceRoot":"","sources":["../../src/hooks/usePlatformAPI.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;GAEG;AACH,wBAAgB,cAAc,IAAI;IAChC,WAAW,EAAE,OAAO,CAAC;IACrB,GAAG,EAAE,WAAW,GAAG,SAAS,CAAC;CAC9B,CAOA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the platform API and whether the module is running in shell mode
|
|
3
|
+
*/
|
|
4
|
+
export function usePlatformAPI() {
|
|
5
|
+
const isShellMode = typeof window !== 'undefined' && window.__ADMIN_PLATFORM_API__ !== undefined;
|
|
6
|
+
return {
|
|
7
|
+
isShellMode,
|
|
8
|
+
api: isShellMode ? window.__ADMIN_PLATFORM_API__ : undefined,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telemetry methods
|
|
3
|
+
*/
|
|
4
|
+
export interface UseTelemetryResult {
|
|
5
|
+
/** Track an event */
|
|
6
|
+
track: (event: string, props?: Record<string, unknown>) => void;
|
|
7
|
+
/** Track an error */
|
|
8
|
+
trackError: (err: unknown, props?: Record<string, unknown>) => void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* useTelemetry provides telemetry methods
|
|
12
|
+
*
|
|
13
|
+
* In shell mode: Uses platform API's telemetry
|
|
14
|
+
* In standalone mode: Logs to console (or could send to local analytics)
|
|
15
|
+
*/
|
|
16
|
+
export declare function useTelemetry(): UseTelemetryResult;
|
|
17
|
+
//# sourceMappingURL=useTelemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTelemetry.d.ts","sourceRoot":"","sources":["../../src/hooks/useTelemetry.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,qBAAqB;IACrB,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAEhE,qBAAqB;IACrB,UAAU,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CACrE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,kBAAkB,CAyBjD"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telemetry hook for tracking events and errors
|
|
3
|
+
*/
|
|
4
|
+
import { useCallback } from 'react';
|
|
5
|
+
import { usePlatformAPI } from './usePlatformAPI';
|
|
6
|
+
/**
|
|
7
|
+
* useTelemetry provides telemetry methods
|
|
8
|
+
*
|
|
9
|
+
* In shell mode: Uses platform API's telemetry
|
|
10
|
+
* In standalone mode: Logs to console (or could send to local analytics)
|
|
11
|
+
*/
|
|
12
|
+
export function useTelemetry() {
|
|
13
|
+
const { isShellMode, api } = usePlatformAPI();
|
|
14
|
+
const track = useCallback((event, props) => {
|
|
15
|
+
if (isShellMode && api) {
|
|
16
|
+
api.telemetry.track(event, props);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
// In standalone mode, log to console
|
|
20
|
+
console.log('[Telemetry]', event, props);
|
|
21
|
+
}
|
|
22
|
+
}, [isShellMode, api]);
|
|
23
|
+
const trackError = useCallback((err, props) => {
|
|
24
|
+
if (isShellMode && api) {
|
|
25
|
+
api.telemetry.trackError(err, props);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
// In standalone mode, log to console
|
|
29
|
+
console.error('[Telemetry Error]', err, props);
|
|
30
|
+
}
|
|
31
|
+
}, [isShellMode, api]);
|
|
32
|
+
return {
|
|
33
|
+
track,
|
|
34
|
+
trackError,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* i18n Configuration for the Admin Platform
|
|
3
|
+
*
|
|
4
|
+
* Supports: Portuguese (Brazil), Spanish, English (US), Romanian
|
|
5
|
+
*/
|
|
6
|
+
import i18n from 'i18next';
|
|
7
|
+
export declare const SUPPORTED_LOCALES: readonly ["pt-BR", "es", "en-US", "ro"];
|
|
8
|
+
export type SupportedLocale = typeof SUPPORTED_LOCALES[number];
|
|
9
|
+
export declare const LOCALE_FLAGS: Record<SupportedLocale, string>;
|
|
10
|
+
export declare const LOCALE_NAMES: Record<SupportedLocale, string>;
|
|
11
|
+
/**
|
|
12
|
+
* Save locale to localStorage
|
|
13
|
+
*/
|
|
14
|
+
export declare function saveLocale(locale: SupportedLocale): void;
|
|
15
|
+
/**
|
|
16
|
+
* Initialize i18next with the shell namespace
|
|
17
|
+
* Call this once in AdminShell before rendering
|
|
18
|
+
*/
|
|
19
|
+
export declare function initI18n(): typeof i18n;
|
|
20
|
+
/**
|
|
21
|
+
* Check if a locale is supported
|
|
22
|
+
*/
|
|
23
|
+
export declare function isSupportedLocale(locale: string): locale is SupportedLocale;
|
|
24
|
+
export { i18n };
|
|
25
|
+
export default i18n;
|
|
26
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/i18n/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,IAAI,MAAM,SAAS,CAAC;AAQ3B,eAAO,MAAM,iBAAiB,yCAA0C,CAAC;AACzE,MAAM,MAAM,eAAe,GAAG,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAE/D,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAKxD,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAKxD,CAAC;AAiBF;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAIxD;AAED;;;GAGG;AACH,wBAAgB,QAAQ,IAAI,OAAO,IAAI,CAoCtC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,IAAI,eAAe,CAE3E;AAED,OAAO,EAAE,IAAI,EAAE,CAAC;AAChB,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* i18n Configuration for the Admin Platform
|
|
3
|
+
*
|
|
4
|
+
* Supports: Portuguese (Brazil), Spanish, English (US), Romanian
|
|
5
|
+
*/
|
|
6
|
+
import i18n from 'i18next';
|
|
7
|
+
import { initReactI18next } from 'react-i18next';
|
|
8
|
+
import ptBR from './locales/pt-BR.json';
|
|
9
|
+
import es from './locales/es.json';
|
|
10
|
+
import enUS from './locales/en-US.json';
|
|
11
|
+
import ro from './locales/ro.json';
|
|
12
|
+
export const SUPPORTED_LOCALES = ['pt-BR', 'es', 'en-US', 'ro'];
|
|
13
|
+
export const LOCALE_FLAGS = {
|
|
14
|
+
'pt-BR': '🇧🇷',
|
|
15
|
+
'es': '🇪🇸',
|
|
16
|
+
'en-US': '🇺🇸',
|
|
17
|
+
'ro': '🇷🇴',
|
|
18
|
+
};
|
|
19
|
+
export const LOCALE_NAMES = {
|
|
20
|
+
'pt-BR': 'Português (Brasil)',
|
|
21
|
+
'es': 'Español',
|
|
22
|
+
'en-US': 'English',
|
|
23
|
+
'ro': 'Română',
|
|
24
|
+
};
|
|
25
|
+
const STORAGE_KEY = 'adminPlatform.locale';
|
|
26
|
+
/**
|
|
27
|
+
* Get the saved locale from localStorage, or return default
|
|
28
|
+
*/
|
|
29
|
+
function getSavedLocale() {
|
|
30
|
+
if (typeof window === 'undefined')
|
|
31
|
+
return 'pt-BR';
|
|
32
|
+
const saved = localStorage.getItem(STORAGE_KEY);
|
|
33
|
+
if (saved && SUPPORTED_LOCALES.includes(saved)) {
|
|
34
|
+
return saved;
|
|
35
|
+
}
|
|
36
|
+
return 'pt-BR';
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Save locale to localStorage
|
|
40
|
+
*/
|
|
41
|
+
export function saveLocale(locale) {
|
|
42
|
+
if (typeof window !== 'undefined') {
|
|
43
|
+
localStorage.setItem(STORAGE_KEY, locale);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Initialize i18next with the shell namespace
|
|
48
|
+
* Call this once in AdminShell before rendering
|
|
49
|
+
*/
|
|
50
|
+
export function initI18n() {
|
|
51
|
+
if (i18n.isInitialized) {
|
|
52
|
+
return i18n;
|
|
53
|
+
}
|
|
54
|
+
i18n
|
|
55
|
+
.use(initReactI18next)
|
|
56
|
+
.init({
|
|
57
|
+
resources: {
|
|
58
|
+
'pt-BR': { shell: ptBR },
|
|
59
|
+
'es': { shell: es },
|
|
60
|
+
'en-US': { shell: enUS },
|
|
61
|
+
'ro': { shell: ro },
|
|
62
|
+
},
|
|
63
|
+
lng: getSavedLocale(),
|
|
64
|
+
fallbackLng: 'en-US',
|
|
65
|
+
defaultNS: 'shell',
|
|
66
|
+
ns: ['shell'],
|
|
67
|
+
interpolation: {
|
|
68
|
+
escapeValue: false, // React already escapes
|
|
69
|
+
},
|
|
70
|
+
react: {
|
|
71
|
+
useSuspense: false, // Avoid suspense issues with microfrontends
|
|
72
|
+
},
|
|
73
|
+
// Debug mode in development
|
|
74
|
+
debug: import.meta.env?.DEV ?? false,
|
|
75
|
+
// Missing key handler
|
|
76
|
+
saveMissing: false,
|
|
77
|
+
missingKeyHandler: (lngs, ns, key) => {
|
|
78
|
+
if (import.meta.env?.DEV) {
|
|
79
|
+
console.warn(`[i18n] Missing translation: ${ns}:${key} for ${lngs.join(', ')}`);
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
return i18n;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Check if a locale is supported
|
|
87
|
+
*/
|
|
88
|
+
export function isSupportedLocale(locale) {
|
|
89
|
+
return SUPPORTED_LOCALES.includes(locale);
|
|
90
|
+
}
|
|
91
|
+
export { i18n };
|
|
92
|
+
export default i18n;
|