mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-06-20 21:00:41 +00:00
feat: add invite code handling from URL for registration flow
This commit is contained in:
+59
-3
@@ -111,6 +111,22 @@ function asText(value: unknown): string {
|
|||||||
return String(value);
|
return String(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function readInviteCodeFromUrl(): string {
|
||||||
|
if (typeof window === 'undefined') return '';
|
||||||
|
|
||||||
|
const searchInvite = new URLSearchParams(window.location.search || '').get('invite');
|
||||||
|
if (searchInvite && searchInvite.trim()) return searchInvite.trim();
|
||||||
|
|
||||||
|
const rawHash = String(window.location.hash || '');
|
||||||
|
const queryIndex = rawHash.indexOf('?');
|
||||||
|
if (queryIndex >= 0) {
|
||||||
|
const hashInvite = new URLSearchParams(rawHash.slice(queryIndex + 1)).get('invite');
|
||||||
|
if (hashInvite && hashInvite.trim()) return hashInvite.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
function summarizeImportResult(
|
function summarizeImportResult(
|
||||||
ciphers: Array<Record<string, unknown>>,
|
ciphers: Array<Record<string, unknown>>,
|
||||||
folderCount: number,
|
folderCount: number,
|
||||||
@@ -302,6 +318,7 @@ export default function App() {
|
|||||||
password2: '',
|
password2: '',
|
||||||
inviteCode: '',
|
inviteCode: '',
|
||||||
});
|
});
|
||||||
|
const [inviteCodeFromUrl, setInviteCodeFromUrl] = useState('');
|
||||||
const [unlockPassword, setUnlockPassword] = useState('');
|
const [unlockPassword, setUnlockPassword] = useState('');
|
||||||
const [pendingTotp, setPendingTotp] = useState<PendingTotp | null>(null);
|
const [pendingTotp, setPendingTotp] = useState<PendingTotp | null>(null);
|
||||||
const [totpCode, setTotpCode] = useState('');
|
const [totpCode, setTotpCode] = useState('');
|
||||||
@@ -326,6 +343,35 @@ export default function App() {
|
|||||||
const [decryptedSends, setDecryptedSends] = useState<Send[]>([]);
|
const [decryptedSends, setDecryptedSends] = useState<Send[]>([]);
|
||||||
const migratedPlainFolderIdsRef = useRef<Set<string>>(new Set());
|
const migratedPlainFolderIdsRef = useRef<Set<string>>(new Set());
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const syncInviteFromUrl = () => {
|
||||||
|
setInviteCodeFromUrl(readInviteCodeFromUrl());
|
||||||
|
};
|
||||||
|
syncInviteFromUrl();
|
||||||
|
window.addEventListener('hashchange', syncInviteFromUrl);
|
||||||
|
window.addEventListener('popstate', syncInviteFromUrl);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('hashchange', syncInviteFromUrl);
|
||||||
|
window.removeEventListener('popstate', syncInviteFromUrl);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!inviteCodeFromUrl) return;
|
||||||
|
setRegisterValues((prev) => (prev.inviteCode === inviteCodeFromUrl ? prev : { ...prev, inviteCode: inviteCodeFromUrl }));
|
||||||
|
}, [inviteCodeFromUrl]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!inviteCodeFromUrl) return;
|
||||||
|
if (phase === 'loading' || phase === 'locked' || phase === 'app') return;
|
||||||
|
setPhase('register');
|
||||||
|
if (location !== '/register') navigate('/register');
|
||||||
|
if (typeof window !== 'undefined' && typeof window.history?.replaceState === 'function') {
|
||||||
|
window.history.replaceState(null, '', '/register');
|
||||||
|
}
|
||||||
|
setInviteCodeFromUrl('');
|
||||||
|
}, [inviteCodeFromUrl, phase, location, navigate]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return;
|
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return;
|
||||||
const media = window.matchMedia('(max-width: 900px)');
|
const media = window.matchMedia('(max-width: 900px)');
|
||||||
@@ -539,6 +585,7 @@ export default function App() {
|
|||||||
}
|
}
|
||||||
setLoginValues({ email: registerValues.email.toLowerCase(), password: '' });
|
setLoginValues({ email: registerValues.email.toLowerCase(), password: '' });
|
||||||
setPhase('login');
|
setPhase('login');
|
||||||
|
navigate('/login');
|
||||||
pushToast('success', t('txt_registration_succeeded_please_sign_in'));
|
pushToast('success', t('txt_registration_succeeded_please_sign_in'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -577,7 +624,7 @@ export default function App() {
|
|||||||
setProfile(null);
|
setProfile(null);
|
||||||
setPendingTotp(null);
|
setPendingTotp(null);
|
||||||
setPhase(setupRegistered ? 'login' : 'register');
|
setPhase(setupRegistered ? 'login' : 'register');
|
||||||
navigate('/login');
|
navigate(setupRegistered ? '/login' : '/register');
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleLogout() {
|
function handleLogout() {
|
||||||
@@ -1695,8 +1742,17 @@ export default function App() {
|
|||||||
onSubmitLogin={() => void handleLogin()}
|
onSubmitLogin={() => void handleLogin()}
|
||||||
onSubmitRegister={() => void handleRegister()}
|
onSubmitRegister={() => void handleRegister()}
|
||||||
onSubmitUnlock={() => void handleUnlock()}
|
onSubmitUnlock={() => void handleUnlock()}
|
||||||
onGotoLogin={() => setPhase('login')}
|
onGotoLogin={() => {
|
||||||
onGotoRegister={() => setPhase('register')}
|
setPhase('login');
|
||||||
|
navigate('/login');
|
||||||
|
}}
|
||||||
|
onGotoRegister={() => {
|
||||||
|
if (inviteCodeFromUrl) {
|
||||||
|
setRegisterValues((prev) => ({ ...prev, inviteCode: inviteCodeFromUrl }));
|
||||||
|
}
|
||||||
|
setPhase('register');
|
||||||
|
navigate('/register');
|
||||||
|
}}
|
||||||
onLogout={logoutNow}
|
onLogout={logoutNow}
|
||||||
/>
|
/>
|
||||||
<ToastHost toasts={toasts} onClose={(id) => setToasts((prev) => prev.filter((x) => x.id !== id))} />
|
<ToastHost toasts={toasts} onClose={(id) => setToasts((prev) => prev.filter((x) => x.id !== id))} />
|
||||||
|
|||||||
Reference in New Issue
Block a user