@vritti/quantum-ui 0.1.10 → 0.1.11
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/dist/AuthProvider.d.ts +25 -2
- package/dist/OnboardingProvider.js +91 -0
- package/dist/OnboardingProvider.js.map +1 -0
- package/dist/assets/quantum-ui.css +118 -1
- package/dist/context/AuthProvider.d.ts +2 -7
- package/dist/context/AuthProvider.js +1 -1
- package/dist/index.d.ts +27 -19
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/dist/AuthProvider.js +0 -137
- package/dist/AuthProvider.js.map +0 -1
package/dist/AuthProvider.d.ts
CHANGED
|
@@ -1,9 +1,32 @@
|
|
|
1
|
+
import { Context } from 'react';
|
|
1
2
|
import { default as default_2 } from 'react';
|
|
2
3
|
|
|
3
|
-
export declare const
|
|
4
|
+
export declare const OnboardingContext: Context<OnboardingContextType | undefined>;
|
|
4
5
|
|
|
5
|
-
declare interface
|
|
6
|
+
export declare interface OnboardingContextType extends OnboardingData {
|
|
7
|
+
onboardingToken: string | null;
|
|
8
|
+
isLoading: boolean;
|
|
9
|
+
error: string | null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export declare interface OnboardingData {
|
|
13
|
+
userId: string;
|
|
14
|
+
email: string;
|
|
15
|
+
firstName: string;
|
|
16
|
+
lastName: string;
|
|
17
|
+
currentStep: string;
|
|
18
|
+
onboardingComplete: boolean;
|
|
19
|
+
accountStatus: string;
|
|
20
|
+
emailVerified: boolean;
|
|
21
|
+
phoneVerified: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export declare const OnboardingProvider: default_2.FC<OnboardingProviderProps>;
|
|
25
|
+
|
|
26
|
+
declare interface OnboardingProviderProps {
|
|
6
27
|
children: default_2.ReactNode;
|
|
7
28
|
}
|
|
8
29
|
|
|
30
|
+
export declare const useOnboarding: () => OnboardingContextType;
|
|
31
|
+
|
|
9
32
|
export { }
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { createContext, useContext, useState, useRef, useCallback, useEffect } from 'react';
|
|
3
|
+
import { useNavigate } from 'react-router-dom';
|
|
4
|
+
import { axios } from './utils/axios.js';
|
|
5
|
+
|
|
6
|
+
const OnboardingContext = createContext(void 0);
|
|
7
|
+
const useOnboarding = () => {
|
|
8
|
+
const context = useContext(OnboardingContext);
|
|
9
|
+
if (!context) {
|
|
10
|
+
throw new Error("useOnboarding must be used within an OnboardingProvider");
|
|
11
|
+
}
|
|
12
|
+
return context;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const OnboardingProvider = ({ children }) => {
|
|
16
|
+
const [data, setData] = useState(null);
|
|
17
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
18
|
+
const navigate = useNavigate();
|
|
19
|
+
const isFetchingRef = useRef(false);
|
|
20
|
+
const fetchOnboardingStatus = useCallback(async () => {
|
|
21
|
+
if (isFetchingRef.current) return;
|
|
22
|
+
isFetchingRef.current = true;
|
|
23
|
+
try {
|
|
24
|
+
const response = await axios.get("/onboarding/status");
|
|
25
|
+
setData({
|
|
26
|
+
...response.data,
|
|
27
|
+
isLoading: false,
|
|
28
|
+
error: null
|
|
29
|
+
});
|
|
30
|
+
} catch (err) {
|
|
31
|
+
const axiosError = err;
|
|
32
|
+
if (axiosError.response?.status === 401) {
|
|
33
|
+
navigate("/login", { replace: true });
|
|
34
|
+
} else {
|
|
35
|
+
setData({
|
|
36
|
+
onboardingToken: null,
|
|
37
|
+
userId: "",
|
|
38
|
+
email: "",
|
|
39
|
+
firstName: "",
|
|
40
|
+
lastName: "",
|
|
41
|
+
currentStep: "",
|
|
42
|
+
onboardingComplete: false,
|
|
43
|
+
accountStatus: "",
|
|
44
|
+
emailVerified: false,
|
|
45
|
+
phoneVerified: false,
|
|
46
|
+
isLoading: false,
|
|
47
|
+
error: axiosError?.message || "Failed to fetch onboarding status"
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
} finally {
|
|
51
|
+
isFetchingRef.current = false;
|
|
52
|
+
setIsLoading(false);
|
|
53
|
+
}
|
|
54
|
+
}, [navigate]);
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
fetchOnboardingStatus();
|
|
57
|
+
}, []);
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (!data?.onboardingToken) return;
|
|
60
|
+
const requestInterceptor = axios.interceptors.request.use((config) => {
|
|
61
|
+
config.headers.Authorization = `Bearer ${data.onboardingToken}`;
|
|
62
|
+
return config;
|
|
63
|
+
});
|
|
64
|
+
return () => {
|
|
65
|
+
axios.interceptors.request.eject(requestInterceptor);
|
|
66
|
+
};
|
|
67
|
+
}, [data?.onboardingToken]);
|
|
68
|
+
if (isLoading) {
|
|
69
|
+
return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center min-h-screen", children: /* @__PURE__ */ jsxs("div", { className: "text-center space-y-4", children: [
|
|
70
|
+
/* @__PURE__ */ jsx("div", { className: "animate-spin rounded-full h-12 w-12 border-b-2 border-primary mx-auto" }),
|
|
71
|
+
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "Loading..." })
|
|
72
|
+
] }) });
|
|
73
|
+
}
|
|
74
|
+
return /* @__PURE__ */ jsx(OnboardingContext.Provider, { value: data || {
|
|
75
|
+
onboardingToken: null,
|
|
76
|
+
userId: "",
|
|
77
|
+
email: "",
|
|
78
|
+
firstName: "",
|
|
79
|
+
lastName: "",
|
|
80
|
+
currentStep: "",
|
|
81
|
+
onboardingComplete: false,
|
|
82
|
+
accountStatus: "",
|
|
83
|
+
emailVerified: false,
|
|
84
|
+
phoneVerified: false,
|
|
85
|
+
isLoading: false,
|
|
86
|
+
error: null
|
|
87
|
+
}, children });
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export { OnboardingContext as O, OnboardingProvider as a, useOnboarding as u };
|
|
91
|
+
//# sourceMappingURL=OnboardingProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OnboardingProvider.js","sources":["../lib/context/OnboardingContext.tsx","../lib/context/OnboardingProvider.tsx"],"sourcesContent":["import { createContext, useContext } from 'react';\n\nexport interface OnboardingData {\n userId: string;\n email: string;\n firstName: string;\n lastName: string;\n currentStep: string;\n onboardingComplete: boolean;\n accountStatus: string;\n emailVerified: boolean;\n phoneVerified: boolean;\n}\n\nexport interface OnboardingContextType extends OnboardingData {\n onboardingToken: string | null;\n isLoading: boolean;\n error: string | null;\n}\n\nexport const OnboardingContext = createContext<OnboardingContextType | undefined>(undefined);\n\nexport const useOnboarding = (): OnboardingContextType => {\n const context = useContext(OnboardingContext);\n if (!context) {\n throw new Error('useOnboarding must be used within an OnboardingProvider');\n }\n return context;\n};\n","import React, { useEffect, useState, useRef, useCallback } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { OnboardingContext, type OnboardingContextType, type OnboardingData } from './OnboardingContext';\nimport { axios } from '../utils/axios';\nimport type { AxiosError } from 'axios';\n\ninterface OnboardingProviderProps {\n children: React.ReactNode;\n}\n\ninterface OnboardingStatusResponse extends OnboardingData {\n onboardingToken: string;\n}\n\nexport const OnboardingProvider: React.FC<OnboardingProviderProps> = ({ children }) => {\n const [data, setData] = useState<OnboardingContextType | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const navigate = useNavigate();\n const isFetchingRef = useRef(false);\n\n const fetchOnboardingStatus = useCallback(async () => {\n // Prevent multiple simultaneous calls\n if (isFetchingRef.current) return;\n\n isFetchingRef.current = true;\n try {\n const response = await axios.get<OnboardingStatusResponse>('/onboarding/status');\n setData({\n ...response.data,\n isLoading: false,\n error: null,\n });\n } catch (err) {\n const axiosError = err as AxiosError;\n if (axiosError.response?.status === 401) {\n navigate('/login', { replace: true });\n } else {\n // Set error state for other failures (connection errors, etc)\n setData({\n onboardingToken: null,\n userId: '',\n email: '',\n firstName: '',\n lastName: '',\n currentStep: '',\n onboardingComplete: false,\n accountStatus: '',\n emailVerified: false,\n phoneVerified: false,\n isLoading: false,\n error: axiosError?.message || 'Failed to fetch onboarding status',\n });\n }\n } finally {\n isFetchingRef.current = false;\n setIsLoading(false);\n }\n }, [navigate]);\n\n // Only call once on mount with empty dependency array\n useEffect(() => {\n fetchOnboardingStatus();\n }, []);\n\n useEffect(() => {\n if (!data?.onboardingToken) return;\n\n // Request interceptor - Add authorization header\n const requestInterceptor = axios.interceptors.request.use((config) => {\n config.headers.Authorization = `Bearer ${data.onboardingToken}`;\n return config;\n });\n\n return () => {\n axios.interceptors.request.eject(requestInterceptor);\n };\n }, [data?.onboardingToken]);\n\n if (isLoading) {\n return (\n <div className='flex items-center justify-center min-h-screen'>\n <div className='text-center space-y-4'>\n <div className='animate-spin rounded-full h-12 w-12 border-b-2 border-primary mx-auto'></div>\n <p className='text-muted-foreground'>Loading...</p>\n </div>\n </div>\n );\n }\n\n return (\n <OnboardingContext.Provider value={data || {\n onboardingToken: null,\n userId: '',\n email: '',\n firstName: '',\n lastName: '',\n currentStep: '',\n onboardingComplete: false,\n accountStatus: '',\n emailVerified: false,\n phoneVerified: false,\n isLoading: false,\n error: null,\n }}>\n {children}\n </OnboardingContext.Provider>\n );\n};\n"],"names":[],"mappings":";;;;;AAoBO,MAAM,iBAAA,GAAoB,cAAiD,MAAS;AAEpF,MAAM,gBAAgB,MAA6B;AACxD,EAAA,MAAM,OAAA,GAAU,WAAW,iBAAiB,CAAA;AAC5C,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,IAAI,MAAM,yDAAyD,CAAA;AAAA,EAC3E;AACA,EAAA,OAAO,OAAA;AACT;;ACdO,MAAM,kBAAA,GAAwD,CAAC,EAAE,QAAA,EAAS,KAAM;AACrF,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAuC,IAAI,CAAA;AACnE,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,SAAS,IAAI,CAAA;AAC/C,EAAA,MAAM,WAAW,WAAA,EAAY;AAC7B,EAAA,MAAM,aAAA,GAAgB,OAAO,KAAK,CAAA;AAElC,EAAA,MAAM,qBAAA,GAAwB,YAAY,YAAY;AAEpD,IAAA,IAAI,cAAc,OAAA,EAAS;AAE3B,IAAA,aAAA,CAAc,OAAA,GAAU,IAAA;AACxB,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,CAA8B,oBAAoB,CAAA;AAC/E,MAAA,OAAA,CAAQ;AAAA,QACN,GAAG,QAAA,CAAS,IAAA;AAAA,QACZ,SAAA,EAAW,KAAA;AAAA,QACX,KAAA,EAAO;AAAA,OACR,CAAA;AAAA,IACH,SAAS,GAAA,EAAK;AACZ,MAAA,MAAM,UAAA,GAAa,GAAA;AACnB,MAAA,IAAI,UAAA,CAAW,QAAA,EAAU,MAAA,KAAW,GAAA,EAAK;AACvC,QAAA,QAAA,CAAS,QAAA,EAAU,EAAE,OAAA,EAAS,IAAA,EAAM,CAAA;AAAA,MACtC,CAAA,MAAO;AAEL,QAAA,OAAA,CAAQ;AAAA,UACN,eAAA,EAAiB,IAAA;AAAA,UACjB,MAAA,EAAQ,EAAA;AAAA,UACR,KAAA,EAAO,EAAA;AAAA,UACP,SAAA,EAAW,EAAA;AAAA,UACX,QAAA,EAAU,EAAA;AAAA,UACV,WAAA,EAAa,EAAA;AAAA,UACb,kBAAA,EAAoB,KAAA;AAAA,UACpB,aAAA,EAAe,EAAA;AAAA,UACf,aAAA,EAAe,KAAA;AAAA,UACf,aAAA,EAAe,KAAA;AAAA,UACf,SAAA,EAAW,KAAA;AAAA,UACX,KAAA,EAAO,YAAY,OAAA,IAAW;AAAA,SAC/B,CAAA;AAAA,MACH;AAAA,IACF,CAAA,SAAE;AACA,MAAA,aAAA,CAAc,OAAA,GAAU,KAAA;AACxB,MAAA,YAAA,CAAa,KAAK,CAAA;AAAA,IACpB;AAAA,EACF,CAAA,EAAG,CAAC,QAAQ,CAAC,CAAA;AAGb,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,qBAAA,EAAsB;AAAA,EACxB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,MAAM,eAAA,EAAiB;AAG5B,IAAA,MAAM,qBAAqB,KAAA,CAAM,YAAA,CAAa,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAA,KAAW;AACpE,MAAA,MAAA,CAAO,OAAA,CAAQ,aAAA,GAAgB,CAAA,OAAA,EAAU,IAAA,CAAK,eAAe,CAAA,CAAA;AAC7D,MAAA,OAAO,MAAA;AAAA,IACT,CAAC,CAAA;AAED,IAAA,OAAO,MAAM;AACX,MAAA,KAAA,CAAM,YAAA,CAAa,OAAA,CAAQ,KAAA,CAAM,kBAAkB,CAAA;AAAA,IACrD,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,IAAA,EAAM,eAAe,CAAC,CAAA;AAE1B,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,2BACG,KAAA,EAAA,EAAI,SAAA,EAAU,iDACb,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,uBAAA,EACb,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,WAAU,uEAAA,EAAwE,CAAA;AAAA,sBACvF,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,uBAAA,EAAwB,QAAA,EAAA,YAAA,EAAU;AAAA,KAAA,EACjD,CAAA,EACF,CAAA;AAAA,EAEJ;AAEA,EAAA,uBACE,GAAA,CAAC,iBAAA,CAAkB,QAAA,EAAlB,EAA2B,OAAO,IAAA,IAAQ;AAAA,IACzC,eAAA,EAAiB,IAAA;AAAA,IACjB,MAAA,EAAQ,EAAA;AAAA,IACR,KAAA,EAAO,EAAA;AAAA,IACP,SAAA,EAAW,EAAA;AAAA,IACX,QAAA,EAAU,EAAA;AAAA,IACV,WAAA,EAAa,EAAA;AAAA,IACb,kBAAA,EAAoB,KAAA;AAAA,IACpB,aAAA,EAAe,EAAA;AAAA,IACf,aAAA,EAAe,KAAA;AAAA,IACf,aAAA,EAAe,KAAA;AAAA,IACf,SAAA,EAAW,KAAA;AAAA,IACX,KAAA,EAAO;AAAA,KAEN,QAAA,EACH,CAAA;AAEJ;;;;"}
|
|
@@ -130,4 +130,121 @@
|
|
|
130
130
|
.PhoneInputCountrySelect:focus + .PhoneInputCountryIcon .PhoneInputInternationalIconGlobe {
|
|
131
131
|
opacity: 1;
|
|
132
132
|
color: var(--PhoneInputCountrySelectArrow-color--focus);
|
|
133
|
-
}
|
|
133
|
+
}/**
|
|
134
|
+
* Quantum UI Shared Styles
|
|
135
|
+
*
|
|
136
|
+
* This file contains ONLY:
|
|
137
|
+
* 1. Color theme variables (:root and .dark) - shared across all apps
|
|
138
|
+
* 2. PhoneInput component overrides - for h-9 container sizing
|
|
139
|
+
*
|
|
140
|
+
* Apps should import this file to get consistent colors and PhoneInput styling,
|
|
141
|
+
* then define their own complete Tailwind configuration.
|
|
142
|
+
*/
|
|
143
|
+
|
|
144
|
+
:root {
|
|
145
|
+
--background: oklch(1 0 0);
|
|
146
|
+
--foreground: oklch(0.3211 0 0);
|
|
147
|
+
--card: oklch(1 0 0);
|
|
148
|
+
--card-foreground: oklch(0.3211 0 0);
|
|
149
|
+
--popover: oklch(1 0 0);
|
|
150
|
+
--popover-foreground: oklch(0.3211 0 0);
|
|
151
|
+
--primary: oklch(0.522 0.1771 255.8297);
|
|
152
|
+
--primary-foreground: oklch(1 0 0);
|
|
153
|
+
--secondary: oklch(0.967 0.0029 264.5419);
|
|
154
|
+
--secondary-foreground: oklch(0.4461 0.0263 256.8018);
|
|
155
|
+
--muted: oklch(0.9846 0.0017 247.8389);
|
|
156
|
+
--muted-foreground: oklch(0.551 0.0234 264.3637);
|
|
157
|
+
--accent: oklch(0.9514 0.025 236.8242);
|
|
158
|
+
--accent-foreground: oklch(0.3791 0.1378 265.5222);
|
|
159
|
+
--destructive: oklch(0.6368 0.2078 25.3313);
|
|
160
|
+
--destructive-foreground: oklch(1 0 0);
|
|
161
|
+
--border: oklch(0.9276 0.0058 264.5313);
|
|
162
|
+
--input: oklch(0.9276 0.0058 264.5313);
|
|
163
|
+
--ring: oklch(0.6231 0.188 259.8145);
|
|
164
|
+
--chart-1: oklch(0.6231 0.188 259.8145);
|
|
165
|
+
--chart-2: oklch(0.5461 0.2152 262.8809);
|
|
166
|
+
--chart-3: oklch(0.4882 0.2172 264.3763);
|
|
167
|
+
--chart-4: oklch(0.4244 0.1809 265.6377);
|
|
168
|
+
--chart-5: oklch(0.3791 0.1378 265.5222);
|
|
169
|
+
--sidebar: oklch(0.9846 0.0017 247.8389);
|
|
170
|
+
--sidebar-foreground: oklch(0.3211 0 0);
|
|
171
|
+
--sidebar-primary: oklch(0.6231 0.188 259.8145);
|
|
172
|
+
--sidebar-primary-foreground: oklch(1 0 0);
|
|
173
|
+
--sidebar-accent: oklch(0.9514 0.025 236.8242);
|
|
174
|
+
--sidebar-accent-foreground: oklch(0.3791 0.1378 265.5222);
|
|
175
|
+
--sidebar-border: oklch(0.9276 0.0058 264.5313);
|
|
176
|
+
--sidebar-ring: oklch(0.6231 0.188 259.8145);
|
|
177
|
+
--font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
|
|
178
|
+
'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
|
179
|
+
--font-serif: ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif;
|
|
180
|
+
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
|
181
|
+
--radius: 0.625rem;
|
|
182
|
+
--shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
|
|
183
|
+
--shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
|
|
184
|
+
--shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1);
|
|
185
|
+
--shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1);
|
|
186
|
+
--shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 2px 4px -1px hsl(0 0% 0% / 0.1);
|
|
187
|
+
--shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 4px 6px -1px hsl(0 0% 0% / 0.1);
|
|
188
|
+
--shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 8px 10px -1px hsl(0 0% 0% / 0.1);
|
|
189
|
+
--shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25);
|
|
190
|
+
--tracking-normal: 0em;
|
|
191
|
+
--spacing: 0.25rem;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.dark {
|
|
195
|
+
--background: oklch(0.2046 0 0);
|
|
196
|
+
--foreground: oklch(0.9219 0 0);
|
|
197
|
+
--card: oklch(0.2686 0 0);
|
|
198
|
+
--card-foreground: oklch(0.9219 0 0);
|
|
199
|
+
--popover: oklch(0.2686 0 0);
|
|
200
|
+
--popover-foreground: oklch(0.9219 0 0);
|
|
201
|
+
--primary: oklch(0.522 0.1771 255.8297);
|
|
202
|
+
--primary-foreground: oklch(1 0 0);
|
|
203
|
+
--secondary: oklch(0.2686 0 0);
|
|
204
|
+
--secondary-foreground: oklch(0.9219 0 0);
|
|
205
|
+
--muted: oklch(0.2686 0 0);
|
|
206
|
+
--muted-foreground: oklch(0.7155 0 0);
|
|
207
|
+
--accent: oklch(0.3791 0.1378 265.5222);
|
|
208
|
+
--accent-foreground: oklch(0.8823 0.0571 254.1284);
|
|
209
|
+
--destructive: oklch(0.6368 0.2078 25.3313);
|
|
210
|
+
--destructive-foreground: oklch(1 0 0);
|
|
211
|
+
--border: oklch(0.3715 0 0);
|
|
212
|
+
--input: oklch(0.3715 0 0);
|
|
213
|
+
--ring: oklch(0.6231 0.188 259.8145);
|
|
214
|
+
--chart-1: oklch(0.7137 0.1434 254.624);
|
|
215
|
+
--chart-2: oklch(0.6231 0.188 259.8145);
|
|
216
|
+
--chart-3: oklch(0.5461 0.2152 262.8809);
|
|
217
|
+
--chart-4: oklch(0.4882 0.2172 264.3763);
|
|
218
|
+
--chart-5: oklch(0.4244 0.1809 265.6377);
|
|
219
|
+
--sidebar: oklch(0.2046 0 0);
|
|
220
|
+
--sidebar-foreground: oklch(0.9219 0 0);
|
|
221
|
+
--sidebar-primary: oklch(0.6231 0.188 259.8145);
|
|
222
|
+
--sidebar-primary-foreground: oklch(1 0 0);
|
|
223
|
+
--sidebar-accent: oklch(0.3791 0.1378 265.5222);
|
|
224
|
+
--sidebar-accent-foreground: oklch(0.8823 0.0571 254.1284);
|
|
225
|
+
--sidebar-border: oklch(0.3715 0 0);
|
|
226
|
+
--sidebar-ring: oklch(0.6231 0.188 259.8145);
|
|
227
|
+
--font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
|
|
228
|
+
'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
|
229
|
+
--font-serif: ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif;
|
|
230
|
+
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
|
231
|
+
--radius: 0.625rem;
|
|
232
|
+
--shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
|
|
233
|
+
--shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
|
|
234
|
+
--shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1);
|
|
235
|
+
--shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1);
|
|
236
|
+
--shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 2px 4px -1px hsl(0 0% 0% / 0.1);
|
|
237
|
+
--shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 4px 6px -1px hsl(0 0% 0% / 0.1);
|
|
238
|
+
--shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 8px 10px -1px hsl(0 0% 0% / 0.1);
|
|
239
|
+
--shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/* PhoneInput flag sizing overrides for h-9 (36px) container */
|
|
243
|
+
.PhoneInput {
|
|
244
|
+
--PhoneInputCountryFlag-height: 1rem;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.PhoneInputCountryIcon {
|
|
248
|
+
max-width: 1rem;
|
|
249
|
+
max-height: 1rem;
|
|
250
|
+
}
|
|
@@ -1,7 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
children: React.ReactNode;
|
|
4
|
-
}
|
|
5
|
-
export declare const AuthProvider: React.FC<AuthProviderProps>;
|
|
6
|
-
export {};
|
|
7
|
-
//# sourceMappingURL=AuthProvider.d.ts.map
|
|
1
|
+
export * from './index'
|
|
2
|
+
export {}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { O as OnboardingContext, a as OnboardingProvider, u as useOnboarding } from '../OnboardingProvider.js';
|
|
2
2
|
//# sourceMappingURL=AuthProvider.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -8,24 +8,6 @@ import { Value as PhoneValue } from 'react-phone-number-input';
|
|
|
8
8
|
import * as React_2 from 'react';
|
|
9
9
|
import { VariantProps } from 'class-variance-authority';
|
|
10
10
|
|
|
11
|
-
export declare const AuthContext: Context<AuthContextType | undefined>;
|
|
12
|
-
|
|
13
|
-
export declare interface AuthContextType {
|
|
14
|
-
accessToken: string | null;
|
|
15
|
-
isAuthenticated: boolean;
|
|
16
|
-
isLoading: boolean;
|
|
17
|
-
error: string | null;
|
|
18
|
-
refreshToken: () => Promise<void>;
|
|
19
|
-
logout: () => void;
|
|
20
|
-
setToken: (token: string) => void;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export declare const AuthProvider: default_2.FC<AuthProviderProps>;
|
|
24
|
-
|
|
25
|
-
declare interface AuthProviderProps {
|
|
26
|
-
children: default_2.ReactNode;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
11
|
export declare function Button({
|
|
30
12
|
className,
|
|
31
13
|
variant,
|
|
@@ -139,6 +121,32 @@ export declare function cn(...inputs: ClassValue[]) {
|
|
|
139
121
|
|
|
140
122
|
export { isValidPhoneNumber }
|
|
141
123
|
|
|
124
|
+
export declare const OnboardingContext: Context<OnboardingContextType | undefined>;
|
|
125
|
+
|
|
126
|
+
export declare interface OnboardingContextType extends OnboardingData {
|
|
127
|
+
onboardingToken: string | null;
|
|
128
|
+
isLoading: boolean;
|
|
129
|
+
error: string | null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export declare interface OnboardingData {
|
|
133
|
+
userId: string;
|
|
134
|
+
email: string;
|
|
135
|
+
firstName: string;
|
|
136
|
+
lastName: string;
|
|
137
|
+
currentStep: string;
|
|
138
|
+
onboardingComplete: boolean;
|
|
139
|
+
accountStatus: string;
|
|
140
|
+
emailVerified: boolean;
|
|
141
|
+
phoneVerified: boolean;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export declare const OnboardingProvider: default_2.FC<OnboardingProviderProps>;
|
|
145
|
+
|
|
146
|
+
declare interface OnboardingProviderProps {
|
|
147
|
+
children: default_2.ReactNode;
|
|
148
|
+
}
|
|
149
|
+
|
|
142
150
|
export declare const PasswordField: default_2.FC<PasswordFieldProps>;
|
|
143
151
|
|
|
144
152
|
declare interface PasswordFieldProps extends Omit<TextFieldProps, 'type' | 'endAdornment'> {
|
|
@@ -191,6 +199,6 @@ declare interface TypographyProps {
|
|
|
191
199
|
className?: string;
|
|
192
200
|
}
|
|
193
201
|
|
|
194
|
-
export declare const
|
|
202
|
+
export declare const useOnboarding: () => OnboardingContextType;
|
|
195
203
|
|
|
196
204
|
export { }
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { O as OnboardingContext, a as OnboardingProvider, u as useOnboarding } from './OnboardingProvider.js';
|
|
2
2
|
export { c as cn } from './utils.js';
|
|
3
3
|
export { B as Button, b as buttonVariants } from './Button.js';
|
|
4
4
|
export { C as Card, a as CardContent, b as CardDescription, c as CardFooter, d as CardHeader, e as CardTitle } from './Card.js';
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
8
|
-
"version": "0.1.
|
|
8
|
+
"version": "0.1.11",
|
|
9
9
|
"type": "module",
|
|
10
10
|
"sideEffects": false,
|
|
11
11
|
"repository": {
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"types": "./dist/AuthProvider.d.ts",
|
|
85
85
|
"import": "./dist/context/AuthProvider.js"
|
|
86
86
|
},
|
|
87
|
-
"./
|
|
87
|
+
"./index.css": "./dist/assets/quantum-ui.css"
|
|
88
88
|
},
|
|
89
89
|
"files": [
|
|
90
90
|
"dist"
|
package/dist/AuthProvider.js
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
-
import { createContext, useContext, useState, useRef, useCallback, useEffect } from 'react';
|
|
3
|
-
import { useNavigate } from 'react-router-dom';
|
|
4
|
-
import { axios } from './utils/axios.js';
|
|
5
|
-
|
|
6
|
-
const AuthContext = createContext(void 0);
|
|
7
|
-
const useAuth = () => {
|
|
8
|
-
const context = useContext(AuthContext);
|
|
9
|
-
if (!context) {
|
|
10
|
-
throw new Error("useAuth must be used within an AuthProvider");
|
|
11
|
-
}
|
|
12
|
-
return context;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const TOKEN_REFRESH_INTERVAL = 15 * 60 * 1e3;
|
|
16
|
-
const AuthProvider = ({ children }) => {
|
|
17
|
-
const [accessToken, setAccessToken] = useState(null);
|
|
18
|
-
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
|
19
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
20
|
-
const [error, setError] = useState(null);
|
|
21
|
-
const navigate = useNavigate();
|
|
22
|
-
const refreshTimerRef = useRef(null);
|
|
23
|
-
const isRefreshingRef = useRef(false);
|
|
24
|
-
const refreshToken = useCallback(async () => {
|
|
25
|
-
if (isRefreshingRef.current) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
try {
|
|
29
|
-
isRefreshingRef.current = true;
|
|
30
|
-
setError(null);
|
|
31
|
-
const response = await axios.get("/auth/refresh-application");
|
|
32
|
-
const { accessToken: newToken } = response.data;
|
|
33
|
-
if (newToken) {
|
|
34
|
-
setAccessToken(newToken);
|
|
35
|
-
setIsAuthenticated(true);
|
|
36
|
-
} else {
|
|
37
|
-
throw new Error("No access token received");
|
|
38
|
-
}
|
|
39
|
-
} catch (err) {
|
|
40
|
-
console.error("Token refresh failed:", err);
|
|
41
|
-
setError("Authentication failed");
|
|
42
|
-
setAccessToken(null);
|
|
43
|
-
setIsAuthenticated(false);
|
|
44
|
-
navigate("/login", { replace: true });
|
|
45
|
-
} finally {
|
|
46
|
-
isRefreshingRef.current = false;
|
|
47
|
-
setIsLoading(false);
|
|
48
|
-
}
|
|
49
|
-
}, [navigate]);
|
|
50
|
-
const setToken = useCallback((token) => {
|
|
51
|
-
setAccessToken(token);
|
|
52
|
-
setIsAuthenticated(true);
|
|
53
|
-
}, []);
|
|
54
|
-
const logout = useCallback(() => {
|
|
55
|
-
setAccessToken(null);
|
|
56
|
-
setIsAuthenticated(false);
|
|
57
|
-
setError(null);
|
|
58
|
-
if (refreshTimerRef.current) {
|
|
59
|
-
clearInterval(refreshTimerRef.current);
|
|
60
|
-
refreshTimerRef.current = null;
|
|
61
|
-
}
|
|
62
|
-
navigate("/login", { replace: true });
|
|
63
|
-
}, [navigate]);
|
|
64
|
-
useEffect(() => {
|
|
65
|
-
refreshToken();
|
|
66
|
-
}, [refreshToken]);
|
|
67
|
-
useEffect(() => {
|
|
68
|
-
if (isAuthenticated && accessToken) {
|
|
69
|
-
if (refreshTimerRef.current) {
|
|
70
|
-
clearInterval(refreshTimerRef.current);
|
|
71
|
-
}
|
|
72
|
-
refreshTimerRef.current = setInterval(() => {
|
|
73
|
-
refreshToken();
|
|
74
|
-
}, TOKEN_REFRESH_INTERVAL);
|
|
75
|
-
}
|
|
76
|
-
return () => {
|
|
77
|
-
if (refreshTimerRef.current) {
|
|
78
|
-
clearInterval(refreshTimerRef.current);
|
|
79
|
-
refreshTimerRef.current = null;
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
}, [isAuthenticated, accessToken, refreshToken]);
|
|
83
|
-
useEffect(() => {
|
|
84
|
-
const requestInterceptor = axios.interceptors.request.use(
|
|
85
|
-
(config) => {
|
|
86
|
-
if (accessToken && config.headers) {
|
|
87
|
-
config.headers.Authorization = `Bearer ${accessToken}`;
|
|
88
|
-
}
|
|
89
|
-
return config;
|
|
90
|
-
},
|
|
91
|
-
(error2) => Promise.reject(error2)
|
|
92
|
-
);
|
|
93
|
-
const responseInterceptor = axios.interceptors.response.use(
|
|
94
|
-
(response) => response,
|
|
95
|
-
async (error2) => {
|
|
96
|
-
const originalRequest = error2.config;
|
|
97
|
-
if (error2.response?.status === 401 && !originalRequest._retry) {
|
|
98
|
-
originalRequest._retry = true;
|
|
99
|
-
try {
|
|
100
|
-
await refreshToken();
|
|
101
|
-
if (accessToken && originalRequest.headers) {
|
|
102
|
-
originalRequest.headers.Authorization = `Bearer ${accessToken}`;
|
|
103
|
-
}
|
|
104
|
-
return axios(originalRequest);
|
|
105
|
-
} catch (refreshError) {
|
|
106
|
-
logout();
|
|
107
|
-
return Promise.reject(refreshError);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
return Promise.reject(error2);
|
|
111
|
-
}
|
|
112
|
-
);
|
|
113
|
-
return () => {
|
|
114
|
-
axios.interceptors.request.eject(requestInterceptor);
|
|
115
|
-
axios.interceptors.response.eject(responseInterceptor);
|
|
116
|
-
};
|
|
117
|
-
}, [accessToken, refreshToken, logout]);
|
|
118
|
-
const value = {
|
|
119
|
-
accessToken,
|
|
120
|
-
isAuthenticated,
|
|
121
|
-
isLoading,
|
|
122
|
-
error,
|
|
123
|
-
refreshToken,
|
|
124
|
-
logout,
|
|
125
|
-
setToken
|
|
126
|
-
};
|
|
127
|
-
if (isLoading) {
|
|
128
|
-
return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center min-h-screen", children: /* @__PURE__ */ jsxs("div", { className: "text-center space-y-4", children: [
|
|
129
|
-
/* @__PURE__ */ jsx("div", { className: "animate-spin rounded-full h-12 w-12 border-b-2 border-primary mx-auto" }),
|
|
130
|
-
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "Loading..." })
|
|
131
|
-
] }) });
|
|
132
|
-
}
|
|
133
|
-
return /* @__PURE__ */ jsx(AuthContext.Provider, { value, children });
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
export { AuthContext as A, AuthProvider as a, useAuth as u };
|
|
137
|
-
//# sourceMappingURL=AuthProvider.js.map
|
package/dist/AuthProvider.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AuthProvider.js","sources":["../lib/context/AuthContext.tsx","../lib/context/AuthProvider.tsx"],"sourcesContent":["import { createContext, useContext } from 'react';\n\nexport interface AuthContextType {\n accessToken: string | null;\n isAuthenticated: boolean;\n isLoading: boolean;\n error: string | null;\n refreshToken: () => Promise<void>;\n logout: () => void;\n setToken: (token: string) => void;\n}\n\nexport const AuthContext = createContext<AuthContextType | undefined>(undefined);\n\nexport const useAuth = (): AuthContextType => {\n const context = useContext(AuthContext);\n if (!context) {\n throw new Error('useAuth must be used within an AuthProvider');\n }\n return context;\n};\n","import React, { useEffect, useState, useCallback, useRef } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { AuthContext, type AuthContextType } from './AuthContext';\nimport { axios } from '../utils/axios';\nimport type { AxiosError, InternalAxiosRequestConfig } from 'axios';\n\ninterface AuthProviderProps {\n children: React.ReactNode;\n}\n\ninterface RefreshResponse {\n accessToken: string;\n}\n\nconst TOKEN_REFRESH_INTERVAL = 15 * 60 * 1000; // 15 minutes in milliseconds\n\nexport const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {\n const [accessToken, setAccessToken] = useState<string | null>(null);\n const [isAuthenticated, setIsAuthenticated] = useState(false);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const navigate = useNavigate();\n\n const refreshTimerRef = useRef<NodeJS.Timeout | null>(null);\n const isRefreshingRef = useRef(false);\n\n // Fetch and set token\n const refreshToken = useCallback(async () => {\n // Prevent multiple simultaneous refresh attempts\n if (isRefreshingRef.current) {\n return;\n }\n\n try {\n isRefreshingRef.current = true;\n setError(null);\n\n const response = await axios.get<RefreshResponse>('/auth/refresh-application');\n\n const { accessToken: newToken } = response.data;\n\n if (newToken) {\n setAccessToken(newToken);\n setIsAuthenticated(true);\n } else {\n throw new Error('No access token received');\n }\n } catch (err) {\n console.error('Token refresh failed:', err);\n setError('Authentication failed');\n setAccessToken(null);\n setIsAuthenticated(false);\n\n // Redirect to login on failure\n navigate('/login', { replace: true });\n } finally {\n isRefreshingRef.current = false;\n setIsLoading(false);\n }\n }, [navigate]);\n\n // Set token manually\n const setToken = useCallback((token: string) => {\n setAccessToken(token);\n setIsAuthenticated(true);\n }, []);\n\n // Logout function\n const logout = useCallback(() => {\n setAccessToken(null);\n setIsAuthenticated(false);\n setError(null);\n\n // Clear refresh timer\n if (refreshTimerRef.current) {\n clearInterval(refreshTimerRef.current);\n refreshTimerRef.current = null;\n }\n\n navigate('/login', { replace: true });\n }, [navigate]);\n\n // Initial token fetch on mount\n useEffect(() => {\n refreshToken();\n }, [refreshToken]);\n\n // Set up periodic token refresh\n useEffect(() => {\n if (isAuthenticated && accessToken) {\n // Clear any existing timer\n if (refreshTimerRef.current) {\n clearInterval(refreshTimerRef.current);\n }\n\n // Set up new refresh timer\n refreshTimerRef.current = setInterval(() => {\n refreshToken();\n }, TOKEN_REFRESH_INTERVAL);\n }\n\n // Cleanup on unmount or when auth state changes\n return () => {\n if (refreshTimerRef.current) {\n clearInterval(refreshTimerRef.current);\n refreshTimerRef.current = null;\n }\n };\n }, [isAuthenticated, accessToken, refreshToken]);\n\n // Set up axios interceptors\n useEffect(() => {\n // Request interceptor - Add authorization header\n const requestInterceptor = axios.interceptors.request.use(\n (config: InternalAxiosRequestConfig) => {\n if (accessToken && config.headers) {\n config.headers.Authorization = `Bearer ${accessToken}`;\n }\n return config;\n },\n (error) => Promise.reject(error)\n );\n\n // Response interceptor - Handle 401 errors\n const responseInterceptor = axios.interceptors.response.use(\n (response) => response,\n async (error: AxiosError) => {\n const originalRequest = error.config as InternalAxiosRequestConfig & { _retry?: boolean };\n\n // If 401 error and not already retried\n if (error.response?.status === 401 && !originalRequest._retry) {\n originalRequest._retry = true;\n\n try {\n // Try to refresh token\n await refreshToken();\n\n // Retry original request with new token\n if (accessToken && originalRequest.headers) {\n originalRequest.headers.Authorization = `Bearer ${accessToken}`;\n }\n\n return axios(originalRequest);\n } catch (refreshError) {\n // Refresh failed, logout user\n logout();\n return Promise.reject(refreshError);\n }\n }\n\n return Promise.reject(error);\n }\n );\n\n // Cleanup interceptors on unmount\n return () => {\n axios.interceptors.request.eject(requestInterceptor);\n axios.interceptors.response.eject(responseInterceptor);\n };\n }, [accessToken, refreshToken, logout]);\n\n const value: AuthContextType = {\n accessToken,\n isAuthenticated,\n isLoading,\n error,\n refreshToken,\n logout,\n setToken,\n };\n\n // Show loading state during initial authentication\n if (isLoading) {\n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <div className=\"text-center space-y-4\">\n <div className=\"animate-spin rounded-full h-12 w-12 border-b-2 border-primary mx-auto\"></div>\n <p className=\"text-muted-foreground\">Loading...</p>\n </div>\n </div>\n );\n }\n\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\n};\n"],"names":["error"],"mappings":"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"}
|