@atlashub/smartstack 3.8.0 → 3.10.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/dist/{AuthCallbackPage-CbkCo5cL.cjs → AuthCallbackPage-Bv2Cyn80.cjs} +2 -2
- package/dist/{AuthCallbackPage-CbkCo5cL.cjs.map → AuthCallbackPage-Bv2Cyn80.cjs.map} +1 -1
- package/dist/{AuthCallbackPage-UbzOvvaa.js → AuthCallbackPage-Cu74zAX1.js} +2 -2
- package/dist/{AuthCallbackPage-UbzOvvaa.js.map → AuthCallbackPage-Cu74zAX1.js.map} +1 -1
- package/dist/{ConfirmEmailPage-Cui47UrD.js → ConfirmEmailPage-BTp8J0pw.js} +2 -2
- package/dist/{ConfirmEmailPage-Cui47UrD.js.map → ConfirmEmailPage-BTp8J0pw.js.map} +1 -1
- package/dist/{ConfirmEmailPage-BkCDKBy0.cjs → ConfirmEmailPage-su3Fvl0e.cjs} +2 -2
- package/dist/{ConfirmEmailPage-BkCDKBy0.cjs.map → ConfirmEmailPage-su3Fvl0e.cjs.map} +1 -1
- package/dist/{ForceChangePasswordPage-ov-jJgku.js → ForceChangePasswordPage-ClENqzCH.js} +2 -2
- package/dist/{ForceChangePasswordPage-ov-jJgku.js.map → ForceChangePasswordPage-ClENqzCH.js.map} +1 -1
- package/dist/{ForceChangePasswordPage-3ozgKLOY.cjs → ForceChangePasswordPage-kEFsb5Aq.cjs} +2 -2
- package/dist/{ForceChangePasswordPage-3ozgKLOY.cjs.map → ForceChangePasswordPage-kEFsb5Aq.cjs.map} +1 -1
- package/dist/{ForgotPasswordPage-DkrQI8cO.cjs → ForgotPasswordPage--Wl0Vxbv.cjs} +2 -2
- package/dist/{ForgotPasswordPage-DkrQI8cO.cjs.map → ForgotPasswordPage--Wl0Vxbv.cjs.map} +1 -1
- package/dist/{ForgotPasswordPage-CNyDYEfP.js → ForgotPasswordPage-BEgvV5f-.js} +2 -2
- package/dist/{ForgotPasswordPage-CNyDYEfP.js.map → ForgotPasswordPage-BEgvV5f-.js.map} +1 -1
- package/dist/{OnboardingWizardPage-DNoe1_iv.js → OnboardingWizardPage-Bx1UlTbr.js} +2 -2
- package/dist/{OnboardingWizardPage-DNoe1_iv.js.map → OnboardingWizardPage-Bx1UlTbr.js.map} +1 -1
- package/dist/{OnboardingWizardPage-BWMGYiu9.cjs → OnboardingWizardPage-C7vendrq.cjs} +2 -2
- package/dist/{OnboardingWizardPage-BWMGYiu9.cjs.map → OnboardingWizardPage-C7vendrq.cjs.map} +1 -1
- package/dist/{RegisterPage-DUGhJPnX.js → RegisterPage-BzV0sCTe.js} +2 -2
- package/dist/{RegisterPage-DUGhJPnX.js.map → RegisterPage-BzV0sCTe.js.map} +1 -1
- package/dist/{RegisterPage--lihqFk7.cjs → RegisterPage-DKr8quRk.cjs} +2 -2
- package/dist/{RegisterPage--lihqFk7.cjs.map → RegisterPage-DKr8quRk.cjs.map} +1 -1
- package/dist/{ResetPasswordPage-BxZb9y8W.js → ResetPasswordPage-DphmJrcJ.js} +2 -2
- package/dist/{ResetPasswordPage-BxZb9y8W.js.map → ResetPasswordPage-DphmJrcJ.js.map} +1 -1
- package/dist/{ResetPasswordPage-BpVqJA06.cjs → ResetPasswordPage-x4do1o-j.cjs} +2 -2
- package/dist/{ResetPasswordPage-BpVqJA06.cjs.map → ResetPasswordPage-x4do1o-j.cjs.map} +1 -1
- package/dist/{index-C2c3iEpN.js → index-0Jhdcj59.js} +3 -3
- package/dist/index-0Jhdcj59.js.map +1 -0
- package/dist/{index-CHdBJkh4.cjs → index-C6C5XmVj.cjs} +3 -3
- package/dist/index-C6C5XmVj.cjs.map +1 -0
- package/dist/smartstack.cjs +1 -1
- package/dist/smartstack.js +1 -1
- package/package.json +1 -1
- package/dist/index-C2c3iEpN.js.map +0 -1
- package/dist/index-CHdBJkh4.cjs.map +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),u=require("react"),h=require("react-router-dom"),c=require("lucide-react"),m=require("./index-
|
|
2
|
-
//# sourceMappingURL=AuthCallbackPage-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),u=require("react"),h=require("react-router-dom"),c=require("lucide-react"),m=require("./index-C6C5XmVj.cjs"),v={auth_failed:"L'authentification a échoué. Veuillez réessayer.",no_email:"Impossible de récupérer votre adresse email depuis le fournisseur.",account_disabled:"Votre compte est désactivé. Contactez l'administrateur.",account_locked:"Votre compte est verrouillé. Contactez l'administrateur.",internal_error:"Une erreur interne est survenue. Veuillez réessayer."};function y(){const[o]=h.useSearchParams(),g=h.useNavigate(),[l,a]=u.useState("processing"),[x,d]=u.useState("");u.useEffect(()=>{const r=o.get("token"),i=o.get("refreshToken"),s=o.get("error");if(s){a("error"),d(v[s]||"Une erreur est survenue lors de l'authentification.");return}r&&i?f(r,i):(a("error"),d("Paramètres d'authentification manquants."))},[o]);const f=async(r,i)=>{try{localStorage.setItem("token",r),localStorage.setItem("refreshToken",i);try{const t=await m.getClientIpAddress(),n=m.detectDeviceType();(t||n)&&await fetch("/api/auth/update-session-client-info",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${r}`},body:JSON.stringify({clientIp:t,deviceType:n})})}catch{}const s=await fetch("/api/auth/me",{headers:{Authorization:`Bearer ${r}`}});if(!s.ok)throw new Error("Failed to fetch user info");const p=await s.json();localStorage.setItem("user",JSON.stringify(p));try{const t=await fetch("/api/onboarding/status",{headers:{Authorization:`Bearer ${r}`}});if(t.ok&&!(await t.json()).hasCompletedOnboarding){a("success"),setTimeout(()=>{window.location.href="/auth/onboarding"},1500);return}}catch{}try{const t=await m.userApi.preferences.get(),n={mode:t.theme||"dark",accentColorKey:t.accentColorKey||"indigo",borderRadius:t.borderRadius||{},itemPaletteKey:t.itemPaletteKey||"neutral"};localStorage.setItem("smartstack-theme-config",JSON.stringify(n)),t.language&&localStorage.setItem("i18nextLng",t.language)}catch{}a("success"),localStorage.removeItem("currentTenantId"),localStorage.removeItem("currentTenantSlug"),localStorage.removeItem("isGlobalView"),setTimeout(()=>{window.location.href="/myspace"},1500)}catch(s){console.error("Auth callback error:",s),a("error"),d("Erreur lors de la finalisation de l'authentification.")}},b=()=>{g("/login")};return e.jsx("div",{className:"min-h-screen flex items-center justify-center bg-[var(--bg-primary)]",children:e.jsx("div",{className:"max-w-md w-full mx-4",children:e.jsxs("div",{className:"bg-[var(--bg-secondary)] rounded-2xl p-8 shadow-lg border border-[var(--border-color)]",children:[l==="processing"&&e.jsxs("div",{className:"text-center",children:[e.jsx(c.Loader2,{className:"w-16 h-16 mx-auto text-[var(--color-accent-500)] animate-spin mb-4"}),e.jsx("h2",{className:"text-xl font-semibold mb-2",children:"Authentification en cours..."}),e.jsx("p",{className:"text-[var(--text-secondary)]",children:"Veuillez patienter pendant que nous finalisons votre connexion."})]}),l==="success"&&e.jsxs("div",{className:"text-center",children:[e.jsx("div",{className:"w-16 h-16 mx-auto bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center mb-4",children:e.jsx(c.CheckCircle,{className:"w-10 h-10 text-green-600 dark:text-green-400"})}),e.jsx("h2",{className:"text-xl font-semibold mb-2",children:"Connexion réussie !"}),e.jsx("p",{className:"text-[var(--text-secondary)]",children:"Vous allez être redirigé vers votre espace personnel..."})]}),l==="error"&&e.jsxs("div",{className:"text-center",children:[e.jsx("div",{className:"w-16 h-16 mx-auto bg-red-100 dark:bg-red-900/30 rounded-full flex items-center justify-center mb-4",children:e.jsx(c.XCircle,{className:"w-10 h-10 text-red-600 dark:text-red-400"})}),e.jsx("h2",{className:"text-xl font-semibold mb-2",children:"Échec de l'authentification"}),e.jsx("div",{className:"bg-red-50 dark:bg-red-900/20 rounded-lg p-4 mb-6",children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(c.AlertCircle,{className:"w-5 h-5 text-red-600 dark:text-red-400 flex-shrink-0 mt-0.5"}),e.jsx("p",{className:"text-sm text-red-700 dark:text-red-300",children:x})]})}),e.jsx("button",{onClick:b,className:"btn btn-primary w-full",children:"Retourner à la connexion"})]})]})})})}exports.AuthCallbackPage=y;
|
|
2
|
+
//# sourceMappingURL=AuthCallbackPage-Bv2Cyn80.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthCallbackPage-CbkCo5cL.cjs","sources":["../src/pages/auth/AuthCallbackPage.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\r\nimport { useSearchParams, useNavigate } from 'react-router-dom';\r\nimport { Loader2, CheckCircle, XCircle, AlertCircle } from 'lucide-react';\r\nimport { userApi } from '@/services/api/userApi';\r\nimport { getClientIpAddress } from '@/utils/ipDetection';\r\nimport { detectDeviceType } from '@/utils/deviceDetection';\r\n\r\ntype CallbackStatus = 'processing' | 'success' | 'error';\r\n\r\nconst errorMessages: Record<string, string> = {\r\n auth_failed: 'L\\'authentification a échoué. Veuillez réessayer.',\r\n no_email: 'Impossible de récupérer votre adresse email depuis le fournisseur.',\r\n account_disabled: 'Votre compte est désactivé. Contactez l\\'administrateur.',\r\n account_locked: 'Votre compte est verrouillé. Contactez l\\'administrateur.',\r\n internal_error: 'Une erreur interne est survenue. Veuillez réessayer.',\r\n};\r\n\r\nexport function AuthCallbackPage() {\r\n const [searchParams] = useSearchParams();\r\n const navigate = useNavigate();\r\n const [status, setStatus] = useState<CallbackStatus>('processing');\r\n const [errorMessage, setErrorMessage] = useState<string>('');\r\n\r\n useEffect(() => {\r\n const token = searchParams.get('token');\r\n const refreshToken = searchParams.get('refreshToken');\r\n const error = searchParams.get('error');\r\n\r\n if (error) {\r\n setStatus('error');\r\n setErrorMessage(errorMessages[error] || 'Une erreur est survenue lors de l\\'authentification.');\r\n return;\r\n }\r\n\r\n if (token && refreshToken) {\r\n handleSuccessfulAuth(token, refreshToken);\r\n } else {\r\n setStatus('error');\r\n setErrorMessage('Paramètres d\\'authentification manquants.');\r\n }\r\n }, [searchParams]);\r\n\r\n const handleSuccessfulAuth = async (token: string, refreshToken: string) => {\r\n try {\r\n localStorage.setItem('token', token);\r\n localStorage.setItem('refreshToken', refreshToken);\r\n\r\n // Update session with client-side IP address (retrieved via external service like ipify.org)\r\n // This is important for OAuth flows where the server can't reliably get the client IP\r\n try {\r\n const clientIp = await getClientIpAddress();\r\n const deviceType = detectDeviceType();\r\n\r\n if (clientIp || deviceType) {\r\n await fetch(`/api/auth/update-session-client-info`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n Authorization: `Bearer ${token}`,\r\n },\r\n body: JSON.stringify({ clientIp, deviceType }),\r\n });\r\n }\r\n } catch (ipError) {\r\n // Non-critical - continue with the flow even if IP update fails\r\n }\r\n\r\n // Fetch user info\r\n const userResponse = await fetch(`/api/auth/me`, {\r\n headers: {\r\n Authorization: `Bearer ${token}`,\r\n },\r\n });\r\n\r\n if (!userResponse.ok) {\r\n throw new Error('Failed to fetch user info');\r\n }\r\n\r\n const user = await userResponse.json();\r\n localStorage.setItem('user', JSON.stringify(user));\r\n\r\n // Check if user needs onboarding\r\n try {\r\n const onboardingResponse = await fetch(`/api/onboarding/status`, {\r\n headers: {\r\n Authorization: `Bearer ${token}`,\r\n },\r\n });\r\n\r\n if (onboardingResponse.ok) {\r\n const onboardingData = await onboardingResponse.json();\r\n if (!onboardingData.hasCompletedOnboarding) {\r\n // Redirect to onboarding wizard\r\n setStatus('success');\r\n setTimeout(() => {\r\n window.location.href = '/auth/onboarding';\r\n }, 1500);\r\n return;\r\n }\r\n }\r\n } catch {\r\n // Non-critical - continue with normal flow\r\n }\r\n\r\n // Fetch user preferences\r\n try {\r\n const prefs = await userApi.preferences.get();\r\n const themeConfig = {\r\n mode: prefs.theme || 'dark',\r\n accentColorKey: prefs.accentColorKey || 'indigo',\r\n borderRadius: prefs.borderRadius || {},\r\n itemPaletteKey: prefs.itemPaletteKey || 'neutral',\r\n };\r\n localStorage.setItem('smartstack-theme-config', JSON.stringify(themeConfig));\r\n if (prefs.language) {\r\n localStorage.setItem('i18nextLng', prefs.language);\r\n }\r\n } catch {\r\n // Non-critical - continue with defaults\r\n }\r\n\r\n setStatus('success');\r\n\r\n // Clear stale tenant state so TenantContext uses the user's configured default tenant (Priority 3: isDefault)\r\n localStorage.removeItem('currentTenantId');\r\n localStorage.removeItem('currentTenantSlug');\r\n localStorage.removeItem('isGlobalView');\r\n\r\n // Redirect after showing success\r\n setTimeout(() => {\r\n window.location.href = '/myspace';\r\n }, 1500);\r\n } catch (err) {\r\n console.error('Auth callback error:', err);\r\n setStatus('error');\r\n setErrorMessage('Erreur lors de la finalisation de l\\'authentification.');\r\n }\r\n };\r\n\r\n const handleRetry = () => {\r\n navigate('/login');\r\n };\r\n\r\n return (\r\n <div className=\"min-h-screen flex items-center justify-center bg-[var(--bg-primary)]\">\r\n <div className=\"max-w-md w-full mx-4\">\r\n <div className=\"bg-[var(--bg-secondary)] rounded-2xl p-8 shadow-lg border border-[var(--border-color)]\">\r\n {status === 'processing' && (\r\n <div className=\"text-center\">\r\n <Loader2 className=\"w-16 h-16 mx-auto text-[var(--color-accent-500)] animate-spin mb-4\" />\r\n <h2 className=\"text-xl font-semibold mb-2\">Authentification en cours...</h2>\r\n <p className=\"text-[var(--text-secondary)]\">\r\n Veuillez patienter pendant que nous finalisons votre connexion.\r\n </p>\r\n </div>\r\n )}\r\n\r\n {status === 'success' && (\r\n <div className=\"text-center\">\r\n <div className=\"w-16 h-16 mx-auto bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center mb-4\">\r\n <CheckCircle className=\"w-10 h-10 text-green-600 dark:text-green-400\" />\r\n </div>\r\n <h2 className=\"text-xl font-semibold mb-2\">Connexion réussie !</h2>\r\n <p className=\"text-[var(--text-secondary)]\">\r\n Vous allez être redirigé vers votre espace personnel...\r\n </p>\r\n </div>\r\n )}\r\n\r\n {status === 'error' && (\r\n <div className=\"text-center\">\r\n <div className=\"w-16 h-16 mx-auto bg-red-100 dark:bg-red-900/30 rounded-full flex items-center justify-center mb-4\">\r\n <XCircle className=\"w-10 h-10 text-red-600 dark:text-red-400\" />\r\n </div>\r\n <h2 className=\"text-xl font-semibold mb-2\">Échec de l'authentification</h2>\r\n <div className=\"bg-red-50 dark:bg-red-900/20 rounded-lg p-4 mb-6\">\r\n <div className=\"flex items-start gap-3\">\r\n <AlertCircle className=\"w-5 h-5 text-red-600 dark:text-red-400 flex-shrink-0 mt-0.5\" />\r\n <p className=\"text-sm text-red-700 dark:text-red-300\">{errorMessage}</p>\r\n </div>\r\n </div>\r\n <button\r\n onClick={handleRetry}\r\n className=\"btn btn-primary w-full\"\r\n >\r\n Retourner à la connexion\r\n </button>\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"names":["errorMessages","AuthCallbackPage","searchParams","useSearchParams","navigate","useNavigate","status","setStatus","useState","errorMessage","setErrorMessage","useEffect","token","refreshToken","error","handleSuccessfulAuth","clientIp","getClientIpAddress","deviceType","detectDeviceType","userResponse","user","onboardingResponse","prefs","userApi","themeConfig","err","handleRetry","jsx","jsxs","Loader2","CheckCircle","XCircle","AlertCircle"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AuthCallbackPage-Bv2Cyn80.cjs","sources":["../src/pages/auth/AuthCallbackPage.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\r\nimport { useSearchParams, useNavigate } from 'react-router-dom';\r\nimport { Loader2, CheckCircle, XCircle, AlertCircle } from 'lucide-react';\r\nimport { userApi } from '@/services/api/userApi';\r\nimport { getClientIpAddress } from '@/utils/ipDetection';\r\nimport { detectDeviceType } from '@/utils/deviceDetection';\r\n\r\ntype CallbackStatus = 'processing' | 'success' | 'error';\r\n\r\nconst errorMessages: Record<string, string> = {\r\n auth_failed: 'L\\'authentification a échoué. Veuillez réessayer.',\r\n no_email: 'Impossible de récupérer votre adresse email depuis le fournisseur.',\r\n account_disabled: 'Votre compte est désactivé. Contactez l\\'administrateur.',\r\n account_locked: 'Votre compte est verrouillé. Contactez l\\'administrateur.',\r\n internal_error: 'Une erreur interne est survenue. Veuillez réessayer.',\r\n};\r\n\r\nexport function AuthCallbackPage() {\r\n const [searchParams] = useSearchParams();\r\n const navigate = useNavigate();\r\n const [status, setStatus] = useState<CallbackStatus>('processing');\r\n const [errorMessage, setErrorMessage] = useState<string>('');\r\n\r\n useEffect(() => {\r\n const token = searchParams.get('token');\r\n const refreshToken = searchParams.get('refreshToken');\r\n const error = searchParams.get('error');\r\n\r\n if (error) {\r\n setStatus('error');\r\n setErrorMessage(errorMessages[error] || 'Une erreur est survenue lors de l\\'authentification.');\r\n return;\r\n }\r\n\r\n if (token && refreshToken) {\r\n handleSuccessfulAuth(token, refreshToken);\r\n } else {\r\n setStatus('error');\r\n setErrorMessage('Paramètres d\\'authentification manquants.');\r\n }\r\n }, [searchParams]);\r\n\r\n const handleSuccessfulAuth = async (token: string, refreshToken: string) => {\r\n try {\r\n localStorage.setItem('token', token);\r\n localStorage.setItem('refreshToken', refreshToken);\r\n\r\n // Update session with client-side IP address (retrieved via external service like ipify.org)\r\n // This is important for OAuth flows where the server can't reliably get the client IP\r\n try {\r\n const clientIp = await getClientIpAddress();\r\n const deviceType = detectDeviceType();\r\n\r\n if (clientIp || deviceType) {\r\n await fetch(`/api/auth/update-session-client-info`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n Authorization: `Bearer ${token}`,\r\n },\r\n body: JSON.stringify({ clientIp, deviceType }),\r\n });\r\n }\r\n } catch (ipError) {\r\n // Non-critical - continue with the flow even if IP update fails\r\n }\r\n\r\n // Fetch user info\r\n const userResponse = await fetch(`/api/auth/me`, {\r\n headers: {\r\n Authorization: `Bearer ${token}`,\r\n },\r\n });\r\n\r\n if (!userResponse.ok) {\r\n throw new Error('Failed to fetch user info');\r\n }\r\n\r\n const user = await userResponse.json();\r\n localStorage.setItem('user', JSON.stringify(user));\r\n\r\n // Check if user needs onboarding\r\n try {\r\n const onboardingResponse = await fetch(`/api/onboarding/status`, {\r\n headers: {\r\n Authorization: `Bearer ${token}`,\r\n },\r\n });\r\n\r\n if (onboardingResponse.ok) {\r\n const onboardingData = await onboardingResponse.json();\r\n if (!onboardingData.hasCompletedOnboarding) {\r\n // Redirect to onboarding wizard\r\n setStatus('success');\r\n setTimeout(() => {\r\n window.location.href = '/auth/onboarding';\r\n }, 1500);\r\n return;\r\n }\r\n }\r\n } catch {\r\n // Non-critical - continue with normal flow\r\n }\r\n\r\n // Fetch user preferences\r\n try {\r\n const prefs = await userApi.preferences.get();\r\n const themeConfig = {\r\n mode: prefs.theme || 'dark',\r\n accentColorKey: prefs.accentColorKey || 'indigo',\r\n borderRadius: prefs.borderRadius || {},\r\n itemPaletteKey: prefs.itemPaletteKey || 'neutral',\r\n };\r\n localStorage.setItem('smartstack-theme-config', JSON.stringify(themeConfig));\r\n if (prefs.language) {\r\n localStorage.setItem('i18nextLng', prefs.language);\r\n }\r\n } catch {\r\n // Non-critical - continue with defaults\r\n }\r\n\r\n setStatus('success');\r\n\r\n // Clear stale tenant state so TenantContext uses the user's configured default tenant (Priority 3: isDefault)\r\n localStorage.removeItem('currentTenantId');\r\n localStorage.removeItem('currentTenantSlug');\r\n localStorage.removeItem('isGlobalView');\r\n\r\n // Redirect after showing success\r\n setTimeout(() => {\r\n window.location.href = '/myspace';\r\n }, 1500);\r\n } catch (err) {\r\n console.error('Auth callback error:', err);\r\n setStatus('error');\r\n setErrorMessage('Erreur lors de la finalisation de l\\'authentification.');\r\n }\r\n };\r\n\r\n const handleRetry = () => {\r\n navigate('/login');\r\n };\r\n\r\n return (\r\n <div className=\"min-h-screen flex items-center justify-center bg-[var(--bg-primary)]\">\r\n <div className=\"max-w-md w-full mx-4\">\r\n <div className=\"bg-[var(--bg-secondary)] rounded-2xl p-8 shadow-lg border border-[var(--border-color)]\">\r\n {status === 'processing' && (\r\n <div className=\"text-center\">\r\n <Loader2 className=\"w-16 h-16 mx-auto text-[var(--color-accent-500)] animate-spin mb-4\" />\r\n <h2 className=\"text-xl font-semibold mb-2\">Authentification en cours...</h2>\r\n <p className=\"text-[var(--text-secondary)]\">\r\n Veuillez patienter pendant que nous finalisons votre connexion.\r\n </p>\r\n </div>\r\n )}\r\n\r\n {status === 'success' && (\r\n <div className=\"text-center\">\r\n <div className=\"w-16 h-16 mx-auto bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center mb-4\">\r\n <CheckCircle className=\"w-10 h-10 text-green-600 dark:text-green-400\" />\r\n </div>\r\n <h2 className=\"text-xl font-semibold mb-2\">Connexion réussie !</h2>\r\n <p className=\"text-[var(--text-secondary)]\">\r\n Vous allez être redirigé vers votre espace personnel...\r\n </p>\r\n </div>\r\n )}\r\n\r\n {status === 'error' && (\r\n <div className=\"text-center\">\r\n <div className=\"w-16 h-16 mx-auto bg-red-100 dark:bg-red-900/30 rounded-full flex items-center justify-center mb-4\">\r\n <XCircle className=\"w-10 h-10 text-red-600 dark:text-red-400\" />\r\n </div>\r\n <h2 className=\"text-xl font-semibold mb-2\">Échec de l'authentification</h2>\r\n <div className=\"bg-red-50 dark:bg-red-900/20 rounded-lg p-4 mb-6\">\r\n <div className=\"flex items-start gap-3\">\r\n <AlertCircle className=\"w-5 h-5 text-red-600 dark:text-red-400 flex-shrink-0 mt-0.5\" />\r\n <p className=\"text-sm text-red-700 dark:text-red-300\">{errorMessage}</p>\r\n </div>\r\n </div>\r\n <button\r\n onClick={handleRetry}\r\n className=\"btn btn-primary w-full\"\r\n >\r\n Retourner à la connexion\r\n </button>\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"names":["errorMessages","AuthCallbackPage","searchParams","useSearchParams","navigate","useNavigate","status","setStatus","useState","errorMessage","setErrorMessage","useEffect","token","refreshToken","error","handleSuccessfulAuth","clientIp","getClientIpAddress","deviceType","detectDeviceType","userResponse","user","onboardingResponse","prefs","userApi","themeConfig","err","handleRetry","jsx","jsxs","Loader2","CheckCircle","XCircle","AlertCircle"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { jsx as e, jsxs as o } from "react/jsx-runtime";
|
|
|
2
2
|
import { useState as m, useEffect as p } from "react";
|
|
3
3
|
import { useSearchParams as x, useNavigate as b } from "react-router-dom";
|
|
4
4
|
import { Loader2 as v, CheckCircle as y, XCircle as N, AlertCircle as w } from "lucide-react";
|
|
5
|
-
import { g as k, d as S, u as C } from "./index-
|
|
5
|
+
import { g as k, d as S, u as C } from "./index-0Jhdcj59.js";
|
|
6
6
|
const I = {
|
|
7
7
|
auth_failed: "L'authentification a échoué. Veuillez réessayer.",
|
|
8
8
|
no_email: "Impossible de récupérer votre adresse email depuis le fournisseur.",
|
|
@@ -109,4 +109,4 @@ function V() {
|
|
|
109
109
|
export {
|
|
110
110
|
V as AuthCallbackPage
|
|
111
111
|
};
|
|
112
|
-
//# sourceMappingURL=AuthCallbackPage-
|
|
112
|
+
//# sourceMappingURL=AuthCallbackPage-Cu74zAX1.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthCallbackPage-UbzOvvaa.js","sources":["../src/pages/auth/AuthCallbackPage.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\r\nimport { useSearchParams, useNavigate } from 'react-router-dom';\r\nimport { Loader2, CheckCircle, XCircle, AlertCircle } from 'lucide-react';\r\nimport { userApi } from '@/services/api/userApi';\r\nimport { getClientIpAddress } from '@/utils/ipDetection';\r\nimport { detectDeviceType } from '@/utils/deviceDetection';\r\n\r\ntype CallbackStatus = 'processing' | 'success' | 'error';\r\n\r\nconst errorMessages: Record<string, string> = {\r\n auth_failed: 'L\\'authentification a échoué. Veuillez réessayer.',\r\n no_email: 'Impossible de récupérer votre adresse email depuis le fournisseur.',\r\n account_disabled: 'Votre compte est désactivé. Contactez l\\'administrateur.',\r\n account_locked: 'Votre compte est verrouillé. Contactez l\\'administrateur.',\r\n internal_error: 'Une erreur interne est survenue. Veuillez réessayer.',\r\n};\r\n\r\nexport function AuthCallbackPage() {\r\n const [searchParams] = useSearchParams();\r\n const navigate = useNavigate();\r\n const [status, setStatus] = useState<CallbackStatus>('processing');\r\n const [errorMessage, setErrorMessage] = useState<string>('');\r\n\r\n useEffect(() => {\r\n const token = searchParams.get('token');\r\n const refreshToken = searchParams.get('refreshToken');\r\n const error = searchParams.get('error');\r\n\r\n if (error) {\r\n setStatus('error');\r\n setErrorMessage(errorMessages[error] || 'Une erreur est survenue lors de l\\'authentification.');\r\n return;\r\n }\r\n\r\n if (token && refreshToken) {\r\n handleSuccessfulAuth(token, refreshToken);\r\n } else {\r\n setStatus('error');\r\n setErrorMessage('Paramètres d\\'authentification manquants.');\r\n }\r\n }, [searchParams]);\r\n\r\n const handleSuccessfulAuth = async (token: string, refreshToken: string) => {\r\n try {\r\n localStorage.setItem('token', token);\r\n localStorage.setItem('refreshToken', refreshToken);\r\n\r\n // Update session with client-side IP address (retrieved via external service like ipify.org)\r\n // This is important for OAuth flows where the server can't reliably get the client IP\r\n try {\r\n const clientIp = await getClientIpAddress();\r\n const deviceType = detectDeviceType();\r\n\r\n if (clientIp || deviceType) {\r\n await fetch(`/api/auth/update-session-client-info`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n Authorization: `Bearer ${token}`,\r\n },\r\n body: JSON.stringify({ clientIp, deviceType }),\r\n });\r\n }\r\n } catch (ipError) {\r\n // Non-critical - continue with the flow even if IP update fails\r\n }\r\n\r\n // Fetch user info\r\n const userResponse = await fetch(`/api/auth/me`, {\r\n headers: {\r\n Authorization: `Bearer ${token}`,\r\n },\r\n });\r\n\r\n if (!userResponse.ok) {\r\n throw new Error('Failed to fetch user info');\r\n }\r\n\r\n const user = await userResponse.json();\r\n localStorage.setItem('user', JSON.stringify(user));\r\n\r\n // Check if user needs onboarding\r\n try {\r\n const onboardingResponse = await fetch(`/api/onboarding/status`, {\r\n headers: {\r\n Authorization: `Bearer ${token}`,\r\n },\r\n });\r\n\r\n if (onboardingResponse.ok) {\r\n const onboardingData = await onboardingResponse.json();\r\n if (!onboardingData.hasCompletedOnboarding) {\r\n // Redirect to onboarding wizard\r\n setStatus('success');\r\n setTimeout(() => {\r\n window.location.href = '/auth/onboarding';\r\n }, 1500);\r\n return;\r\n }\r\n }\r\n } catch {\r\n // Non-critical - continue with normal flow\r\n }\r\n\r\n // Fetch user preferences\r\n try {\r\n const prefs = await userApi.preferences.get();\r\n const themeConfig = {\r\n mode: prefs.theme || 'dark',\r\n accentColorKey: prefs.accentColorKey || 'indigo',\r\n borderRadius: prefs.borderRadius || {},\r\n itemPaletteKey: prefs.itemPaletteKey || 'neutral',\r\n };\r\n localStorage.setItem('smartstack-theme-config', JSON.stringify(themeConfig));\r\n if (prefs.language) {\r\n localStorage.setItem('i18nextLng', prefs.language);\r\n }\r\n } catch {\r\n // Non-critical - continue with defaults\r\n }\r\n\r\n setStatus('success');\r\n\r\n // Clear stale tenant state so TenantContext uses the user's configured default tenant (Priority 3: isDefault)\r\n localStorage.removeItem('currentTenantId');\r\n localStorage.removeItem('currentTenantSlug');\r\n localStorage.removeItem('isGlobalView');\r\n\r\n // Redirect after showing success\r\n setTimeout(() => {\r\n window.location.href = '/myspace';\r\n }, 1500);\r\n } catch (err) {\r\n console.error('Auth callback error:', err);\r\n setStatus('error');\r\n setErrorMessage('Erreur lors de la finalisation de l\\'authentification.');\r\n }\r\n };\r\n\r\n const handleRetry = () => {\r\n navigate('/login');\r\n };\r\n\r\n return (\r\n <div className=\"min-h-screen flex items-center justify-center bg-[var(--bg-primary)]\">\r\n <div className=\"max-w-md w-full mx-4\">\r\n <div className=\"bg-[var(--bg-secondary)] rounded-2xl p-8 shadow-lg border border-[var(--border-color)]\">\r\n {status === 'processing' && (\r\n <div className=\"text-center\">\r\n <Loader2 className=\"w-16 h-16 mx-auto text-[var(--color-accent-500)] animate-spin mb-4\" />\r\n <h2 className=\"text-xl font-semibold mb-2\">Authentification en cours...</h2>\r\n <p className=\"text-[var(--text-secondary)]\">\r\n Veuillez patienter pendant que nous finalisons votre connexion.\r\n </p>\r\n </div>\r\n )}\r\n\r\n {status === 'success' && (\r\n <div className=\"text-center\">\r\n <div className=\"w-16 h-16 mx-auto bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center mb-4\">\r\n <CheckCircle className=\"w-10 h-10 text-green-600 dark:text-green-400\" />\r\n </div>\r\n <h2 className=\"text-xl font-semibold mb-2\">Connexion réussie !</h2>\r\n <p className=\"text-[var(--text-secondary)]\">\r\n Vous allez être redirigé vers votre espace personnel...\r\n </p>\r\n </div>\r\n )}\r\n\r\n {status === 'error' && (\r\n <div className=\"text-center\">\r\n <div className=\"w-16 h-16 mx-auto bg-red-100 dark:bg-red-900/30 rounded-full flex items-center justify-center mb-4\">\r\n <XCircle className=\"w-10 h-10 text-red-600 dark:text-red-400\" />\r\n </div>\r\n <h2 className=\"text-xl font-semibold mb-2\">Échec de l'authentification</h2>\r\n <div className=\"bg-red-50 dark:bg-red-900/20 rounded-lg p-4 mb-6\">\r\n <div className=\"flex items-start gap-3\">\r\n <AlertCircle className=\"w-5 h-5 text-red-600 dark:text-red-400 flex-shrink-0 mt-0.5\" />\r\n <p className=\"text-sm text-red-700 dark:text-red-300\">{errorMessage}</p>\r\n </div>\r\n </div>\r\n <button\r\n onClick={handleRetry}\r\n className=\"btn btn-primary w-full\"\r\n >\r\n Retourner à la connexion\r\n </button>\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"names":["errorMessages","AuthCallbackPage","searchParams","useSearchParams","navigate","useNavigate","status","setStatus","useState","errorMessage","setErrorMessage","useEffect","token","refreshToken","error","handleSuccessfulAuth","clientIp","getClientIpAddress","deviceType","detectDeviceType","userResponse","user","onboardingResponse","prefs","userApi","themeConfig","err","jsx","jsxs","Loader2","CheckCircle","XCircle","AlertCircle"],"mappings":";;;;;AASA,MAAMA,IAAwC;AAAA,EAC5C,aAAa;AAAA,EACb,UAAU;AAAA,EACV,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,gBAAgB;AAClB;AAEO,SAASC,IAAmB;AACjC,QAAM,CAACC,CAAY,IAAIC,EAAA,GACjBC,IAAWC,EAAA,GACX,CAACC,GAAQC,CAAS,IAAIC,EAAyB,YAAY,GAC3D,CAACC,GAAcC,CAAe,IAAIF,EAAiB,EAAE;AAE3D,EAAAG,EAAU,MAAM;AACd,UAAMC,IAAQV,EAAa,IAAI,OAAO,GAChCW,IAAeX,EAAa,IAAI,cAAc,GAC9CY,IAAQZ,EAAa,IAAI,OAAO;AAEtC,QAAIY,GAAO;AACT,MAAAP,EAAU,OAAO,GACjBG,EAAgBV,EAAcc,CAAK,KAAK,qDAAsD;AAC9F;AAAA,IACF;AAEA,IAAIF,KAASC,IACXE,EAAqBH,GAAOC,CAAY,KAExCN,EAAU,OAAO,GACjBG,EAAgB,0CAA2C;AAAA,EAE/D,GAAG,CAACR,CAAY,CAAC;AAEjB,QAAMa,IAAuB,OAAOH,GAAeC,MAAyB;AAC1E,QAAI;AACF,mBAAa,QAAQ,SAASD,CAAK,GACnC,aAAa,QAAQ,gBAAgBC,CAAY;AAIjD,UAAI;AACF,cAAMG,IAAW,MAAMC,EAAA,GACjBC,IAAaC,EAAA;AAEnB,SAAIH,KAAYE,MACd,MAAM,MAAM,wCAAwC;AAAA,UAClD,QAAQ;AAAA,UACR,SAAS;AAAA,YACP,gBAAgB;AAAA,YAChB,eAAe,UAAUN,CAAK;AAAA,UAAA;AAAA,UAEhC,MAAM,KAAK,UAAU,EAAE,UAAAI,GAAU,YAAAE,GAAY;AAAA,QAAA,CAC9C;AAAA,MAEL,QAAkB;AAAA,MAElB;AAGA,YAAME,IAAe,MAAM,MAAM,gBAAgB;AAAA,QAC/C,SAAS;AAAA,UACP,eAAe,UAAUR,CAAK;AAAA,QAAA;AAAA,MAChC,CACD;AAED,UAAI,CAACQ,EAAa;AAChB,cAAM,IAAI,MAAM,2BAA2B;AAG7C,YAAMC,IAAO,MAAMD,EAAa,KAAA;AAChC,mBAAa,QAAQ,QAAQ,KAAK,UAAUC,CAAI,CAAC;AAGjD,UAAI;AACF,cAAMC,IAAqB,MAAM,MAAM,0BAA0B;AAAA,UAC/D,SAAS;AAAA,YACP,eAAe,UAAUV,CAAK;AAAA,UAAA;AAAA,QAChC,CACD;AAED,YAAIU,EAAmB,MAEjB,EADmB,MAAMA,EAAmB,KAAA,GAC5B,wBAAwB;AAE1C,UAAAf,EAAU,SAAS,GACnB,WAAW,MAAM;AACf,mBAAO,SAAS,OAAO;AAAA,UACzB,GAAG,IAAI;AACP;AAAA,QACF;AAAA,MAEJ,QAAQ;AAAA,MAER;AAGA,UAAI;AACF,cAAMgB,IAAQ,MAAMC,EAAQ,YAAY,IAAA,GAClCC,IAAc;AAAA,UAClB,MAAMF,EAAM,SAAS;AAAA,UACrB,gBAAgBA,EAAM,kBAAkB;AAAA,UACxC,cAAcA,EAAM,gBAAgB,CAAA;AAAA,UACpC,gBAAgBA,EAAM,kBAAkB;AAAA,QAAA;AAE1C,qBAAa,QAAQ,2BAA2B,KAAK,UAAUE,CAAW,CAAC,GACvEF,EAAM,YACR,aAAa,QAAQ,cAAcA,EAAM,QAAQ;AAAA,MAErD,QAAQ;AAAA,MAER;AAEA,MAAAhB,EAAU,SAAS,GAGnB,aAAa,WAAW,iBAAiB,GACzC,aAAa,WAAW,mBAAmB,GAC3C,aAAa,WAAW,cAAc,GAGtC,WAAW,MAAM;AACf,eAAO,SAAS,OAAO;AAAA,MACzB,GAAG,IAAI;AAAA,IACT,SAASmB,GAAK;AACZ,cAAQ,MAAM,wBAAwBA,CAAG,GACzCnB,EAAU,OAAO,GACjBG,EAAgB,uDAAwD;AAAA,IAC1E;AAAA,EACF;AAMA,SACE,gBAAAiB,EAAC,OAAA,EAAI,WAAU,wEACb,UAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,wBACb,UAAA,gBAAAC,EAAC,OAAA,EAAI,WAAU,0FACZ,UAAA;AAAA,IAAAtB,MAAW,gBACV,gBAAAsB,EAAC,OAAA,EAAI,WAAU,eACb,UAAA;AAAA,MAAA,gBAAAD,EAACE,GAAA,EAAQ,WAAU,qEAAA,CAAqE;AAAA,MACxF,gBAAAF,EAAC,MAAA,EAAG,WAAU,8BAA6B,UAAA,gCAA4B;AAAA,MACvE,gBAAAA,EAAC,KAAA,EAAE,WAAU,gCAA+B,UAAA,kEAAA,CAE5C;AAAA,IAAA,GACF;AAAA,IAGDrB,MAAW,aACV,gBAAAsB,EAAC,OAAA,EAAI,WAAU,eACb,UAAA;AAAA,MAAA,gBAAAD,EAAC,SAAI,WAAU,0GACb,4BAACG,GAAA,EAAY,WAAU,gDAA+C,EAAA,CACxE;AAAA,MACA,gBAAAH,EAAC,MAAA,EAAG,WAAU,8BAA6B,UAAA,uBAAmB;AAAA,MAC9D,gBAAAA,EAAC,KAAA,EAAE,WAAU,gCAA+B,UAAA,0DAAA,CAE5C;AAAA,IAAA,GACF;AAAA,IAGDrB,MAAW,WACV,gBAAAsB,EAAC,OAAA,EAAI,WAAU,eACb,UAAA;AAAA,MAAA,gBAAAD,EAAC,SAAI,WAAU,sGACb,4BAACI,GAAA,EAAQ,WAAU,4CAA2C,EAAA,CAChE;AAAA,MACA,gBAAAJ,EAAC,MAAA,EAAG,WAAU,8BAA6B,UAAA,+BAA2B;AAAA,wBACrE,OAAA,EAAI,WAAU,oDACb,UAAA,gBAAAC,EAAC,OAAA,EAAI,WAAU,0BACb,UAAA;AAAA,QAAA,gBAAAD,EAACK,GAAA,EAAY,WAAU,8DAAA,CAA8D;AAAA,QACrF,gBAAAL,EAAC,KAAA,EAAE,WAAU,0CAA0C,UAAAlB,EAAA,CAAa;AAAA,MAAA,EAAA,CACtE,EAAA,CACF;AAAA,MACA,gBAAAkB;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,SA3CM,MAAM;AACxB,YAAAvB,EAAS,QAAQ;AAAA,UACnB;AAAA,UA0Cc,WAAU;AAAA,UACX,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,IAED,EAAA,CACF;AAAA,EAAA,EAAA,CAEJ,GACF,GACF;AAEJ;"}
|
|
1
|
+
{"version":3,"file":"AuthCallbackPage-Cu74zAX1.js","sources":["../src/pages/auth/AuthCallbackPage.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\r\nimport { useSearchParams, useNavigate } from 'react-router-dom';\r\nimport { Loader2, CheckCircle, XCircle, AlertCircle } from 'lucide-react';\r\nimport { userApi } from '@/services/api/userApi';\r\nimport { getClientIpAddress } from '@/utils/ipDetection';\r\nimport { detectDeviceType } from '@/utils/deviceDetection';\r\n\r\ntype CallbackStatus = 'processing' | 'success' | 'error';\r\n\r\nconst errorMessages: Record<string, string> = {\r\n auth_failed: 'L\\'authentification a échoué. Veuillez réessayer.',\r\n no_email: 'Impossible de récupérer votre adresse email depuis le fournisseur.',\r\n account_disabled: 'Votre compte est désactivé. Contactez l\\'administrateur.',\r\n account_locked: 'Votre compte est verrouillé. Contactez l\\'administrateur.',\r\n internal_error: 'Une erreur interne est survenue. Veuillez réessayer.',\r\n};\r\n\r\nexport function AuthCallbackPage() {\r\n const [searchParams] = useSearchParams();\r\n const navigate = useNavigate();\r\n const [status, setStatus] = useState<CallbackStatus>('processing');\r\n const [errorMessage, setErrorMessage] = useState<string>('');\r\n\r\n useEffect(() => {\r\n const token = searchParams.get('token');\r\n const refreshToken = searchParams.get('refreshToken');\r\n const error = searchParams.get('error');\r\n\r\n if (error) {\r\n setStatus('error');\r\n setErrorMessage(errorMessages[error] || 'Une erreur est survenue lors de l\\'authentification.');\r\n return;\r\n }\r\n\r\n if (token && refreshToken) {\r\n handleSuccessfulAuth(token, refreshToken);\r\n } else {\r\n setStatus('error');\r\n setErrorMessage('Paramètres d\\'authentification manquants.');\r\n }\r\n }, [searchParams]);\r\n\r\n const handleSuccessfulAuth = async (token: string, refreshToken: string) => {\r\n try {\r\n localStorage.setItem('token', token);\r\n localStorage.setItem('refreshToken', refreshToken);\r\n\r\n // Update session with client-side IP address (retrieved via external service like ipify.org)\r\n // This is important for OAuth flows where the server can't reliably get the client IP\r\n try {\r\n const clientIp = await getClientIpAddress();\r\n const deviceType = detectDeviceType();\r\n\r\n if (clientIp || deviceType) {\r\n await fetch(`/api/auth/update-session-client-info`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n Authorization: `Bearer ${token}`,\r\n },\r\n body: JSON.stringify({ clientIp, deviceType }),\r\n });\r\n }\r\n } catch (ipError) {\r\n // Non-critical - continue with the flow even if IP update fails\r\n }\r\n\r\n // Fetch user info\r\n const userResponse = await fetch(`/api/auth/me`, {\r\n headers: {\r\n Authorization: `Bearer ${token}`,\r\n },\r\n });\r\n\r\n if (!userResponse.ok) {\r\n throw new Error('Failed to fetch user info');\r\n }\r\n\r\n const user = await userResponse.json();\r\n localStorage.setItem('user', JSON.stringify(user));\r\n\r\n // Check if user needs onboarding\r\n try {\r\n const onboardingResponse = await fetch(`/api/onboarding/status`, {\r\n headers: {\r\n Authorization: `Bearer ${token}`,\r\n },\r\n });\r\n\r\n if (onboardingResponse.ok) {\r\n const onboardingData = await onboardingResponse.json();\r\n if (!onboardingData.hasCompletedOnboarding) {\r\n // Redirect to onboarding wizard\r\n setStatus('success');\r\n setTimeout(() => {\r\n window.location.href = '/auth/onboarding';\r\n }, 1500);\r\n return;\r\n }\r\n }\r\n } catch {\r\n // Non-critical - continue with normal flow\r\n }\r\n\r\n // Fetch user preferences\r\n try {\r\n const prefs = await userApi.preferences.get();\r\n const themeConfig = {\r\n mode: prefs.theme || 'dark',\r\n accentColorKey: prefs.accentColorKey || 'indigo',\r\n borderRadius: prefs.borderRadius || {},\r\n itemPaletteKey: prefs.itemPaletteKey || 'neutral',\r\n };\r\n localStorage.setItem('smartstack-theme-config', JSON.stringify(themeConfig));\r\n if (prefs.language) {\r\n localStorage.setItem('i18nextLng', prefs.language);\r\n }\r\n } catch {\r\n // Non-critical - continue with defaults\r\n }\r\n\r\n setStatus('success');\r\n\r\n // Clear stale tenant state so TenantContext uses the user's configured default tenant (Priority 3: isDefault)\r\n localStorage.removeItem('currentTenantId');\r\n localStorage.removeItem('currentTenantSlug');\r\n localStorage.removeItem('isGlobalView');\r\n\r\n // Redirect after showing success\r\n setTimeout(() => {\r\n window.location.href = '/myspace';\r\n }, 1500);\r\n } catch (err) {\r\n console.error('Auth callback error:', err);\r\n setStatus('error');\r\n setErrorMessage('Erreur lors de la finalisation de l\\'authentification.');\r\n }\r\n };\r\n\r\n const handleRetry = () => {\r\n navigate('/login');\r\n };\r\n\r\n return (\r\n <div className=\"min-h-screen flex items-center justify-center bg-[var(--bg-primary)]\">\r\n <div className=\"max-w-md w-full mx-4\">\r\n <div className=\"bg-[var(--bg-secondary)] rounded-2xl p-8 shadow-lg border border-[var(--border-color)]\">\r\n {status === 'processing' && (\r\n <div className=\"text-center\">\r\n <Loader2 className=\"w-16 h-16 mx-auto text-[var(--color-accent-500)] animate-spin mb-4\" />\r\n <h2 className=\"text-xl font-semibold mb-2\">Authentification en cours...</h2>\r\n <p className=\"text-[var(--text-secondary)]\">\r\n Veuillez patienter pendant que nous finalisons votre connexion.\r\n </p>\r\n </div>\r\n )}\r\n\r\n {status === 'success' && (\r\n <div className=\"text-center\">\r\n <div className=\"w-16 h-16 mx-auto bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center mb-4\">\r\n <CheckCircle className=\"w-10 h-10 text-green-600 dark:text-green-400\" />\r\n </div>\r\n <h2 className=\"text-xl font-semibold mb-2\">Connexion réussie !</h2>\r\n <p className=\"text-[var(--text-secondary)]\">\r\n Vous allez être redirigé vers votre espace personnel...\r\n </p>\r\n </div>\r\n )}\r\n\r\n {status === 'error' && (\r\n <div className=\"text-center\">\r\n <div className=\"w-16 h-16 mx-auto bg-red-100 dark:bg-red-900/30 rounded-full flex items-center justify-center mb-4\">\r\n <XCircle className=\"w-10 h-10 text-red-600 dark:text-red-400\" />\r\n </div>\r\n <h2 className=\"text-xl font-semibold mb-2\">Échec de l'authentification</h2>\r\n <div className=\"bg-red-50 dark:bg-red-900/20 rounded-lg p-4 mb-6\">\r\n <div className=\"flex items-start gap-3\">\r\n <AlertCircle className=\"w-5 h-5 text-red-600 dark:text-red-400 flex-shrink-0 mt-0.5\" />\r\n <p className=\"text-sm text-red-700 dark:text-red-300\">{errorMessage}</p>\r\n </div>\r\n </div>\r\n <button\r\n onClick={handleRetry}\r\n className=\"btn btn-primary w-full\"\r\n >\r\n Retourner à la connexion\r\n </button>\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"names":["errorMessages","AuthCallbackPage","searchParams","useSearchParams","navigate","useNavigate","status","setStatus","useState","errorMessage","setErrorMessage","useEffect","token","refreshToken","error","handleSuccessfulAuth","clientIp","getClientIpAddress","deviceType","detectDeviceType","userResponse","user","onboardingResponse","prefs","userApi","themeConfig","err","jsx","jsxs","Loader2","CheckCircle","XCircle","AlertCircle"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { jsx as e, jsxs as t } from "react/jsx-runtime";
|
|
|
2
2
|
import { useState as s, useEffect as C } from "react";
|
|
3
3
|
import { useSearchParams as R, Link as m } from "react-router-dom";
|
|
4
4
|
import { Loader2 as y, CheckCircle2 as N, XCircle as j, Mail as _, RefreshCw as S } from "lucide-react";
|
|
5
|
-
import { T as L, a as v } from "./index-
|
|
5
|
+
import { T as L, a as v } from "./index-0Jhdcj59.js";
|
|
6
6
|
function I() {
|
|
7
7
|
const [k] = R(), l = k.get("token"), [r, n] = s("loading"), [u, o] = s(""), [g, w] = s(""), [d, E] = s(""), [x, h] = s(!1), [f, c] = s("");
|
|
8
8
|
return C(() => {
|
|
@@ -112,4 +112,4 @@ function I() {
|
|
|
112
112
|
export {
|
|
113
113
|
I as ConfirmEmailPage
|
|
114
114
|
};
|
|
115
|
-
//# sourceMappingURL=ConfirmEmailPage-
|
|
115
|
+
//# sourceMappingURL=ConfirmEmailPage-BTp8J0pw.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConfirmEmailPage-Cui47UrD.js","sources":["../src/pages/auth/ConfirmEmailPage.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\r\nimport { useSearchParams, Link } from 'react-router-dom';\r\nimport { CheckCircle2, XCircle, Loader2, Mail, RefreshCw } from 'lucide-react';\r\nimport { ThemeSwitcher } from '@/components/ui/ThemeSwitcher';\r\nimport { authApi } from '@/services/api/authApi';\r\n\r\ntype Status = 'loading' | 'success' | 'error' | 'expired' | 'already_used';\r\n\r\nexport function ConfirmEmailPage() {\r\n const [searchParams] = useSearchParams();\r\n const token = searchParams.get('token');\r\n\r\n const [status, setStatus] = useState<Status>('loading');\r\n const [message, setMessage] = useState('');\r\n const [email, setEmail] = useState('');\r\n const [resendEmail, setResendEmail] = useState('');\r\n const [isResending, setIsResending] = useState(false);\r\n const [resendMessage, setResendMessage] = useState('');\r\n\r\n useEffect(() => {\r\n if (!token) {\r\n setStatus('error');\r\n setMessage('Lien de confirmation invalide. Aucun token fourni.');\r\n return;\r\n }\r\n\r\n const confirmEmail = async () => {\r\n try {\r\n const response = await authApi.confirmEmail(token);\r\n setStatus('success');\r\n setMessage(response.message);\r\n setEmail(response.email);\r\n } catch (err) {\r\n const error = err as { message?: string; code?: string };\r\n const code = (err as { code?: string })?.code;\r\n\r\n if (code === 'TOKEN_EXPIRED') {\r\n setStatus('expired');\r\n } else if (code === 'TOKEN_ALREADY_USED') {\r\n setStatus('already_used');\r\n } else {\r\n setStatus('error');\r\n }\r\n setMessage(error?.message || 'Une erreur est survenue lors de la confirmation.');\r\n }\r\n };\r\n\r\n confirmEmail();\r\n }, [token]);\r\n\r\n const handleResendConfirmation = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (!resendEmail) return;\r\n\r\n setIsResending(true);\r\n setResendMessage('');\r\n\r\n try {\r\n const response = await authApi.resendConfirmation(resendEmail);\r\n setResendMessage(response.message);\r\n } catch (err) {\r\n const error = err as { message?: string };\r\n setResendMessage(error?.message || 'Erreur lors de l\\'envoi.');\r\n } finally {\r\n setIsResending(false);\r\n }\r\n };\r\n\r\n return (\r\n <div className=\"min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-900 p-8\">\r\n <div className=\"w-full max-w-md\">\r\n <div className=\"flex justify-end mb-8\">\r\n <ThemeSwitcher />\r\n </div>\r\n\r\n <div className=\"bg-white dark:bg-gray-800 rounded-2xl shadow-xl p-8\">\r\n {/* Loading State */}\r\n {status === 'loading' && (\r\n <div className=\"text-center\">\r\n <Loader2 className=\"w-16 h-16 text-blue-500 animate-spin mx-auto mb-4\" />\r\n <h2 className=\"text-xl font-semibold text-gray-900 dark:text-white mb-2\">\r\n Confirmation en cours...\r\n </h2>\r\n <p className=\"text-gray-600 dark:text-gray-400\">\r\n Veuillez patienter pendant que nous vérifions votre email.\r\n </p>\r\n </div>\r\n )}\r\n\r\n {/* Success State */}\r\n {status === 'success' && (\r\n <div className=\"text-center\">\r\n <div className=\"w-16 h-16 bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center mx-auto mb-4\">\r\n <CheckCircle2 className=\"w-10 h-10 text-green-600 dark:text-green-400\" />\r\n </div>\r\n <h2 className=\"text-xl font-semibold text-gray-900 dark:text-white mb-2\">\r\n Email confirmé !\r\n </h2>\r\n <p className=\"text-gray-600 dark:text-gray-400 mb-6\">\r\n {message}\r\n </p>\r\n {email && (\r\n <p className=\"text-sm text-gray-500 dark:text-gray-400 mb-6\">\r\n Compte : <strong>{email}</strong>\r\n </p>\r\n )}\r\n <Link\r\n to=\"/login\"\r\n className=\"inline-flex items-center justify-center gap-2 px-6 py-3 bg-gradient-to-r from-blue-600 to-purple-600 text-white rounded-lg font-medium hover:from-blue-700 hover:to-purple-700 transition-all\"\r\n >\r\n Se connecter\r\n </Link>\r\n </div>\r\n )}\r\n\r\n {/* Error / Expired / Already Used States */}\r\n {(status === 'error' || status === 'expired' || status === 'already_used') && (\r\n <div className=\"text-center\">\r\n <div className={`w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-4 ${\r\n status === 'already_used'\r\n ? 'bg-amber-100 dark:bg-amber-900/30'\r\n : 'bg-red-100 dark:bg-red-900/30'\r\n }`}>\r\n {status === 'already_used' ? (\r\n <CheckCircle2 className=\"w-10 h-10 text-amber-600 dark:text-amber-400\" />\r\n ) : (\r\n <XCircle className=\"w-10 h-10 text-red-600 dark:text-red-400\" />\r\n )}\r\n </div>\r\n <h2 className=\"text-xl font-semibold text-gray-900 dark:text-white mb-2\">\r\n {status === 'expired' && 'Lien expiré'}\r\n {status === 'already_used' && 'Lien déjà utilisé'}\r\n {status === 'error' && 'Erreur de confirmation'}\r\n </h2>\r\n <p className=\"text-gray-600 dark:text-gray-400 mb-6\">\r\n {message}\r\n </p>\r\n\r\n {/* Resend Form */}\r\n {(status === 'expired' || status === 'error') && (\r\n <div className=\"border-t border-gray-200 dark:border-gray-700 pt-6 mt-6\">\r\n <p className=\"text-sm text-gray-600 dark:text-gray-400 mb-4\">\r\n Demander un nouveau lien de confirmation :\r\n </p>\r\n <form onSubmit={handleResendConfirmation} className=\"space-y-3\">\r\n <div className=\"relative\">\r\n <div className=\"absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none\">\r\n <Mail className=\"h-5 w-5 text-gray-400\" />\r\n </div>\r\n <input\r\n type=\"email\"\r\n value={resendEmail}\r\n onChange={(e) => setResendEmail(e.target.value)}\r\n placeholder=\"Votre email\"\r\n className=\"block w-full pl-10 pr-3 py-2.5 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-400 focus:ring-2 focus:ring-blue-500 focus:border-transparent\"\r\n required\r\n />\r\n </div>\r\n <button\r\n type=\"submit\"\r\n disabled={isResending}\r\n className=\"w-full flex items-center justify-center gap-2 px-4 py-2.5 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 disabled:opacity-50 transition-colors\"\r\n >\r\n {isResending ? (\r\n <Loader2 className=\"w-5 h-5 animate-spin\" />\r\n ) : (\r\n <RefreshCw className=\"w-5 h-5\" />\r\n )}\r\n Renvoyer le lien\r\n </button>\r\n </form>\r\n {resendMessage && (\r\n <p className=\"mt-3 text-sm text-green-600 dark:text-green-400\">\r\n {resendMessage}\r\n </p>\r\n )}\r\n </div>\r\n )}\r\n\r\n {status === 'already_used' && (\r\n <Link\r\n to=\"/login\"\r\n className=\"inline-flex items-center justify-center gap-2 px-6 py-3 bg-gradient-to-r from-blue-600 to-purple-600 text-white rounded-lg font-medium hover:from-blue-700 hover:to-purple-700 transition-all\"\r\n >\r\n Se connecter\r\n </Link>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n\r\n <p className=\"text-center text-sm text-gray-500 dark:text-gray-400 mt-6\">\r\n <Link to=\"/login\" className=\"hover:underline\">\r\n Retour à la connexion\r\n </Link>\r\n </p>\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"names":["ConfirmEmailPage","searchParams","useSearchParams","token","status","setStatus","useState","message","setMessage","email","setEmail","resendEmail","setResendEmail","isResending","setIsResending","resendMessage","setResendMessage","useEffect","response","authApi","err","error","code","jsxs","jsx","ThemeSwitcher","Loader2","CheckCircle2","Link","XCircle","e","Mail","RefreshCw"],"mappings":";;;;;AAQO,SAASA,IAAmB;AACjC,QAAM,CAACC,CAAY,IAAIC,EAAA,GACjBC,IAAQF,EAAa,IAAI,OAAO,GAEhC,CAACG,GAAQC,CAAS,IAAIC,EAAiB,SAAS,GAChD,CAACC,GAASC,CAAU,IAAIF,EAAS,EAAE,GACnC,CAACG,GAAOC,CAAQ,IAAIJ,EAAS,EAAE,GAC/B,CAACK,GAAaC,CAAc,IAAIN,EAAS,EAAE,GAC3C,CAACO,GAAaC,CAAc,IAAIR,EAAS,EAAK,GAC9C,CAACS,GAAeC,CAAgB,IAAIV,EAAS,EAAE;AAErD,SAAAW,EAAU,MAAM;AACd,QAAI,CAACd,GAAO;AACV,MAAAE,EAAU,OAAO,GACjBG,EAAW,oDAAoD;AAC/D;AAAA,IACF;AAuBA,KArBqB,YAAY;AAC/B,UAAI;AACF,cAAMU,IAAW,MAAMC,EAAQ,aAAahB,CAAK;AACjD,QAAAE,EAAU,SAAS,GACnBG,EAAWU,EAAS,OAAO,GAC3BR,EAASQ,EAAS,KAAK;AAAA,MACzB,SAASE,GAAK;AACZ,cAAMC,IAAQD,GACRE,IAAQF,GAA2B;AAEzC,QACEf,EADEiB,MAAS,kBACD,YACDA,MAAS,uBACR,iBAEA,OAJS,GAMrBd,EAAWa,GAAO,WAAW,kDAAkD;AAAA,MACjF;AAAA,IACF,GAEA;AAAA,EACF,GAAG,CAAClB,CAAK,CAAC,qBAqBP,OAAA,EAAI,WAAU,iFACb,UAAA,gBAAAoB,EAAC,OAAA,EAAI,WAAU,mBACb,UAAA;AAAA,IAAA,gBAAAC,EAAC,OAAA,EAAI,WAAU,yBACb,UAAA,gBAAAA,EAACC,KAAc,GACjB;AAAA,IAEA,gBAAAF,EAAC,OAAA,EAAI,WAAU,uDAEZ,UAAA;AAAA,MAAAnB,MAAW,aACV,gBAAAmB,EAAC,OAAA,EAAI,WAAU,eACb,UAAA;AAAA,QAAA,gBAAAC,EAACE,GAAA,EAAQ,WAAU,oDAAA,CAAoD;AAAA,QACvE,gBAAAF,EAAC,MAAA,EAAG,WAAU,4DAA2D,UAAA,4BAEzE;AAAA,QACA,gBAAAA,EAAC,KAAA,EAAE,WAAU,oCAAmC,UAAA,6DAAA,CAEhD;AAAA,MAAA,GACF;AAAA,MAIDpB,MAAW,aACV,gBAAAmB,EAAC,OAAA,EAAI,WAAU,eACb,UAAA;AAAA,QAAA,gBAAAC,EAAC,SAAI,WAAU,0GACb,4BAACG,GAAA,EAAa,WAAU,gDAA+C,EAAA,CACzE;AAAA,QACA,gBAAAH,EAAC,MAAA,EAAG,WAAU,4DAA2D,UAAA,oBAEzE;AAAA,QACA,gBAAAA,EAAC,KAAA,EAAE,WAAU,yCACV,UAAAjB,GACH;AAAA,QACCE,KACC,gBAAAc,EAAC,KAAA,EAAE,WAAU,iDAAgD,UAAA;AAAA,UAAA;AAAA,UAClD,gBAAAC,EAAC,YAAQ,UAAAf,EAAA,CAAM;AAAA,QAAA,GAC1B;AAAA,QAEF,gBAAAe;AAAA,UAACI;AAAA,UAAA;AAAA,YACC,IAAG;AAAA,YACH,WAAU;AAAA,YACX,UAAA;AAAA,UAAA;AAAA,QAAA;AAAA,MAED,GACF;AAAA,OAIAxB,MAAW,WAAWA,MAAW,aAAaA,MAAW,mBACzD,gBAAAmB,EAAC,OAAA,EAAI,WAAU,eACb,UAAA;AAAA,QAAA,gBAAAC,EAAC,SAAI,WAAW,wEACdpB,MAAW,iBACP,sCACA,+BACN,IACG,UAAAA,MAAW,iBACV,gBAAAoB,EAACG,GAAA,EAAa,WAAU,+CAAA,CAA+C,sBAEtEE,GAAA,EAAQ,WAAU,4CAA2C,EAAA,CAElE;AAAA,QACA,gBAAAN,EAAC,MAAA,EAAG,WAAU,4DACX,UAAA;AAAA,UAAAnB,MAAW,aAAa;AAAA,UACxBA,MAAW,kBAAkB;AAAA,UAC7BA,MAAW,WAAW;AAAA,QAAA,GACzB;AAAA,QACA,gBAAAoB,EAAC,KAAA,EAAE,WAAU,yCACV,UAAAjB,GACH;AAAA,SAGEH,MAAW,aAAaA,MAAW,YACnC,gBAAAmB,EAAC,OAAA,EAAI,WAAU,2DACb,UAAA;AAAA,UAAA,gBAAAC,EAAC,KAAA,EAAE,WAAU,iDAAgD,UAAA,8CAE7D;AAAA,UACA,gBAAAD,EAAC,QAAA,EAAK,UA9FW,OAAOO,MAAuB;AAE7D,gBADAA,EAAE,eAAA,GACE,EAACnB,GAEL;AAAA,cAAAG,EAAe,EAAI,GACnBE,EAAiB,EAAE;AAEnB,kBAAI;AACF,sBAAME,IAAW,MAAMC,EAAQ,mBAAmBR,CAAW;AAC7D,gBAAAK,EAAiBE,EAAS,OAAO;AAAA,cACnC,SAASE,GAAK;AAEZ,gBAAAJ,EADcI,GACU,WAAW,yBAA0B;AAAA,cAC/D,UAAA;AACE,gBAAAN,EAAe,EAAK;AAAA,cACtB;AAAA;AAAA,UACF,GA8E0D,WAAU,aAClD,UAAA;AAAA,YAAA,gBAAAS,EAAC,OAAA,EAAI,WAAU,YACb,UAAA;AAAA,cAAA,gBAAAC,EAAC,SAAI,WAAU,wEACb,4BAACO,GAAA,EAAK,WAAU,yBAAwB,EAAA,CAC1C;AAAA,cACA,gBAAAP;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,MAAK;AAAA,kBACL,OAAOb;AAAA,kBACP,UAAU,CAACmB,MAAMlB,EAAekB,EAAE,OAAO,KAAK;AAAA,kBAC9C,aAAY;AAAA,kBACZ,WAAU;AAAA,kBACV,UAAQ;AAAA,gBAAA;AAAA,cAAA;AAAA,YACV,GACF;AAAA,YACA,gBAAAP;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,MAAK;AAAA,gBACL,UAAUV;AAAA,gBACV,WAAU;AAAA,gBAET,UAAA;AAAA,kBAAAA,IACC,gBAAAW,EAACE,KAAQ,WAAU,uBAAA,CAAuB,IAE1C,gBAAAF,EAACQ,GAAA,EAAU,WAAU,UAAA,CAAU;AAAA,kBAC/B;AAAA,gBAAA;AAAA,cAAA;AAAA,YAAA;AAAA,UAEJ,GACF;AAAA,UACCjB,KACC,gBAAAS,EAAC,KAAA,EAAE,WAAU,mDACV,UAAAT,EAAA,CACH;AAAA,QAAA,GAEJ;AAAA,QAGDX,MAAW,kBACV,gBAAAoB;AAAA,UAACI;AAAA,UAAA;AAAA,YACC,IAAG;AAAA,YACH,WAAU;AAAA,YACX,UAAA;AAAA,UAAA;AAAA,QAAA;AAAA,MAED,EAAA,CAEJ;AAAA,IAAA,GAEJ;AAAA,IAEA,gBAAAJ,EAAC,KAAA,EAAE,WAAU,6DACX,UAAA,gBAAAA,EAACI,GAAA,EAAK,IAAG,UAAS,WAAU,mBAAkB,UAAA,wBAAA,CAE9C,EAAA,CACF;AAAA,EAAA,EAAA,CACF,EAAA,CACF;AAEJ;"}
|
|
1
|
+
{"version":3,"file":"ConfirmEmailPage-BTp8J0pw.js","sources":["../src/pages/auth/ConfirmEmailPage.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\r\nimport { useSearchParams, Link } from 'react-router-dom';\r\nimport { CheckCircle2, XCircle, Loader2, Mail, RefreshCw } from 'lucide-react';\r\nimport { ThemeSwitcher } from '@/components/ui/ThemeSwitcher';\r\nimport { authApi } from '@/services/api/authApi';\r\n\r\ntype Status = 'loading' | 'success' | 'error' | 'expired' | 'already_used';\r\n\r\nexport function ConfirmEmailPage() {\r\n const [searchParams] = useSearchParams();\r\n const token = searchParams.get('token');\r\n\r\n const [status, setStatus] = useState<Status>('loading');\r\n const [message, setMessage] = useState('');\r\n const [email, setEmail] = useState('');\r\n const [resendEmail, setResendEmail] = useState('');\r\n const [isResending, setIsResending] = useState(false);\r\n const [resendMessage, setResendMessage] = useState('');\r\n\r\n useEffect(() => {\r\n if (!token) {\r\n setStatus('error');\r\n setMessage('Lien de confirmation invalide. Aucun token fourni.');\r\n return;\r\n }\r\n\r\n const confirmEmail = async () => {\r\n try {\r\n const response = await authApi.confirmEmail(token);\r\n setStatus('success');\r\n setMessage(response.message);\r\n setEmail(response.email);\r\n } catch (err) {\r\n const error = err as { message?: string; code?: string };\r\n const code = (err as { code?: string })?.code;\r\n\r\n if (code === 'TOKEN_EXPIRED') {\r\n setStatus('expired');\r\n } else if (code === 'TOKEN_ALREADY_USED') {\r\n setStatus('already_used');\r\n } else {\r\n setStatus('error');\r\n }\r\n setMessage(error?.message || 'Une erreur est survenue lors de la confirmation.');\r\n }\r\n };\r\n\r\n confirmEmail();\r\n }, [token]);\r\n\r\n const handleResendConfirmation = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (!resendEmail) return;\r\n\r\n setIsResending(true);\r\n setResendMessage('');\r\n\r\n try {\r\n const response = await authApi.resendConfirmation(resendEmail);\r\n setResendMessage(response.message);\r\n } catch (err) {\r\n const error = err as { message?: string };\r\n setResendMessage(error?.message || 'Erreur lors de l\\'envoi.');\r\n } finally {\r\n setIsResending(false);\r\n }\r\n };\r\n\r\n return (\r\n <div className=\"min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-900 p-8\">\r\n <div className=\"w-full max-w-md\">\r\n <div className=\"flex justify-end mb-8\">\r\n <ThemeSwitcher />\r\n </div>\r\n\r\n <div className=\"bg-white dark:bg-gray-800 rounded-2xl shadow-xl p-8\">\r\n {/* Loading State */}\r\n {status === 'loading' && (\r\n <div className=\"text-center\">\r\n <Loader2 className=\"w-16 h-16 text-blue-500 animate-spin mx-auto mb-4\" />\r\n <h2 className=\"text-xl font-semibold text-gray-900 dark:text-white mb-2\">\r\n Confirmation en cours...\r\n </h2>\r\n <p className=\"text-gray-600 dark:text-gray-400\">\r\n Veuillez patienter pendant que nous vérifions votre email.\r\n </p>\r\n </div>\r\n )}\r\n\r\n {/* Success State */}\r\n {status === 'success' && (\r\n <div className=\"text-center\">\r\n <div className=\"w-16 h-16 bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center mx-auto mb-4\">\r\n <CheckCircle2 className=\"w-10 h-10 text-green-600 dark:text-green-400\" />\r\n </div>\r\n <h2 className=\"text-xl font-semibold text-gray-900 dark:text-white mb-2\">\r\n Email confirmé !\r\n </h2>\r\n <p className=\"text-gray-600 dark:text-gray-400 mb-6\">\r\n {message}\r\n </p>\r\n {email && (\r\n <p className=\"text-sm text-gray-500 dark:text-gray-400 mb-6\">\r\n Compte : <strong>{email}</strong>\r\n </p>\r\n )}\r\n <Link\r\n to=\"/login\"\r\n className=\"inline-flex items-center justify-center gap-2 px-6 py-3 bg-gradient-to-r from-blue-600 to-purple-600 text-white rounded-lg font-medium hover:from-blue-700 hover:to-purple-700 transition-all\"\r\n >\r\n Se connecter\r\n </Link>\r\n </div>\r\n )}\r\n\r\n {/* Error / Expired / Already Used States */}\r\n {(status === 'error' || status === 'expired' || status === 'already_used') && (\r\n <div className=\"text-center\">\r\n <div className={`w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-4 ${\r\n status === 'already_used'\r\n ? 'bg-amber-100 dark:bg-amber-900/30'\r\n : 'bg-red-100 dark:bg-red-900/30'\r\n }`}>\r\n {status === 'already_used' ? (\r\n <CheckCircle2 className=\"w-10 h-10 text-amber-600 dark:text-amber-400\" />\r\n ) : (\r\n <XCircle className=\"w-10 h-10 text-red-600 dark:text-red-400\" />\r\n )}\r\n </div>\r\n <h2 className=\"text-xl font-semibold text-gray-900 dark:text-white mb-2\">\r\n {status === 'expired' && 'Lien expiré'}\r\n {status === 'already_used' && 'Lien déjà utilisé'}\r\n {status === 'error' && 'Erreur de confirmation'}\r\n </h2>\r\n <p className=\"text-gray-600 dark:text-gray-400 mb-6\">\r\n {message}\r\n </p>\r\n\r\n {/* Resend Form */}\r\n {(status === 'expired' || status === 'error') && (\r\n <div className=\"border-t border-gray-200 dark:border-gray-700 pt-6 mt-6\">\r\n <p className=\"text-sm text-gray-600 dark:text-gray-400 mb-4\">\r\n Demander un nouveau lien de confirmation :\r\n </p>\r\n <form onSubmit={handleResendConfirmation} className=\"space-y-3\">\r\n <div className=\"relative\">\r\n <div className=\"absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none\">\r\n <Mail className=\"h-5 w-5 text-gray-400\" />\r\n </div>\r\n <input\r\n type=\"email\"\r\n value={resendEmail}\r\n onChange={(e) => setResendEmail(e.target.value)}\r\n placeholder=\"Votre email\"\r\n className=\"block w-full pl-10 pr-3 py-2.5 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-400 focus:ring-2 focus:ring-blue-500 focus:border-transparent\"\r\n required\r\n />\r\n </div>\r\n <button\r\n type=\"submit\"\r\n disabled={isResending}\r\n className=\"w-full flex items-center justify-center gap-2 px-4 py-2.5 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 disabled:opacity-50 transition-colors\"\r\n >\r\n {isResending ? (\r\n <Loader2 className=\"w-5 h-5 animate-spin\" />\r\n ) : (\r\n <RefreshCw className=\"w-5 h-5\" />\r\n )}\r\n Renvoyer le lien\r\n </button>\r\n </form>\r\n {resendMessage && (\r\n <p className=\"mt-3 text-sm text-green-600 dark:text-green-400\">\r\n {resendMessage}\r\n </p>\r\n )}\r\n </div>\r\n )}\r\n\r\n {status === 'already_used' && (\r\n <Link\r\n to=\"/login\"\r\n className=\"inline-flex items-center justify-center gap-2 px-6 py-3 bg-gradient-to-r from-blue-600 to-purple-600 text-white rounded-lg font-medium hover:from-blue-700 hover:to-purple-700 transition-all\"\r\n >\r\n Se connecter\r\n </Link>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n\r\n <p className=\"text-center text-sm text-gray-500 dark:text-gray-400 mt-6\">\r\n <Link to=\"/login\" className=\"hover:underline\">\r\n Retour à la connexion\r\n </Link>\r\n </p>\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"names":["ConfirmEmailPage","searchParams","useSearchParams","token","status","setStatus","useState","message","setMessage","email","setEmail","resendEmail","setResendEmail","isResending","setIsResending","resendMessage","setResendMessage","useEffect","response","authApi","err","error","code","jsxs","jsx","ThemeSwitcher","Loader2","CheckCircle2","Link","XCircle","e","Mail","RefreshCw"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),s=require("react"),l=require("react-router-dom"),a=require("lucide-react"),x=require("./index-
|
|
2
|
-
//# sourceMappingURL=ConfirmEmailPage-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),s=require("react"),l=require("react-router-dom"),a=require("lucide-react"),x=require("./index-C6C5XmVj.cjs");function w(){const[j]=l.useSearchParams(),c=j.get("token"),[r,n]=s.useState("loading"),[u,o]=s.useState(""),[g,N]=s.useState(""),[d,k]=s.useState(""),[h,f]=s.useState(!1),[b,m]=s.useState("");s.useEffect(()=>{if(!c){n("error"),o("Lien de confirmation invalide. Aucun token fourni.");return}(async()=>{try{const t=await x.authApi.confirmEmail(c);n("success"),o(t.message),N(t.email)}catch(t){const p=t,y=t?.code;n(y==="TOKEN_EXPIRED"?"expired":y==="TOKEN_ALREADY_USED"?"already_used":"error"),o(p?.message||"Une erreur est survenue lors de la confirmation.")}})()},[c]);const v=async i=>{if(i.preventDefault(),!!d){f(!0),m("");try{const t=await x.authApi.resendConfirmation(d);m(t.message)}catch(t){m(t?.message||"Erreur lors de l'envoi.")}finally{f(!1)}}};return e.jsx("div",{className:"min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-900 p-8",children:e.jsxs("div",{className:"w-full max-w-md",children:[e.jsx("div",{className:"flex justify-end mb-8",children:e.jsx(x.ThemeSwitcher,{})}),e.jsxs("div",{className:"bg-white dark:bg-gray-800 rounded-2xl shadow-xl p-8",children:[r==="loading"&&e.jsxs("div",{className:"text-center",children:[e.jsx(a.Loader2,{className:"w-16 h-16 text-blue-500 animate-spin mx-auto mb-4"}),e.jsx("h2",{className:"text-xl font-semibold text-gray-900 dark:text-white mb-2",children:"Confirmation en cours..."}),e.jsx("p",{className:"text-gray-600 dark:text-gray-400",children:"Veuillez patienter pendant que nous vérifions votre email."})]}),r==="success"&&e.jsxs("div",{className:"text-center",children:[e.jsx("div",{className:"w-16 h-16 bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center mx-auto mb-4",children:e.jsx(a.CheckCircle2,{className:"w-10 h-10 text-green-600 dark:text-green-400"})}),e.jsx("h2",{className:"text-xl font-semibold text-gray-900 dark:text-white mb-2",children:"Email confirmé !"}),e.jsx("p",{className:"text-gray-600 dark:text-gray-400 mb-6",children:u}),g&&e.jsxs("p",{className:"text-sm text-gray-500 dark:text-gray-400 mb-6",children:["Compte : ",e.jsx("strong",{children:g})]}),e.jsx(l.Link,{to:"/login",className:"inline-flex items-center justify-center gap-2 px-6 py-3 bg-gradient-to-r from-blue-600 to-purple-600 text-white rounded-lg font-medium hover:from-blue-700 hover:to-purple-700 transition-all",children:"Se connecter"})]}),(r==="error"||r==="expired"||r==="already_used")&&e.jsxs("div",{className:"text-center",children:[e.jsx("div",{className:`w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-4 ${r==="already_used"?"bg-amber-100 dark:bg-amber-900/30":"bg-red-100 dark:bg-red-900/30"}`,children:r==="already_used"?e.jsx(a.CheckCircle2,{className:"w-10 h-10 text-amber-600 dark:text-amber-400"}):e.jsx(a.XCircle,{className:"w-10 h-10 text-red-600 dark:text-red-400"})}),e.jsxs("h2",{className:"text-xl font-semibold text-gray-900 dark:text-white mb-2",children:[r==="expired"&&"Lien expiré",r==="already_used"&&"Lien déjà utilisé",r==="error"&&"Erreur de confirmation"]}),e.jsx("p",{className:"text-gray-600 dark:text-gray-400 mb-6",children:u}),(r==="expired"||r==="error")&&e.jsxs("div",{className:"border-t border-gray-200 dark:border-gray-700 pt-6 mt-6",children:[e.jsx("p",{className:"text-sm text-gray-600 dark:text-gray-400 mb-4",children:"Demander un nouveau lien de confirmation :"}),e.jsxs("form",{onSubmit:v,className:"space-y-3",children:[e.jsxs("div",{className:"relative",children:[e.jsx("div",{className:"absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none",children:e.jsx(a.Mail,{className:"h-5 w-5 text-gray-400"})}),e.jsx("input",{type:"email",value:d,onChange:i=>k(i.target.value),placeholder:"Votre email",className:"block w-full pl-10 pr-3 py-2.5 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-400 focus:ring-2 focus:ring-blue-500 focus:border-transparent",required:!0})]}),e.jsxs("button",{type:"submit",disabled:h,className:"w-full flex items-center justify-center gap-2 px-4 py-2.5 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 disabled:opacity-50 transition-colors",children:[h?e.jsx(a.Loader2,{className:"w-5 h-5 animate-spin"}):e.jsx(a.RefreshCw,{className:"w-5 h-5"}),"Renvoyer le lien"]})]}),b&&e.jsx("p",{className:"mt-3 text-sm text-green-600 dark:text-green-400",children:b})]}),r==="already_used"&&e.jsx(l.Link,{to:"/login",className:"inline-flex items-center justify-center gap-2 px-6 py-3 bg-gradient-to-r from-blue-600 to-purple-600 text-white rounded-lg font-medium hover:from-blue-700 hover:to-purple-700 transition-all",children:"Se connecter"})]})]}),e.jsx("p",{className:"text-center text-sm text-gray-500 dark:text-gray-400 mt-6",children:e.jsx(l.Link,{to:"/login",className:"hover:underline",children:"Retour à la connexion"})})]})})}exports.ConfirmEmailPage=w;
|
|
2
|
+
//# sourceMappingURL=ConfirmEmailPage-su3Fvl0e.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConfirmEmailPage-BkCDKBy0.cjs","sources":["../src/pages/auth/ConfirmEmailPage.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\r\nimport { useSearchParams, Link } from 'react-router-dom';\r\nimport { CheckCircle2, XCircle, Loader2, Mail, RefreshCw } from 'lucide-react';\r\nimport { ThemeSwitcher } from '@/components/ui/ThemeSwitcher';\r\nimport { authApi } from '@/services/api/authApi';\r\n\r\ntype Status = 'loading' | 'success' | 'error' | 'expired' | 'already_used';\r\n\r\nexport function ConfirmEmailPage() {\r\n const [searchParams] = useSearchParams();\r\n const token = searchParams.get('token');\r\n\r\n const [status, setStatus] = useState<Status>('loading');\r\n const [message, setMessage] = useState('');\r\n const [email, setEmail] = useState('');\r\n const [resendEmail, setResendEmail] = useState('');\r\n const [isResending, setIsResending] = useState(false);\r\n const [resendMessage, setResendMessage] = useState('');\r\n\r\n useEffect(() => {\r\n if (!token) {\r\n setStatus('error');\r\n setMessage('Lien de confirmation invalide. Aucun token fourni.');\r\n return;\r\n }\r\n\r\n const confirmEmail = async () => {\r\n try {\r\n const response = await authApi.confirmEmail(token);\r\n setStatus('success');\r\n setMessage(response.message);\r\n setEmail(response.email);\r\n } catch (err) {\r\n const error = err as { message?: string; code?: string };\r\n const code = (err as { code?: string })?.code;\r\n\r\n if (code === 'TOKEN_EXPIRED') {\r\n setStatus('expired');\r\n } else if (code === 'TOKEN_ALREADY_USED') {\r\n setStatus('already_used');\r\n } else {\r\n setStatus('error');\r\n }\r\n setMessage(error?.message || 'Une erreur est survenue lors de la confirmation.');\r\n }\r\n };\r\n\r\n confirmEmail();\r\n }, [token]);\r\n\r\n const handleResendConfirmation = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (!resendEmail) return;\r\n\r\n setIsResending(true);\r\n setResendMessage('');\r\n\r\n try {\r\n const response = await authApi.resendConfirmation(resendEmail);\r\n setResendMessage(response.message);\r\n } catch (err) {\r\n const error = err as { message?: string };\r\n setResendMessage(error?.message || 'Erreur lors de l\\'envoi.');\r\n } finally {\r\n setIsResending(false);\r\n }\r\n };\r\n\r\n return (\r\n <div className=\"min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-900 p-8\">\r\n <div className=\"w-full max-w-md\">\r\n <div className=\"flex justify-end mb-8\">\r\n <ThemeSwitcher />\r\n </div>\r\n\r\n <div className=\"bg-white dark:bg-gray-800 rounded-2xl shadow-xl p-8\">\r\n {/* Loading State */}\r\n {status === 'loading' && (\r\n <div className=\"text-center\">\r\n <Loader2 className=\"w-16 h-16 text-blue-500 animate-spin mx-auto mb-4\" />\r\n <h2 className=\"text-xl font-semibold text-gray-900 dark:text-white mb-2\">\r\n Confirmation en cours...\r\n </h2>\r\n <p className=\"text-gray-600 dark:text-gray-400\">\r\n Veuillez patienter pendant que nous vérifions votre email.\r\n </p>\r\n </div>\r\n )}\r\n\r\n {/* Success State */}\r\n {status === 'success' && (\r\n <div className=\"text-center\">\r\n <div className=\"w-16 h-16 bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center mx-auto mb-4\">\r\n <CheckCircle2 className=\"w-10 h-10 text-green-600 dark:text-green-400\" />\r\n </div>\r\n <h2 className=\"text-xl font-semibold text-gray-900 dark:text-white mb-2\">\r\n Email confirmé !\r\n </h2>\r\n <p className=\"text-gray-600 dark:text-gray-400 mb-6\">\r\n {message}\r\n </p>\r\n {email && (\r\n <p className=\"text-sm text-gray-500 dark:text-gray-400 mb-6\">\r\n Compte : <strong>{email}</strong>\r\n </p>\r\n )}\r\n <Link\r\n to=\"/login\"\r\n className=\"inline-flex items-center justify-center gap-2 px-6 py-3 bg-gradient-to-r from-blue-600 to-purple-600 text-white rounded-lg font-medium hover:from-blue-700 hover:to-purple-700 transition-all\"\r\n >\r\n Se connecter\r\n </Link>\r\n </div>\r\n )}\r\n\r\n {/* Error / Expired / Already Used States */}\r\n {(status === 'error' || status === 'expired' || status === 'already_used') && (\r\n <div className=\"text-center\">\r\n <div className={`w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-4 ${\r\n status === 'already_used'\r\n ? 'bg-amber-100 dark:bg-amber-900/30'\r\n : 'bg-red-100 dark:bg-red-900/30'\r\n }`}>\r\n {status === 'already_used' ? (\r\n <CheckCircle2 className=\"w-10 h-10 text-amber-600 dark:text-amber-400\" />\r\n ) : (\r\n <XCircle className=\"w-10 h-10 text-red-600 dark:text-red-400\" />\r\n )}\r\n </div>\r\n <h2 className=\"text-xl font-semibold text-gray-900 dark:text-white mb-2\">\r\n {status === 'expired' && 'Lien expiré'}\r\n {status === 'already_used' && 'Lien déjà utilisé'}\r\n {status === 'error' && 'Erreur de confirmation'}\r\n </h2>\r\n <p className=\"text-gray-600 dark:text-gray-400 mb-6\">\r\n {message}\r\n </p>\r\n\r\n {/* Resend Form */}\r\n {(status === 'expired' || status === 'error') && (\r\n <div className=\"border-t border-gray-200 dark:border-gray-700 pt-6 mt-6\">\r\n <p className=\"text-sm text-gray-600 dark:text-gray-400 mb-4\">\r\n Demander un nouveau lien de confirmation :\r\n </p>\r\n <form onSubmit={handleResendConfirmation} className=\"space-y-3\">\r\n <div className=\"relative\">\r\n <div className=\"absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none\">\r\n <Mail className=\"h-5 w-5 text-gray-400\" />\r\n </div>\r\n <input\r\n type=\"email\"\r\n value={resendEmail}\r\n onChange={(e) => setResendEmail(e.target.value)}\r\n placeholder=\"Votre email\"\r\n className=\"block w-full pl-10 pr-3 py-2.5 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-400 focus:ring-2 focus:ring-blue-500 focus:border-transparent\"\r\n required\r\n />\r\n </div>\r\n <button\r\n type=\"submit\"\r\n disabled={isResending}\r\n className=\"w-full flex items-center justify-center gap-2 px-4 py-2.5 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 disabled:opacity-50 transition-colors\"\r\n >\r\n {isResending ? (\r\n <Loader2 className=\"w-5 h-5 animate-spin\" />\r\n ) : (\r\n <RefreshCw className=\"w-5 h-5\" />\r\n )}\r\n Renvoyer le lien\r\n </button>\r\n </form>\r\n {resendMessage && (\r\n <p className=\"mt-3 text-sm text-green-600 dark:text-green-400\">\r\n {resendMessage}\r\n </p>\r\n )}\r\n </div>\r\n )}\r\n\r\n {status === 'already_used' && (\r\n <Link\r\n to=\"/login\"\r\n className=\"inline-flex items-center justify-center gap-2 px-6 py-3 bg-gradient-to-r from-blue-600 to-purple-600 text-white rounded-lg font-medium hover:from-blue-700 hover:to-purple-700 transition-all\"\r\n >\r\n Se connecter\r\n </Link>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n\r\n <p className=\"text-center text-sm text-gray-500 dark:text-gray-400 mt-6\">\r\n <Link to=\"/login\" className=\"hover:underline\">\r\n Retour à la connexion\r\n </Link>\r\n </p>\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"names":["ConfirmEmailPage","searchParams","useSearchParams","token","status","setStatus","useState","message","setMessage","email","setEmail","resendEmail","setResendEmail","isResending","setIsResending","resendMessage","setResendMessage","useEffect","response","authApi","err","error","code","handleResendConfirmation","e","jsxs","jsx","ThemeSwitcher","Loader2","CheckCircle2","Link","XCircle","Mail","RefreshCw"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ConfirmEmailPage-su3Fvl0e.cjs","sources":["../src/pages/auth/ConfirmEmailPage.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\r\nimport { useSearchParams, Link } from 'react-router-dom';\r\nimport { CheckCircle2, XCircle, Loader2, Mail, RefreshCw } from 'lucide-react';\r\nimport { ThemeSwitcher } from '@/components/ui/ThemeSwitcher';\r\nimport { authApi } from '@/services/api/authApi';\r\n\r\ntype Status = 'loading' | 'success' | 'error' | 'expired' | 'already_used';\r\n\r\nexport function ConfirmEmailPage() {\r\n const [searchParams] = useSearchParams();\r\n const token = searchParams.get('token');\r\n\r\n const [status, setStatus] = useState<Status>('loading');\r\n const [message, setMessage] = useState('');\r\n const [email, setEmail] = useState('');\r\n const [resendEmail, setResendEmail] = useState('');\r\n const [isResending, setIsResending] = useState(false);\r\n const [resendMessage, setResendMessage] = useState('');\r\n\r\n useEffect(() => {\r\n if (!token) {\r\n setStatus('error');\r\n setMessage('Lien de confirmation invalide. Aucun token fourni.');\r\n return;\r\n }\r\n\r\n const confirmEmail = async () => {\r\n try {\r\n const response = await authApi.confirmEmail(token);\r\n setStatus('success');\r\n setMessage(response.message);\r\n setEmail(response.email);\r\n } catch (err) {\r\n const error = err as { message?: string; code?: string };\r\n const code = (err as { code?: string })?.code;\r\n\r\n if (code === 'TOKEN_EXPIRED') {\r\n setStatus('expired');\r\n } else if (code === 'TOKEN_ALREADY_USED') {\r\n setStatus('already_used');\r\n } else {\r\n setStatus('error');\r\n }\r\n setMessage(error?.message || 'Une erreur est survenue lors de la confirmation.');\r\n }\r\n };\r\n\r\n confirmEmail();\r\n }, [token]);\r\n\r\n const handleResendConfirmation = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (!resendEmail) return;\r\n\r\n setIsResending(true);\r\n setResendMessage('');\r\n\r\n try {\r\n const response = await authApi.resendConfirmation(resendEmail);\r\n setResendMessage(response.message);\r\n } catch (err) {\r\n const error = err as { message?: string };\r\n setResendMessage(error?.message || 'Erreur lors de l\\'envoi.');\r\n } finally {\r\n setIsResending(false);\r\n }\r\n };\r\n\r\n return (\r\n <div className=\"min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-900 p-8\">\r\n <div className=\"w-full max-w-md\">\r\n <div className=\"flex justify-end mb-8\">\r\n <ThemeSwitcher />\r\n </div>\r\n\r\n <div className=\"bg-white dark:bg-gray-800 rounded-2xl shadow-xl p-8\">\r\n {/* Loading State */}\r\n {status === 'loading' && (\r\n <div className=\"text-center\">\r\n <Loader2 className=\"w-16 h-16 text-blue-500 animate-spin mx-auto mb-4\" />\r\n <h2 className=\"text-xl font-semibold text-gray-900 dark:text-white mb-2\">\r\n Confirmation en cours...\r\n </h2>\r\n <p className=\"text-gray-600 dark:text-gray-400\">\r\n Veuillez patienter pendant que nous vérifions votre email.\r\n </p>\r\n </div>\r\n )}\r\n\r\n {/* Success State */}\r\n {status === 'success' && (\r\n <div className=\"text-center\">\r\n <div className=\"w-16 h-16 bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center mx-auto mb-4\">\r\n <CheckCircle2 className=\"w-10 h-10 text-green-600 dark:text-green-400\" />\r\n </div>\r\n <h2 className=\"text-xl font-semibold text-gray-900 dark:text-white mb-2\">\r\n Email confirmé !\r\n </h2>\r\n <p className=\"text-gray-600 dark:text-gray-400 mb-6\">\r\n {message}\r\n </p>\r\n {email && (\r\n <p className=\"text-sm text-gray-500 dark:text-gray-400 mb-6\">\r\n Compte : <strong>{email}</strong>\r\n </p>\r\n )}\r\n <Link\r\n to=\"/login\"\r\n className=\"inline-flex items-center justify-center gap-2 px-6 py-3 bg-gradient-to-r from-blue-600 to-purple-600 text-white rounded-lg font-medium hover:from-blue-700 hover:to-purple-700 transition-all\"\r\n >\r\n Se connecter\r\n </Link>\r\n </div>\r\n )}\r\n\r\n {/* Error / Expired / Already Used States */}\r\n {(status === 'error' || status === 'expired' || status === 'already_used') && (\r\n <div className=\"text-center\">\r\n <div className={`w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-4 ${\r\n status === 'already_used'\r\n ? 'bg-amber-100 dark:bg-amber-900/30'\r\n : 'bg-red-100 dark:bg-red-900/30'\r\n }`}>\r\n {status === 'already_used' ? (\r\n <CheckCircle2 className=\"w-10 h-10 text-amber-600 dark:text-amber-400\" />\r\n ) : (\r\n <XCircle className=\"w-10 h-10 text-red-600 dark:text-red-400\" />\r\n )}\r\n </div>\r\n <h2 className=\"text-xl font-semibold text-gray-900 dark:text-white mb-2\">\r\n {status === 'expired' && 'Lien expiré'}\r\n {status === 'already_used' && 'Lien déjà utilisé'}\r\n {status === 'error' && 'Erreur de confirmation'}\r\n </h2>\r\n <p className=\"text-gray-600 dark:text-gray-400 mb-6\">\r\n {message}\r\n </p>\r\n\r\n {/* Resend Form */}\r\n {(status === 'expired' || status === 'error') && (\r\n <div className=\"border-t border-gray-200 dark:border-gray-700 pt-6 mt-6\">\r\n <p className=\"text-sm text-gray-600 dark:text-gray-400 mb-4\">\r\n Demander un nouveau lien de confirmation :\r\n </p>\r\n <form onSubmit={handleResendConfirmation} className=\"space-y-3\">\r\n <div className=\"relative\">\r\n <div className=\"absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none\">\r\n <Mail className=\"h-5 w-5 text-gray-400\" />\r\n </div>\r\n <input\r\n type=\"email\"\r\n value={resendEmail}\r\n onChange={(e) => setResendEmail(e.target.value)}\r\n placeholder=\"Votre email\"\r\n className=\"block w-full pl-10 pr-3 py-2.5 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-400 focus:ring-2 focus:ring-blue-500 focus:border-transparent\"\r\n required\r\n />\r\n </div>\r\n <button\r\n type=\"submit\"\r\n disabled={isResending}\r\n className=\"w-full flex items-center justify-center gap-2 px-4 py-2.5 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 disabled:opacity-50 transition-colors\"\r\n >\r\n {isResending ? (\r\n <Loader2 className=\"w-5 h-5 animate-spin\" />\r\n ) : (\r\n <RefreshCw className=\"w-5 h-5\" />\r\n )}\r\n Renvoyer le lien\r\n </button>\r\n </form>\r\n {resendMessage && (\r\n <p className=\"mt-3 text-sm text-green-600 dark:text-green-400\">\r\n {resendMessage}\r\n </p>\r\n )}\r\n </div>\r\n )}\r\n\r\n {status === 'already_used' && (\r\n <Link\r\n to=\"/login\"\r\n className=\"inline-flex items-center justify-center gap-2 px-6 py-3 bg-gradient-to-r from-blue-600 to-purple-600 text-white rounded-lg font-medium hover:from-blue-700 hover:to-purple-700 transition-all\"\r\n >\r\n Se connecter\r\n </Link>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n\r\n <p className=\"text-center text-sm text-gray-500 dark:text-gray-400 mt-6\">\r\n <Link to=\"/login\" className=\"hover:underline\">\r\n Retour à la connexion\r\n </Link>\r\n </p>\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"names":["ConfirmEmailPage","searchParams","useSearchParams","token","status","setStatus","useState","message","setMessage","email","setEmail","resendEmail","setResendEmail","isResending","setIsResending","resendMessage","setResendMessage","useEffect","response","authApi","err","error","code","handleResendConfirmation","e","jsxs","jsx","ThemeSwitcher","Loader2","CheckCircle2","Link","XCircle","Mail","RefreshCw"],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import { useState as n } from "react";
|
|
|
3
3
|
import { useNavigate as q } from "react-router-dom";
|
|
4
4
|
import { useTranslation as L } from "react-i18next";
|
|
5
5
|
import { CheckCircle as b, Lock as M, AlertTriangle as T, EyeOff as p, Eye as w, Loader2 as $ } from "lucide-react";
|
|
6
|
-
import { a as D } from "./index-
|
|
6
|
+
import { a as D } from "./index-0Jhdcj59.js";
|
|
7
7
|
function H() {
|
|
8
8
|
const { t: o } = L(), y = q(), [l, v] = n(""), [s, N] = n(""), [d, k] = n(""), [i, P] = n(!1), [c, C] = n(!1), [m, h] = n(!1), [g, u] = n(null), [A, j] = n(!1), z = ((r) => {
|
|
9
9
|
const t = [];
|
|
@@ -132,4 +132,4 @@ function H() {
|
|
|
132
132
|
export {
|
|
133
133
|
H as ForceChangePasswordPage
|
|
134
134
|
};
|
|
135
|
-
//# sourceMappingURL=ForceChangePasswordPage-
|
|
135
|
+
//# sourceMappingURL=ForceChangePasswordPage-ClENqzCH.js.map
|
package/dist/{ForceChangePasswordPage-ov-jJgku.js.map → ForceChangePasswordPage-ClENqzCH.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ForceChangePasswordPage-ov-jJgku.js","sources":["../src/pages/auth/ForceChangePasswordPage.tsx"],"sourcesContent":["import { useState } from 'react';\r\nimport { useNavigate } from 'react-router-dom';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { Lock, Eye, EyeOff, Loader2, AlertTriangle, CheckCircle } from 'lucide-react';\r\nimport { authApi } from '@/services/api/authApi';\r\n\r\nexport function ForceChangePasswordPage() {\r\n const { t } = useTranslation();\r\n const navigate = useNavigate();\r\n\r\n const [currentPassword, setCurrentPassword] = useState('');\r\n const [newPassword, setNewPassword] = useState('');\r\n const [confirmPassword, setConfirmPassword] = useState('');\r\n const [showCurrentPassword, setShowCurrentPassword] = useState(false);\r\n const [showNewPassword, setShowNewPassword] = useState(false);\r\n const [loading, setLoading] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const [success, setSuccess] = useState(false);\r\n\r\n const validatePassword = (password: string): string[] => {\r\n const errors: string[] = [];\r\n if (password.length < 8) errors.push('Au moins 8 caractères');\r\n if (!/[A-Z]/.test(password)) errors.push('Au moins une majuscule');\r\n if (!/[a-z]/.test(password)) errors.push('Au moins une minuscule');\r\n if (!/[0-9]/.test(password)) errors.push('Au moins un chiffre');\r\n return errors;\r\n };\r\n\r\n const passwordErrors = validatePassword(newPassword);\r\n const isValid = newPassword === confirmPassword && passwordErrors.length === 0 && currentPassword.length > 0;\r\n\r\n const handleSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (!isValid) return;\r\n\r\n setLoading(true);\r\n setError(null);\r\n\r\n try {\r\n await authApi.changePassword(currentPassword, newPassword);\r\n setSuccess(true);\r\n setTimeout(() => {\r\n navigate('/');\r\n }, 2000);\r\n } catch (err: unknown) {\r\n if (err instanceof Error) {\r\n setError(err.message);\r\n } else {\r\n setError('Une erreur est survenue');\r\n }\r\n } finally {\r\n setLoading(false);\r\n }\r\n };\r\n\r\n if (success) {\r\n return (\r\n <div className=\"min-h-screen flex items-center justify-center bg-gradient-to-br from-blue-50 to-indigo-100 dark:from-gray-900 dark:to-gray-800 p-4\">\r\n <div className=\"w-full max-w-md bg-white dark:bg-gray-800 rounded-2xl shadow-xl p-8 text-center\">\r\n <div className=\"w-16 h-16 bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center mx-auto mb-4\">\r\n <CheckCircle className=\"w-8 h-8 text-green-600 dark:text-green-400\" />\r\n </div>\r\n <h2 className=\"text-2xl font-bold text-gray-900 dark:text-white mb-2\">\r\n Mot de passe modifié\r\n </h2>\r\n <p className=\"text-gray-600 dark:text-gray-400\">\r\n Vous allez être redirigé vers l'accueil...\r\n </p>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"min-h-screen flex items-center justify-center bg-gradient-to-br from-blue-50 to-indigo-100 dark:from-gray-900 dark:to-gray-800 p-4\">\r\n <div className=\"w-full max-w-md\">\r\n <div className=\"bg-white dark:bg-gray-800 rounded-2xl shadow-xl p-8\">\r\n {/* Header */}\r\n <div className=\"text-center mb-8\">\r\n <div className=\"w-16 h-16 bg-amber-100 dark:bg-amber-900/30 rounded-full flex items-center justify-center mx-auto mb-4\">\r\n <Lock className=\"w-8 h-8 text-amber-600 dark:text-amber-400\" />\r\n </div>\r\n <h1 className=\"text-2xl font-bold text-gray-900 dark:text-white\">\r\n {t('auth.forceChangePassword.title', 'Changement de mot de passe requis')}\r\n </h1>\r\n <p className=\"text-gray-600 dark:text-gray-400 mt-2\">\r\n {t('auth.forceChangePassword.description', 'Pour des raisons de sécurité, vous devez définir un nouveau mot de passe.')}\r\n </p>\r\n </div>\r\n\r\n {/* Error */}\r\n {error && (\r\n <div className=\"mb-6 p-4 rounded-xl bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300 flex items-center gap-2\">\r\n <AlertTriangle className=\"w-5 h-5 flex-shrink-0\" />\r\n <span>{error}</span>\r\n </div>\r\n )}\r\n\r\n {/* Form */}\r\n <form onSubmit={handleSubmit} className=\"space-y-6\">\r\n {/* Current Password */}\r\n <div>\r\n <label className=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\r\n {t('auth.forceChangePassword.currentPassword', 'Mot de passe actuel (temporaire)')}\r\n </label>\r\n <div className=\"relative\">\r\n <input\r\n type={showCurrentPassword ? 'text' : 'password'}\r\n required\r\n value={currentPassword}\r\n onChange={e => setCurrentPassword(e.target.value)}\r\n className=\"w-full px-4 py-3 rounded-xl border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-blue-500\"\r\n placeholder=\"Entrez le mot de passe fourni par l'administrateur\"\r\n />\r\n <button\r\n type=\"button\"\r\n onClick={() => setShowCurrentPassword(!showCurrentPassword)}\r\n className=\"absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700 dark:hover:text-gray-300\"\r\n >\r\n {showCurrentPassword ? <EyeOff className=\"w-5 h-5\" /> : <Eye className=\"w-5 h-5\" />}\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* New Password */}\r\n <div>\r\n <label className=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\r\n {t('auth.forceChangePassword.newPassword', 'Nouveau mot de passe')}\r\n </label>\r\n <div className=\"relative\">\r\n <input\r\n type={showNewPassword ? 'text' : 'password'}\r\n required\r\n value={newPassword}\r\n onChange={e => setNewPassword(e.target.value)}\r\n className=\"w-full px-4 py-3 rounded-xl border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-blue-500\"\r\n placeholder=\"Choisissez un nouveau mot de passe\"\r\n />\r\n <button\r\n type=\"button\"\r\n onClick={() => setShowNewPassword(!showNewPassword)}\r\n className=\"absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700 dark:hover:text-gray-300\"\r\n >\r\n {showNewPassword ? <EyeOff className=\"w-5 h-5\" /> : <Eye className=\"w-5 h-5\" />}\r\n </button>\r\n </div>\r\n\r\n {/* Password requirements */}\r\n {newPassword && (\r\n <div className=\"mt-2 space-y-1\">\r\n {['Au moins 8 caractères', 'Au moins une majuscule', 'Au moins une minuscule', 'Au moins un chiffre'].map((req, i) => {\r\n const checks = [\r\n newPassword.length >= 8,\r\n /[A-Z]/.test(newPassword),\r\n /[a-z]/.test(newPassword),\r\n /[0-9]/.test(newPassword)\r\n ];\r\n return (\r\n <div key={`pwd-req-${i}`} className={`flex items-center gap-2 text-sm ${checks[i] ? 'text-green-600' : 'text-gray-500'}`}>\r\n {checks[i] ? <CheckCircle className=\"w-4 h-4\" /> : <div className=\"w-4 h-4 rounded-full border border-current\" />}\r\n {req}\r\n </div>\r\n );\r\n })}\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Confirm Password */}\r\n <div>\r\n <label className=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\r\n {t('auth.forceChangePassword.confirmPassword', 'Confirmer le nouveau mot de passe')}\r\n </label>\r\n <input\r\n type=\"password\"\r\n required\r\n value={confirmPassword}\r\n onChange={e => setConfirmPassword(e.target.value)}\r\n className={`w-full px-4 py-3 rounded-xl border ${\r\n confirmPassword && confirmPassword !== newPassword\r\n ? 'border-red-500 focus:ring-red-500'\r\n : 'border-gray-300 dark:border-gray-600 focus:ring-blue-500'\r\n } bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none focus:ring-2`}\r\n placeholder=\"Confirmez votre nouveau mot de passe\"\r\n />\r\n {confirmPassword && confirmPassword !== newPassword && (\r\n <p className=\"mt-1 text-sm text-red-600\">Les mots de passe ne correspondent pas</p>\r\n )}\r\n </div>\r\n\r\n {/* Submit */}\r\n <button\r\n type=\"submit\"\r\n disabled={!isValid || loading}\r\n className=\"w-full py-3 px-4 rounded-xl bg-blue-600 hover:bg-blue-700 text-white font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2\"\r\n >\r\n {loading ? (\r\n <>\r\n <Loader2 className=\"w-5 h-5 animate-spin\" />\r\n <span>Modification en cours...</span>\r\n </>\r\n ) : (\r\n <span>{t('auth.forceChangePassword.submit', 'Définir mon nouveau mot de passe')}</span>\r\n )}\r\n </button>\r\n </form>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"names":["ForceChangePasswordPage","t","useTranslation","navigate","useNavigate","currentPassword","setCurrentPassword","useState","newPassword","setNewPassword","confirmPassword","setConfirmPassword","showCurrentPassword","setShowCurrentPassword","showNewPassword","setShowNewPassword","loading","setLoading","error","setError","success","setSuccess","passwordErrors","password","errors","isValid","handleSubmit","e","authApi","err","jsxs","jsx","CheckCircle","Lock","AlertTriangle","EyeOff","Eye","req","i","checks","Fragment","Loader2"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ForceChangePasswordPage-ClENqzCH.js","sources":["../src/pages/auth/ForceChangePasswordPage.tsx"],"sourcesContent":["import { useState } from 'react';\r\nimport { useNavigate } from 'react-router-dom';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { Lock, Eye, EyeOff, Loader2, AlertTriangle, CheckCircle } from 'lucide-react';\r\nimport { authApi } from '@/services/api/authApi';\r\n\r\nexport function ForceChangePasswordPage() {\r\n const { t } = useTranslation();\r\n const navigate = useNavigate();\r\n\r\n const [currentPassword, setCurrentPassword] = useState('');\r\n const [newPassword, setNewPassword] = useState('');\r\n const [confirmPassword, setConfirmPassword] = useState('');\r\n const [showCurrentPassword, setShowCurrentPassword] = useState(false);\r\n const [showNewPassword, setShowNewPassword] = useState(false);\r\n const [loading, setLoading] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const [success, setSuccess] = useState(false);\r\n\r\n const validatePassword = (password: string): string[] => {\r\n const errors: string[] = [];\r\n if (password.length < 8) errors.push('Au moins 8 caractères');\r\n if (!/[A-Z]/.test(password)) errors.push('Au moins une majuscule');\r\n if (!/[a-z]/.test(password)) errors.push('Au moins une minuscule');\r\n if (!/[0-9]/.test(password)) errors.push('Au moins un chiffre');\r\n return errors;\r\n };\r\n\r\n const passwordErrors = validatePassword(newPassword);\r\n const isValid = newPassword === confirmPassword && passwordErrors.length === 0 && currentPassword.length > 0;\r\n\r\n const handleSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (!isValid) return;\r\n\r\n setLoading(true);\r\n setError(null);\r\n\r\n try {\r\n await authApi.changePassword(currentPassword, newPassword);\r\n setSuccess(true);\r\n setTimeout(() => {\r\n navigate('/');\r\n }, 2000);\r\n } catch (err: unknown) {\r\n if (err instanceof Error) {\r\n setError(err.message);\r\n } else {\r\n setError('Une erreur est survenue');\r\n }\r\n } finally {\r\n setLoading(false);\r\n }\r\n };\r\n\r\n if (success) {\r\n return (\r\n <div className=\"min-h-screen flex items-center justify-center bg-gradient-to-br from-blue-50 to-indigo-100 dark:from-gray-900 dark:to-gray-800 p-4\">\r\n <div className=\"w-full max-w-md bg-white dark:bg-gray-800 rounded-2xl shadow-xl p-8 text-center\">\r\n <div className=\"w-16 h-16 bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center mx-auto mb-4\">\r\n <CheckCircle className=\"w-8 h-8 text-green-600 dark:text-green-400\" />\r\n </div>\r\n <h2 className=\"text-2xl font-bold text-gray-900 dark:text-white mb-2\">\r\n Mot de passe modifié\r\n </h2>\r\n <p className=\"text-gray-600 dark:text-gray-400\">\r\n Vous allez être redirigé vers l'accueil...\r\n </p>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"min-h-screen flex items-center justify-center bg-gradient-to-br from-blue-50 to-indigo-100 dark:from-gray-900 dark:to-gray-800 p-4\">\r\n <div className=\"w-full max-w-md\">\r\n <div className=\"bg-white dark:bg-gray-800 rounded-2xl shadow-xl p-8\">\r\n {/* Header */}\r\n <div className=\"text-center mb-8\">\r\n <div className=\"w-16 h-16 bg-amber-100 dark:bg-amber-900/30 rounded-full flex items-center justify-center mx-auto mb-4\">\r\n <Lock className=\"w-8 h-8 text-amber-600 dark:text-amber-400\" />\r\n </div>\r\n <h1 className=\"text-2xl font-bold text-gray-900 dark:text-white\">\r\n {t('auth.forceChangePassword.title', 'Changement de mot de passe requis')}\r\n </h1>\r\n <p className=\"text-gray-600 dark:text-gray-400 mt-2\">\r\n {t('auth.forceChangePassword.description', 'Pour des raisons de sécurité, vous devez définir un nouveau mot de passe.')}\r\n </p>\r\n </div>\r\n\r\n {/* Error */}\r\n {error && (\r\n <div className=\"mb-6 p-4 rounded-xl bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300 flex items-center gap-2\">\r\n <AlertTriangle className=\"w-5 h-5 flex-shrink-0\" />\r\n <span>{error}</span>\r\n </div>\r\n )}\r\n\r\n {/* Form */}\r\n <form onSubmit={handleSubmit} className=\"space-y-6\">\r\n {/* Current Password */}\r\n <div>\r\n <label className=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\r\n {t('auth.forceChangePassword.currentPassword', 'Mot de passe actuel (temporaire)')}\r\n </label>\r\n <div className=\"relative\">\r\n <input\r\n type={showCurrentPassword ? 'text' : 'password'}\r\n required\r\n value={currentPassword}\r\n onChange={e => setCurrentPassword(e.target.value)}\r\n className=\"w-full px-4 py-3 rounded-xl border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-blue-500\"\r\n placeholder=\"Entrez le mot de passe fourni par l'administrateur\"\r\n />\r\n <button\r\n type=\"button\"\r\n onClick={() => setShowCurrentPassword(!showCurrentPassword)}\r\n className=\"absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700 dark:hover:text-gray-300\"\r\n >\r\n {showCurrentPassword ? <EyeOff className=\"w-5 h-5\" /> : <Eye className=\"w-5 h-5\" />}\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* New Password */}\r\n <div>\r\n <label className=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\r\n {t('auth.forceChangePassword.newPassword', 'Nouveau mot de passe')}\r\n </label>\r\n <div className=\"relative\">\r\n <input\r\n type={showNewPassword ? 'text' : 'password'}\r\n required\r\n value={newPassword}\r\n onChange={e => setNewPassword(e.target.value)}\r\n className=\"w-full px-4 py-3 rounded-xl border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-blue-500\"\r\n placeholder=\"Choisissez un nouveau mot de passe\"\r\n />\r\n <button\r\n type=\"button\"\r\n onClick={() => setShowNewPassword(!showNewPassword)}\r\n className=\"absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700 dark:hover:text-gray-300\"\r\n >\r\n {showNewPassword ? <EyeOff className=\"w-5 h-5\" /> : <Eye className=\"w-5 h-5\" />}\r\n </button>\r\n </div>\r\n\r\n {/* Password requirements */}\r\n {newPassword && (\r\n <div className=\"mt-2 space-y-1\">\r\n {['Au moins 8 caractères', 'Au moins une majuscule', 'Au moins une minuscule', 'Au moins un chiffre'].map((req, i) => {\r\n const checks = [\r\n newPassword.length >= 8,\r\n /[A-Z]/.test(newPassword),\r\n /[a-z]/.test(newPassword),\r\n /[0-9]/.test(newPassword)\r\n ];\r\n return (\r\n <div key={`pwd-req-${i}`} className={`flex items-center gap-2 text-sm ${checks[i] ? 'text-green-600' : 'text-gray-500'}`}>\r\n {checks[i] ? <CheckCircle className=\"w-4 h-4\" /> : <div className=\"w-4 h-4 rounded-full border border-current\" />}\r\n {req}\r\n </div>\r\n );\r\n })}\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Confirm Password */}\r\n <div>\r\n <label className=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\r\n {t('auth.forceChangePassword.confirmPassword', 'Confirmer le nouveau mot de passe')}\r\n </label>\r\n <input\r\n type=\"password\"\r\n required\r\n value={confirmPassword}\r\n onChange={e => setConfirmPassword(e.target.value)}\r\n className={`w-full px-4 py-3 rounded-xl border ${\r\n confirmPassword && confirmPassword !== newPassword\r\n ? 'border-red-500 focus:ring-red-500'\r\n : 'border-gray-300 dark:border-gray-600 focus:ring-blue-500'\r\n } bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none focus:ring-2`}\r\n placeholder=\"Confirmez votre nouveau mot de passe\"\r\n />\r\n {confirmPassword && confirmPassword !== newPassword && (\r\n <p className=\"mt-1 text-sm text-red-600\">Les mots de passe ne correspondent pas</p>\r\n )}\r\n </div>\r\n\r\n {/* Submit */}\r\n <button\r\n type=\"submit\"\r\n disabled={!isValid || loading}\r\n className=\"w-full py-3 px-4 rounded-xl bg-blue-600 hover:bg-blue-700 text-white font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2\"\r\n >\r\n {loading ? (\r\n <>\r\n <Loader2 className=\"w-5 h-5 animate-spin\" />\r\n <span>Modification en cours...</span>\r\n </>\r\n ) : (\r\n <span>{t('auth.forceChangePassword.submit', 'Définir mon nouveau mot de passe')}</span>\r\n )}\r\n </button>\r\n </form>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"names":["ForceChangePasswordPage","t","useTranslation","navigate","useNavigate","currentPassword","setCurrentPassword","useState","newPassword","setNewPassword","confirmPassword","setConfirmPassword","showCurrentPassword","setShowCurrentPassword","showNewPassword","setShowNewPassword","loading","setLoading","error","setError","success","setSuccess","passwordErrors","password","errors","isValid","handleSubmit","e","authApi","err","jsxs","jsx","CheckCircle","Lock","AlertTriangle","EyeOff","Eye","req","i","checks","Fragment","Loader2"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),n=require("react"),S=require("react-router-dom"),A=require("react-i18next"),a=require("lucide-react"),q=require("./index-
|
|
2
|
-
//# sourceMappingURL=ForceChangePasswordPage-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),n=require("react"),S=require("react-router-dom"),A=require("react-i18next"),a=require("lucide-react"),q=require("./index-C6C5XmVj.cjs");function E(){const{t:o}=A.useTranslation(),b=S.useNavigate(),[l,w]=n.useState(""),[t,p]=n.useState(""),[d,y]=n.useState(""),[i,j]=n.useState(!1),[c,v]=n.useState(!1),[m,x]=n.useState(!1),[h,u]=n.useState(null),[N,k]=n.useState(!1),P=(s=>{const r=[];return s.length<8&&r.push("Au moins 8 caractères"),/[A-Z]/.test(s)||r.push("Au moins une majuscule"),/[a-z]/.test(s)||r.push("Au moins une minuscule"),/[0-9]/.test(s)||r.push("Au moins un chiffre"),r})(t),g=t===d&&P.length===0&&l.length>0,C=async s=>{if(s.preventDefault(),!!g){x(!0),u(null);try{await q.authApi.changePassword(l,t),k(!0),setTimeout(()=>{b("/")},2e3)}catch(r){r instanceof Error?u(r.message):u("Une erreur est survenue")}finally{x(!1)}}};return N?e.jsx("div",{className:"min-h-screen flex items-center justify-center bg-gradient-to-br from-blue-50 to-indigo-100 dark:from-gray-900 dark:to-gray-800 p-4",children:e.jsxs("div",{className:"w-full max-w-md bg-white dark:bg-gray-800 rounded-2xl shadow-xl p-8 text-center",children:[e.jsx("div",{className:"w-16 h-16 bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center mx-auto mb-4",children:e.jsx(a.CheckCircle,{className:"w-8 h-8 text-green-600 dark:text-green-400"})}),e.jsx("h2",{className:"text-2xl font-bold text-gray-900 dark:text-white mb-2",children:"Mot de passe modifié"}),e.jsx("p",{className:"text-gray-600 dark:text-gray-400",children:"Vous allez être redirigé vers l'accueil..."})]})}):e.jsx("div",{className:"min-h-screen flex items-center justify-center bg-gradient-to-br from-blue-50 to-indigo-100 dark:from-gray-900 dark:to-gray-800 p-4",children:e.jsx("div",{className:"w-full max-w-md",children:e.jsxs("div",{className:"bg-white dark:bg-gray-800 rounded-2xl shadow-xl p-8",children:[e.jsxs("div",{className:"text-center mb-8",children:[e.jsx("div",{className:"w-16 h-16 bg-amber-100 dark:bg-amber-900/30 rounded-full flex items-center justify-center mx-auto mb-4",children:e.jsx(a.Lock,{className:"w-8 h-8 text-amber-600 dark:text-amber-400"})}),e.jsx("h1",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:o("auth.forceChangePassword.title","Changement de mot de passe requis")}),e.jsx("p",{className:"text-gray-600 dark:text-gray-400 mt-2",children:o("auth.forceChangePassword.description","Pour des raisons de sécurité, vous devez définir un nouveau mot de passe.")})]}),h&&e.jsxs("div",{className:"mb-6 p-4 rounded-xl bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300 flex items-center gap-2",children:[e.jsx(a.AlertTriangle,{className:"w-5 h-5 flex-shrink-0"}),e.jsx("span",{children:h})]}),e.jsxs("form",{onSubmit:C,className:"space-y-6",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:o("auth.forceChangePassword.currentPassword","Mot de passe actuel (temporaire)")}),e.jsxs("div",{className:"relative",children:[e.jsx("input",{type:i?"text":"password",required:!0,value:l,onChange:s=>w(s.target.value),className:"w-full px-4 py-3 rounded-xl border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-blue-500",placeholder:"Entrez le mot de passe fourni par l'administrateur"}),e.jsx("button",{type:"button",onClick:()=>j(!i),className:"absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700 dark:hover:text-gray-300",children:i?e.jsx(a.EyeOff,{className:"w-5 h-5"}):e.jsx(a.Eye,{className:"w-5 h-5"})})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:o("auth.forceChangePassword.newPassword","Nouveau mot de passe")}),e.jsxs("div",{className:"relative",children:[e.jsx("input",{type:c?"text":"password",required:!0,value:t,onChange:s=>p(s.target.value),className:"w-full px-4 py-3 rounded-xl border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-blue-500",placeholder:"Choisissez un nouveau mot de passe"}),e.jsx("button",{type:"button",onClick:()=>v(!c),className:"absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700 dark:hover:text-gray-300",children:c?e.jsx(a.EyeOff,{className:"w-5 h-5"}):e.jsx(a.Eye,{className:"w-5 h-5"})})]}),t&&e.jsx("div",{className:"mt-2 space-y-1",children:["Au moins 8 caractères","Au moins une majuscule","Au moins une minuscule","Au moins un chiffre"].map((s,r)=>{const f=[t.length>=8,/[A-Z]/.test(t),/[a-z]/.test(t),/[0-9]/.test(t)];return e.jsxs("div",{className:`flex items-center gap-2 text-sm ${f[r]?"text-green-600":"text-gray-500"}`,children:[f[r]?e.jsx(a.CheckCircle,{className:"w-4 h-4"}):e.jsx("div",{className:"w-4 h-4 rounded-full border border-current"}),s]},`pwd-req-${r}`)})})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:o("auth.forceChangePassword.confirmPassword","Confirmer le nouveau mot de passe")}),e.jsx("input",{type:"password",required:!0,value:d,onChange:s=>y(s.target.value),className:`w-full px-4 py-3 rounded-xl border ${d&&d!==t?"border-red-500 focus:ring-red-500":"border-gray-300 dark:border-gray-600 focus:ring-blue-500"} bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none focus:ring-2`,placeholder:"Confirmez votre nouveau mot de passe"}),d&&d!==t&&e.jsx("p",{className:"mt-1 text-sm text-red-600",children:"Les mots de passe ne correspondent pas"})]}),e.jsx("button",{type:"submit",disabled:!g||m,className:"w-full py-3 px-4 rounded-xl bg-blue-600 hover:bg-blue-700 text-white font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2",children:m?e.jsxs(e.Fragment,{children:[e.jsx(a.Loader2,{className:"w-5 h-5 animate-spin"}),e.jsx("span",{children:"Modification en cours..."})]}):e.jsx("span",{children:o("auth.forceChangePassword.submit","Définir mon nouveau mot de passe")})})]})]})})})}exports.ForceChangePasswordPage=E;
|
|
2
|
+
//# sourceMappingURL=ForceChangePasswordPage-kEFsb5Aq.cjs.map
|