diff --git a/src/components/ChatBubble/ChatBubble.tsx b/src/components/ChatBubble/ChatBubble.tsx index a7ae5e4a..1569187e 100644 --- a/src/components/ChatBubble/ChatBubble.tsx +++ b/src/components/ChatBubble/ChatBubble.tsx @@ -55,6 +55,7 @@ marked.use({ renderer: { link: ({ href, title, text }) => { const cleanHref = cleanUrl(href); + if (cleanHref === null) { return text; } diff --git a/src/components/MemoriWidget/MemoriWidget.tsx b/src/components/MemoriWidget/MemoriWidget.tsx index 10849393..7699fda8 100644 --- a/src/components/MemoriWidget/MemoriWidget.tsx +++ b/src/components/MemoriWidget/MemoriWidget.tsx @@ -1093,6 +1093,16 @@ const MemoriWidget = ({ } }); }; + + + /** + * Opening Session + */ + /** + * Fetches a new session with the given parameters + * @param params OpenSession parameters + * @returns Promise resolving to dialog state and session ID if successful, void otherwise + */ const fetchSession = async ( params: OpenSession ): Promise<{ @@ -1104,6 +1114,7 @@ const MemoriWidget = ({ return; } + // Check if authentication is needed for private Memori if ( memori.privacyType !== 'PUBLIC' && !memori.secretToken && @@ -1115,6 +1126,7 @@ const MemoriWidget = ({ } setLoading(true); try { + // Check for and set giver invitation if available if (!memori.giverTag && !!memori.receivedInvitations?.length) { let giverInvitation = memori.receivedInvitations.find( (i: Invitation) => i.type === 'GIVER' && i.state === 'ACCEPTED' @@ -1126,6 +1138,7 @@ const MemoriWidget = ({ } } + // Get referral URL let referral; try { referral = (() => { @@ -1135,6 +1148,7 @@ const MemoriWidget = ({ console.debug(err); } + // Initialize session with parameters const session = await initSession({ ...params, tag: params.tag ?? personification?.tag, @@ -1148,6 +1162,8 @@ const MemoriWidget = ({ timeZoneOffset: new Date().getTimezoneOffset().toString(), }, }); + + // Handle successful session creation if ( session?.sessionID && session?.currentState && @@ -1162,25 +1178,45 @@ const MemoriWidget = ({ dialogState: session.currentState, sessionID: session.sessionID, } as { dialogState: DialogState; sessionID: string }; - } else if ( + } + // Handle age restriction error + else if ( session?.resultMessage.startsWith('This Memori is aged restricted') ) { console.warn(session); toast.error(t('underageTwinSession', { age: minAge })); setGotErrorInOpening(true); - } else if (session?.resultCode === 403) { + } + // Handle authentication error + else if (session?.resultCode === 403) { setMemoriPwd(undefined); setAuthModalState('password'); - } else { + } + // Handle other errors + else { console.warn(session); toast.error(t(getErrori18nKey(session?.resultCode))); setGotErrorInOpening(true); } } catch (err) { console.error(err); - new Error('Error fetching session'); + toast.error(t('errorFetchingSession')); + throw new Error('Error fetching session'); } }; + + /** + * Reopens an existing session with optional parameters + * @param updateDialogState Whether to update dialog state + * @param password Optional password for authentication + * @param recoveryTokens Optional recovery tokens + * @param tag Optional tag + * @param pin Optional PIN + * @param initialContextVars Optional initial context variables + * @param initialQuestion Optional initial question + * @param birthDate Optional birth date for age verification + * @returns Promise resolving to dialog state and session ID if successful, null otherwise + */ const reopenSession = async ( updateDialogState: boolean = false, password?: string, @@ -1198,6 +1234,7 @@ const MemoriWidget = ({ return; } + // Check if authentication is needed if ( memori.privacyType !== 'PUBLIC' && !password && @@ -1210,6 +1247,7 @@ const MemoriWidget = ({ return; } + // Get referral URL let referral; try { referral = (() => { @@ -1217,8 +1255,11 @@ const MemoriWidget = ({ })(); } catch (err) { console.debug(err); + toast.error(t('errorGettingReferralURL')); + throw new Error('Error getting referral URL'); } + // Initialize session with parameters const { sessionID, currentState, ...response } = await initSession({ memoriID: memori.engineMemoriID ?? '', password: password || memoriPwd || memori.secretToken, @@ -1242,12 +1283,15 @@ const MemoriWidget = ({ }, }); + // Handle successful session creation if (sessionID && currentState && response.resultCode === 0) { setSessionId(sessionID); + // Update dialog state if requested if (updateDialogState) { setCurrentDialogState(currentState); if (currentState.emission) { + // Set history based on current length history.length <= 1 ? setHistory([ { @@ -1284,6 +1328,7 @@ const MemoriWidget = ({ } } + // Apply position and date if needed if (position) applyPosition(position, sessionID); if (memori.needsDateTime) sendDateChangedEvent({ sessionID: sessionID, state: currentState }); @@ -1293,28 +1338,37 @@ const MemoriWidget = ({ dialogState: currentState, sessionID, }; - } else if ( + } + // Handle age restriction error + else if ( response?.resultMessage.startsWith('This Memori is aged restricted') ) { console.error(response); toast.error(t('underageTwinSession', { age: minAge })); setGotErrorInOpening(true); - } else if (response?.resultCode === 403) { + } + // Handle authentication error + else if (response?.resultCode === 403) { setMemoriPwd(undefined); setAuthModalState('password'); - } else { + } + // Handle other errors + else { console.error(response); toast.error(t(getErrori18nKey(response.resultCode))); setGotErrorInOpening(true); } } catch (err) { console.error(err); + toast.error(t('errorReopeningSession')); + throw new Error('Error reopening session'); } setLoading(false); return null; }; + const changeTag = async ( memoriId: string, sessionId: string, diff --git a/src/locales/de.json b/src/locales/de.json index 23e59b8d..d8b608f8 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -55,6 +55,9 @@ "birthDateHelper": "Wir fragen nur nach Ihrem Geburtsdatum, um Funktionen zu aktivieren oder zu deaktivieren, für die Altersbeschränkungen gelten", "underage": "Das müssen Sie mindestens sein {{age}} Jahre alt, um sich anzumelden.", "underageTwinSession": "Das müssen Sie mindestens sein {{age}} Jahre alt, um mit diesem Zwilling zu interagieren.", + "errorFetchingSession": "Fehler beim Laden der Sitzung", + "errorGettingReferralURL": "Fehler beim Laden des Referrals", + "errorReopeningSession": "Fehler beim erneuten Öffnen der Sitzung", "ageVerification": "Altersüberprüfung", "ageVerificationText": "Um mit diesem Zwilling interagieren zu können, müssen Sie mindestens sein {{minAge}} Jahre alt.", "nsfw": "NSFW: Dieser Twin enthält Inhalte für Erwachsene", diff --git a/src/locales/en.json b/src/locales/en.json index f9e01879..5929f66a 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -55,6 +55,9 @@ "birthDateHelper": "We ask for your birth date only to enable or disable functionalities that have age restrictions", "underage": "You must be at least {{age}} years old to sign up.", "underageTwinSession": "You must be at least {{age}} years old to interact with this Twin.", + "errorFetchingSession": "Error during session loading", + "errorGettingReferralURL": "Error during referral loading", + "errorReopeningSession": "Error during session reopening", "ageVerification": "Age verification", "ageVerificationText": "To interact with this Twin, you must be at least {{minAge}} years old.", "nsfw": "NSFW: This Twin contains adult contents", diff --git a/src/locales/es.json b/src/locales/es.json index 800096c3..e5c9e2a9 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -55,6 +55,9 @@ "birthDateHelper": "Solicitamos tu fecha de nacimiento únicamente para habilitar o deshabilitar funcionalidades que tienen restricciones de edad.", "underage": "Debes ser al menos {{age}} años para inscribirse.", "underageTwinSession": "Debes ser al menos {{age}} años para interactuar con este gemelo.", + "errorFetchingSession": "Error durante el cargamento de la sesión", + "errorGettingReferralURL": "Error durante el cargamento del référent", + "errorReopeningSession": "Error durante el re-abrir la sesión", "ageVerification": "Verificación de edad", "ageVerificationText": "Para interactuar con este Gemelo, debes tener al menos {{minAge}} años.", "nsfw": "NSFW: Este gemelo contiene contenido para adultos", diff --git a/src/locales/fr.json b/src/locales/fr.json index 992fc6da..3f33ec02 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -55,6 +55,9 @@ "birthDateHelper": "Nous demandons votre date de naissance uniquement pour activer ou désactiver les fonctionnalités qui ont des restrictions d'âge", "underage": "Vous devez être au moins {{age}} ans pour s'inscrire.", "underageTwinSession": "Vous devez être au moins {{age}} ans pour interagir avec ce Twin.", + "errorFetchingSession": "Erreur lors du chargement de la session", + "errorGettingReferralURL": "Erreur lors du chargement du référent", + "errorReopeningSession": "Erreur lors de la re-ouverture de la session", "ageVerification": "Vérification de l'âge", "ageVerificationText": "Pour interagir avec ce Twin, vous devez être au minimum {{minAge}} ans.", "nsfw": "NSFW : Ce jumeau contient du contenu pour adultes", diff --git a/src/locales/it.json b/src/locales/it.json index 6aea8604..53ce25c8 100644 --- a/src/locales/it.json +++ b/src/locales/it.json @@ -55,6 +55,9 @@ "birthDateHelper": "Ti chiediamo la data di nascita esclusivamente per abilitare o disabilitare le funzionalità che hanno restrizioni in base all'età", "underage": "Devi avere almeno {{age}} anni per registrarti.", "underageTwinSession": "Devi avere almeno {{age}} anni per interagire con questo Twin.", + "errorFetchingSession": "Errore durante il caricamento della sessione", + "errorGettingReferralURL": "Errore durante il caricamento del riferimento", + "errorReopeningSession": "Errore durante il riapertura della sessione", "ageVerification": "Verifica dell'età", "ageVerificationText": "Per interagire con questo Twin, devi aver almeno {{minAge}} anni.", "nsfw": "NSFW: Questo Twin contiene contenuti per adulti",