From 88013161d1b2148aaabd6bde5dcff8a2b9816f8d Mon Sep 17 00:00:00 2001 From: Leendert de Borst Date: Wed, 17 Sep 2025 11:35:49 +0200 Subject: [PATCH] Update email domain field behavior in browser extension and mobile app (#1231) --- .../popup/components/EmailDomainField.tsx | 46 +++++++++++++++---- .../components/form/EmailDomainField.tsx | 44 ++++++++++++++---- 2 files changed, 74 insertions(+), 16 deletions(-) diff --git a/apps/browser-extension/src/entrypoints/popup/components/EmailDomainField.tsx b/apps/browser-extension/src/entrypoints/popup/components/EmailDomainField.tsx index edf82b9ce..9c8b3bcbe 100644 --- a/apps/browser-extension/src/entrypoints/popup/components/EmailDomainField.tsx +++ b/apps/browser-extension/src/entrypoints/popup/components/EmailDomainField.tsx @@ -90,7 +90,7 @@ const EmailDomainField: React.FC = ({ setIsCustomDomain(!isKnownDomain); } else { setLocalPart(value); - setIsCustomDomain(false); + // Don't reset isCustomDomain here - preserve the current mode // Set default domain if not already set if (!selectedDomain && !value.includes('@')) { @@ -107,6 +107,13 @@ const EmailDomainField: React.FC = ({ const handleLocalPartChange = useCallback((e: React.ChangeEvent) => { const newLocalPart = e.target.value; + // If in custom domain mode, always pass through the full value + if (isCustomDomain) { + onChange(newLocalPart); + // Stay in custom domain mode - don't auto-switch back + return; + } + // Check if new value contains '@' symbol, if so, switch to custom domain mode if (newLocalPart.includes('@')) { setIsCustomDomain(true); @@ -115,10 +122,11 @@ const EmailDomainField: React.FC = ({ } setLocalPart(newLocalPart); - if (!isCustomDomain && selectedDomain) { + // If the local part is empty, treat the whole field as empty + if (!newLocalPart || newLocalPart.trim() === '') { + onChange(''); + } else if (selectedDomain) { onChange(`${newLocalPart}@${selectedDomain}`); - } else { - onChange(newLocalPart); } }, [isCustomDomain, selectedDomain, onChange]); @@ -126,7 +134,12 @@ const EmailDomainField: React.FC = ({ const selectDomain = useCallback((domain: string) => { setSelectedDomain(domain); const cleanLocalPart = localPart.includes('@') ? localPart.split('@')[0] : localPart; - onChange(`${cleanLocalPart}@${domain}`); + // If the local part is empty, treat the whole field as empty + if (!cleanLocalPart || cleanLocalPart.trim() === '') { + onChange(''); + } else { + onChange(`${cleanLocalPart}@${domain}`); + } setIsCustomDomain(false); setIsPopupVisible(false); }, [localPart, onChange]); @@ -136,13 +149,30 @@ const EmailDomainField: React.FC = ({ const newIsCustom = !isCustomDomain; setIsCustomDomain(newIsCustom); - if (!newIsCustom && !value.includes('@')) { - // Switching to domain chooser mode, add default domain + if (newIsCustom) { + /* + * Switching to custom domain mode + * If we have a domain-based value, extract just the local part + */ + if (value && value.includes('@')) { + const [local] = value.split('@'); + onChange(local); + setLocalPart(local); + } + } else { + // Switching to domain chooser mode const defaultDomain = showPrivateDomains && privateEmailDomains[0] ? privateEmailDomains[0] : PUBLIC_EMAIL_DOMAINS[0]; - onChange(`${localPart}@${defaultDomain}`); setSelectedDomain(defaultDomain); + + // Only add domain if we have a local part + if (localPart && localPart.trim()) { + onChange(`${localPart}@${defaultDomain}`); + } else if (value && !value.includes('@')) { + // If we have a value without @, add the domain + onChange(`${value}@${defaultDomain}`); + } } }, [isCustomDomain, value, localPart, showPrivateDomains, privateEmailDomains, onChange]); diff --git a/apps/mobile-app/components/form/EmailDomainField.tsx b/apps/mobile-app/components/form/EmailDomainField.tsx index ada5bc2c4..a971a2321 100644 --- a/apps/mobile-app/components/form/EmailDomainField.tsx +++ b/apps/mobile-app/components/form/EmailDomainField.tsx @@ -97,7 +97,7 @@ export const EmailDomainField: React.FC = ({ setIsCustomDomain(!isKnownDomain); } else { setLocalPart(value); - setIsCustomDomain(false); + // Don't reset isCustomDomain here - preserve the current mode // Set default domain if not already set if (!selectedDomain && !value.includes('@')) { @@ -112,6 +112,13 @@ export const EmailDomainField: React.FC = ({ // Handle local part changes const handleLocalPartChange = useCallback((newText: string) => { + // If in custom domain mode, always pass through the full value + if (isCustomDomain) { + onChange(newText); + // Stay in custom domain mode - don't auto-switch back + return; + } + // Check if new value contains '@' symbol, if so, switch to custom domain mode if (newText.includes('@')) { setIsCustomDomain(true); @@ -120,10 +127,11 @@ export const EmailDomainField: React.FC = ({ } setLocalPart(newText); - if (!isCustomDomain && selectedDomain) { + // If the local part is empty, treat the whole field as empty + if (!newText || newText.trim() === '') { + onChange(''); + } else if (selectedDomain) { onChange(`${newText}@${selectedDomain}`); - } else { - onChange(newText); } }, [isCustomDomain, selectedDomain, onChange]); @@ -131,7 +139,12 @@ export const EmailDomainField: React.FC = ({ const selectDomain = useCallback((domain: string) => { setSelectedDomain(domain); const cleanLocalPart = localPart.includes('@') ? localPart.split('@')[0] : localPart; - onChange(`${cleanLocalPart}@${domain}`); + // If the local part is empty, treat the whole field as empty + if (!cleanLocalPart || cleanLocalPart.trim() === '') { + onChange(''); + } else { + onChange(`${cleanLocalPart}@${domain}`); + } setIsCustomDomain(false); setIsModalVisible(false); }, [localPart, onChange]); @@ -141,13 +154,28 @@ export const EmailDomainField: React.FC = ({ const newIsCustom = !isCustomDomain; setIsCustomDomain(newIsCustom); - if (!newIsCustom && !value.includes('@')) { - // Switching to domain chooser mode, add default domain + if (newIsCustom) { + // Switching to custom domain mode + // If we have a domain-based value, extract just the local part + if (value && value.includes('@')) { + const [local] = value.split('@'); + onChange(local); + setLocalPart(local); + } + } else { + // Switching to domain chooser mode const defaultDomain = showPrivateDomains && privateEmailDomains[0] ? privateEmailDomains[0] : PUBLIC_EMAIL_DOMAINS[0]; - onChange(`${localPart}@${defaultDomain}`); setSelectedDomain(defaultDomain); + + // Only add domain if we have a local part + if (localPart && localPart.trim()) { + onChange(`${localPart}@${defaultDomain}`); + } else if (value && !value.includes('@')) { + // If we have a value without @, add the domain + onChange(`${value}@${defaultDomain}`); + } } }, [isCustomDomain, value, localPart, showPrivateDomains, privateEmailDomains, onChange]);