diff --git a/src/front/Components/DesignSystem/DragAndDrop/index.tsx b/src/front/Components/DesignSystem/DragAndDrop/index.tsx index bc2a8021..a73ab98f 100644 --- a/src/front/Components/DesignSystem/DragAndDrop/index.tsx +++ b/src/front/Components/DesignSystem/DragAndDrop/index.tsx @@ -77,6 +77,10 @@ const mimeTypesAccepted: { [key: string]: IMimeTypes } = { extension: "txt", size: 104857600, // 100MB }, + "application/json": { + extension: "json", + size: 104857600, // 100MB + }, }; type IDocumentFileBase = { diff --git a/src/front/Components/Layouts/Login/StepEmail/index.tsx b/src/front/Components/Layouts/Login/StepEmail/index.tsx index 17b108dd..d87a8cc1 100644 --- a/src/front/Components/Layouts/Login/StepEmail/index.tsx +++ b/src/front/Components/Layouts/Login/StepEmail/index.tsx @@ -4,7 +4,7 @@ import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Ty //import Image from "next/image"; import Form from "@Front/Components/DesignSystem/Form"; import TextField from "@Front/Components/DesignSystem/Form/TextField"; -import Button from "@Front/Components/DesignSystem/Button"; +import Button, { EButtonVariant, EButtonstyletype } from "@Front/Components/DesignSystem/Button"; //import franceConnectLogo from "../france-connect.svg"; // import { useRouter } from "next/router"; // import Customers from "@Front/Api/Auth/Id360/Customers/Customers"; @@ -20,10 +20,11 @@ import Confirm from "@Front/Components/DesignSystem/OldModal/Confirm"; type IProps = { onSubmit: (e: React.FormEvent | null, values: { [key: string]: string }) => void; validationErrors: ValidationError[]; + onImportProfile?: () => void; }; export default function StepEmail(props: IProps) { - const { onSubmit, validationErrors } = props; + const { onSubmit, validationErrors, onImportProfile } = props; const [isErrorModalOpen, setIsErrorModalOpen] = useState(0); /* const router = useRouter(); @@ -111,6 +112,20 @@ export default function StepEmail(props: IProps) { + {onImportProfile && ( +
+ + Options avancées : + + +
+ )} void; + onBack: () => void; + validationErrors: ValidationError[]; +}; + +export default function StepImportProfile(props: IProps) { + const { onSubmit, onBack, validationErrors } = props; + const [profileData, setProfileData] = useState(null); + const [error, setError] = useState(""); + + const validateProfileStructure = (data: any): boolean => { + // Basic validation for profile structure + return data && + typeof data === "object" && + data.version && + data.user_data && + typeof data.user_data === "object"; + }; + + const handleFileUpload = useCallback((files: File[]) => { + const file = files[0]; + if (!file) return; + + setError(""); + + // Read and parse JSON + file.text() + .then((text) => { + const data = JSON.parse(text); + + // Validate profile structure + if (!validateProfileStructure(data)) { + setError('Le fichier ne contient pas un profil valide.'); + return; + } + + setProfileData(data); + }) + .catch((e) => { + setError(`Erreur lors de la lecture du fichier JSON: ${e}`); + }); + }, []); + + const handleSubmit = useCallback(() => { + if (profileData) { + onSubmit(profileData); + } + }, [profileData, onSubmit]); + + // Get validation error for import + const importError = validationErrors.find((error) => error.property === "import"); + + return ( +
+ +
Importer un profil
+
+ + + Sélectionnez un fichier JSON contenant vos données de profil pour restaurer votre session. + + +
+ +
+ + {(error || importError) && ( + + {error || (importError?.constraints && Object.values(importError.constraints)[0])} + + )} + + {profileData && ( +
+ + Profil détecté : + + + Version : {profileData.version} + + {profileData.exported_at && ( + + Exporté le : {new Date(profileData.exported_at).toLocaleDateString('fr-FR')} + + )} +
+ )} + +
+ + +
+
+ ); +} \ No newline at end of file diff --git a/src/front/Components/Layouts/Login/index.tsx b/src/front/Components/Layouts/Login/index.tsx index a72a55ac..6005e476 100644 --- a/src/front/Components/Layouts/Login/index.tsx +++ b/src/front/Components/Layouts/Login/index.tsx @@ -21,6 +21,9 @@ import UserStore from "@Front/Stores/UserStore"; import AuthModal from "src/sdk/AuthModal"; import CustomerService from "src/common/Api/LeCoffreApi/sdk/CustomerService"; +import StepImportProfile from "./StepImportProfile"; +import MessageBus from "src/sdk/MessageBus"; +import Iframe from "src/sdk/Iframe"; export enum LoginStep { EMAIL, @@ -28,6 +31,7 @@ export enum LoginStep { PASSWORD, NEW_PASSWORD, PASSWORD_FORGOTTEN, + IMPORT_PROFILE, } export default function Login() { @@ -43,6 +47,8 @@ export default function Login() { const [partialPhoneNumber, setPartialPhoneNumber] = useState(""); const [validationErrors, setValidationErrors] = useState([]); const [isAuthModalOpen, setIsAuthModalOpen] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const [showIframeForImport, setShowIframeForImport] = useState(false); // const openErrorModal = useCallback(() => { // setIsErrorModalOpen(true); @@ -241,10 +247,52 @@ export default function Login() { } }, [email, totpCodeUid]); + const onImportProfileSubmit = useCallback(async (profileData: any) => { + try { + setIsLoading(true); + setValidationErrors([]); + + // Show iframe for import operation (but hidden from view) + setShowIframeForImport(true); + + // Initialize message listener for import operation + MessageBus.getInstance().initMessageListener(); + + // Wait for the iframe to be ready + await MessageBus.getInstance().isReady(); + + await MessageBus.getInstance().importBackup(profileData); + + // Clean up message listener after import + MessageBus.getInstance().destroyMessageListener(); + setShowIframeForImport(false); + + router.push(Module.getInstance().get().modules.pages.Folder.pages.Select.props.path); + } catch (error: any) { + setValidationErrors([ + { + property: "import", + constraints: { + [error.http_status || "500"]: error.message || "Erreur lors de l'import du profil", + }, + }, + ]); + } finally { + setIsLoading(false); + setShowIframeForImport(false); + } + }, [router]); + return (
- {step === LoginStep.EMAIL && } + {step === LoginStep.EMAIL && ( + setStep(LoginStep.IMPORT_PROFILE)} + /> + )} {step === LoginStep.TOTP && ( } + {step === LoginStep.IMPORT_PROFILE && ( + setStep(LoginStep.EMAIL)} + validationErrors={validationErrors} + /> + )}
+ {showIframeForImport &&