mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-06-20 13:00:39 +00:00
Optimize the public sending page and navigation logic in presentation mode to ensure consistency in user experience
This commit is contained in:
+7
-1
@@ -400,13 +400,18 @@ export default function App() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (IS_DEMO_MODE) {
|
if (IS_DEMO_MODE) {
|
||||||
|
const currentHashPath = typeof window !== 'undefined'
|
||||||
|
? (window.location.hash || '').replace(/^#/, '').split('?')[0].split('#')[0]
|
||||||
|
: '';
|
||||||
|
const normalizedCurrentHashPath = currentHashPath.replace(/^\/+/, '').replace(/\/+$/, '');
|
||||||
|
const isDemoPublicSendRoute = /^send\/[^/]+(?:\/[^/]+)?$/i.test(normalizedCurrentHashPath);
|
||||||
setDefaultKdfIterations(initialBootstrap.defaultKdfIterations);
|
setDefaultKdfIterations(initialBootstrap.defaultKdfIterations);
|
||||||
setJwtWarning(null);
|
setJwtWarning(null);
|
||||||
setSession(null);
|
setSession(null);
|
||||||
setProfile(null);
|
setProfile(null);
|
||||||
setPhase('login');
|
setPhase('login');
|
||||||
setUnlockPreparing(false);
|
setUnlockPreparing(false);
|
||||||
if (location !== '/login') navigate('/login');
|
if (!isDemoPublicSendRoute && location !== '/login') navigate('/login');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -956,6 +961,7 @@ export default function App() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (IS_DEMO_MODE) return;
|
||||||
if (phase !== 'app' || !vaultInitialDecryptDone) return;
|
if (phase !== 'app' || !vaultInitialDecryptDone) return;
|
||||||
void preloadAuthenticatedWorkspace(isAdmin);
|
void preloadAuthenticatedWorkspace(isAdmin);
|
||||||
}, [phase, vaultInitialDecryptDone, isAdmin]);
|
}, [phase, vaultInitialDecryptDone, isAdmin]);
|
||||||
|
|||||||
@@ -87,12 +87,13 @@ function parsePublicSendData(value: unknown): PublicSendData | null {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function PublicSendPage(props: PublicSendPageProps) {
|
export default function PublicSendPage(props: PublicSendPageProps) {
|
||||||
const [loading, setLoading] = useState(true);
|
const initialDemoSend = IS_DEMO_MODE ? getDemoPublicSend(props.accessId) : null;
|
||||||
|
const [loading, setLoading] = useState(!IS_DEMO_MODE);
|
||||||
const [password, setPassword] = useState('');
|
const [password, setPassword] = useState('');
|
||||||
const [needPassword, setNeedPassword] = useState(false);
|
const [needPassword, setNeedPassword] = useState(false);
|
||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
const [notFound, setNotFound] = useState(false);
|
const [notFound, setNotFound] = useState(IS_DEMO_MODE && !initialDemoSend);
|
||||||
const [sendData, setSendData] = useState<PublicSendData | null>(null);
|
const [sendData, setSendData] = useState<PublicSendData | null>(initialDemoSend);
|
||||||
const [busy, setBusy] = useState(false);
|
const [busy, setBusy] = useState(false);
|
||||||
const [downloadPercent, setDownloadPercent] = useState<number | null>(null);
|
const [downloadPercent, setDownloadPercent] = useState<number | null>(null);
|
||||||
const loadRequestRef = useRef(0);
|
const loadRequestRef = useRef(0);
|
||||||
@@ -201,6 +202,15 @@ export default function PublicSendPage(props: PublicSendPageProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (IS_DEMO_MODE) {
|
||||||
|
const demoSend = getDemoPublicSend(props.accessId);
|
||||||
|
setSendData(demoSend);
|
||||||
|
setNotFound(!demoSend);
|
||||||
|
setNeedPassword(false);
|
||||||
|
setError('');
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
void loadSend();
|
void loadSend();
|
||||||
return () => {
|
return () => {
|
||||||
loadAbortRef.current?.abort();
|
loadAbortRef.current?.abort();
|
||||||
|
|||||||
@@ -224,8 +224,17 @@ export default function SendsPage(props: SendsPageProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getAccessUrl(send: Send): string {
|
||||||
|
const rawUrl = send.shareUrl || `/send/${send.accessId}`;
|
||||||
|
if (/^https?:\/\//i.test(rawUrl)) return rawUrl;
|
||||||
|
if (rawUrl.startsWith('/#/')) return `${window.location.origin}${rawUrl}`;
|
||||||
|
if (rawUrl.startsWith('#/')) return `${window.location.origin}/${rawUrl}`;
|
||||||
|
if (rawUrl.startsWith('/')) return `${window.location.origin}/#${rawUrl}`;
|
||||||
|
return `${window.location.origin}/#/${rawUrl.replace(/^\/+/, '')}`;
|
||||||
|
}
|
||||||
|
|
||||||
function copyAccessUrl(send: Send): void {
|
function copyAccessUrl(send: Send): void {
|
||||||
const url = send.shareUrl || `${window.location.origin}/#/send/${send.accessId}`;
|
const url = getAccessUrl(send);
|
||||||
void copyTextToClipboard(url, { successMessage: t('txt_link_copied') });
|
void copyTextToClipboard(url, { successMessage: t('txt_link_copied') });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
preloadWebsiteIcon,
|
preloadWebsiteIcon,
|
||||||
subscribeWebsiteIconStatus,
|
subscribeWebsiteIconStatus,
|
||||||
} from '@/lib/website-icon-cache';
|
} from '@/lib/website-icon-cache';
|
||||||
|
import { demoBrandIconUrl } from '@/lib/demo-brand-icons';
|
||||||
import { firstCipherUri, hostFromUri, websiteIconUrl } from '@/lib/website-utils';
|
import { firstCipherUri, hostFromUri, websiteIconUrl } from '@/lib/website-utils';
|
||||||
|
|
||||||
const ICON_LOAD_ROOT_MARGIN = '180px 0px';
|
const ICON_LOAD_ROOT_MARGIN = '180px 0px';
|
||||||
@@ -25,21 +26,7 @@ export default function WebsiteIcon(props: WebsiteIconProps) {
|
|||||||
const [shouldLoad, setShouldLoad] = useState(() => (host ? getWebsiteIconStatus(host) === 'loaded' : true));
|
const [shouldLoad, setShouldLoad] = useState(() => (host ? getWebsiteIconStatus(host) === 'loaded' : true));
|
||||||
const [status, setStatus] = useState(() => (host ? getWebsiteIconStatus(host) : 'idle'));
|
const [status, setStatus] = useState(() => (host ? getWebsiteIconStatus(host) : 'idle'));
|
||||||
const [imageUrl, setImageUrl] = useState(() => (host ? getWebsiteIconImageUrl(host) : ''));
|
const [imageUrl, setImageUrl] = useState(() => (host ? getWebsiteIconImageUrl(host) : ''));
|
||||||
const [demoIconUrl, setDemoIconUrl] = useState('');
|
const demoIconUrl = SHOULD_LOAD_DEMO_BRAND_ICONS && host ? demoBrandIconUrl(host) : '';
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!SHOULD_LOAD_DEMO_BRAND_ICONS || !host) {
|
|
||||||
setDemoIconUrl('');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let disposed = false;
|
|
||||||
void import('@/lib/demo-brand-icons').then(({ demoBrandIconUrl }) => {
|
|
||||||
if (!disposed) setDemoIconUrl(demoBrandIconUrl(host));
|
|
||||||
});
|
|
||||||
return () => {
|
|
||||||
disposed = true;
|
|
||||||
};
|
|
||||||
}, [host]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!host) {
|
if (!host) {
|
||||||
@@ -88,6 +75,7 @@ export default function WebsiteIcon(props: WebsiteIconProps) {
|
|||||||
}, [host, shouldLoad, status]);
|
}, [host, shouldLoad, status]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (SHOULD_LOAD_DEMO_BRAND_ICONS) return;
|
||||||
if (demoIconUrl) return;
|
if (demoIconUrl) return;
|
||||||
if (!host || !src || !shouldLoad || status === 'loaded' || status === 'error') return;
|
if (!host || !src || !shouldLoad || status === 'loaded' || status === 'error') return;
|
||||||
let disposed = false;
|
let disposed = false;
|
||||||
|
|||||||
@@ -422,7 +422,7 @@ export const DEMO_SENDS: Send[] = [
|
|||||||
deletionDate: '2026-05-18T08:00:00.000Z',
|
deletionDate: '2026-05-18T08:00:00.000Z',
|
||||||
expirationDate: null,
|
expirationDate: null,
|
||||||
revisionDate: DEMO_NOW,
|
revisionDate: DEMO_NOW,
|
||||||
shareUrl: '/send/demo-note/demo-key',
|
shareUrl: '/#/send/demo-note/demo-key',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'send-demo-file',
|
id: 'send-demo-file',
|
||||||
@@ -438,7 +438,7 @@ export const DEMO_SENDS: Send[] = [
|
|||||||
deletionDate: '2026-05-11T08:00:00.000Z',
|
deletionDate: '2026-05-11T08:00:00.000Z',
|
||||||
expirationDate: '2026-05-08T08:00:00.000Z',
|
expirationDate: '2026-05-08T08:00:00.000Z',
|
||||||
revisionDate: DEMO_NOW,
|
revisionDate: DEMO_NOW,
|
||||||
shareUrl: '/send/demo-file/demo-key',
|
shareUrl: '/#/send/demo-file/demo-key',
|
||||||
file: {
|
file: {
|
||||||
id: 'send-file-001',
|
id: 'send-file-001',
|
||||||
fileName: 'design-handoff.zip',
|
fileName: 'design-handoff.zip',
|
||||||
@@ -730,7 +730,7 @@ function sendFromDraft(draft: SendDraft, current?: Send | null): Send {
|
|||||||
deletionDate: new Date(Date.now() + deletionDays * 86400_000).toISOString(),
|
deletionDate: new Date(Date.now() + deletionDays * 86400_000).toISOString(),
|
||||||
expirationDate: expirationDays > 0 ? new Date(Date.now() + expirationDays * 86400_000).toISOString() : null,
|
expirationDate: expirationDays > 0 ? new Date(Date.now() + expirationDays * 86400_000).toISOString() : null,
|
||||||
revisionDate: now,
|
revisionDate: now,
|
||||||
shareUrl: current?.shareUrl || (isFile ? '/send/demo-file/demo-key' : '/send/demo-note/demo-key'),
|
shareUrl: current?.shareUrl || (isFile ? '/#/send/demo-file/demo-key' : '/#/send/demo-note/demo-key'),
|
||||||
file: isFile ? {
|
file: isFile ? {
|
||||||
id: current?.file?.id || createDemoId('send-file'),
|
id: current?.file?.id || createDemoId('send-file'),
|
||||||
fileName,
|
fileName,
|
||||||
|
|||||||
+13
-10
@@ -60,16 +60,19 @@ export default defineConfig(({ mode }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
normalized.includes('/src/components/ImportPage.tsx') ||
|
!isDemo &&
|
||||||
normalized.includes('/src/lib/import-') ||
|
(
|
||||||
normalized.includes('/src/lib/export-formats.ts') ||
|
normalized.includes('/src/components/ImportPage.tsx') ||
|
||||||
normalized.includes('/src/components/SendsPage.tsx') ||
|
normalized.includes('/src/lib/import-') ||
|
||||||
normalized.includes('/src/components/TotpCodesPage.tsx') ||
|
normalized.includes('/src/lib/export-formats.ts') ||
|
||||||
normalized.includes('/src/components/BackupCenterPage.tsx') ||
|
normalized.includes('/src/components/SendsPage.tsx') ||
|
||||||
normalized.includes('/src/components/backup-center/') ||
|
normalized.includes('/src/components/TotpCodesPage.tsx') ||
|
||||||
normalized.includes('/src/components/SettingsPage.tsx') ||
|
normalized.includes('/src/components/BackupCenterPage.tsx') ||
|
||||||
normalized.includes('/src/components/SecurityDevicesPage.tsx') ||
|
normalized.includes('/src/components/backup-center/') ||
|
||||||
normalized.includes('/src/components/AdminPage.tsx')
|
normalized.includes('/src/components/SettingsPage.tsx') ||
|
||||||
|
normalized.includes('/src/components/SecurityDevicesPage.tsx') ||
|
||||||
|
normalized.includes('/src/components/AdminPage.tsx')
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
return 'workspace-suite';
|
return 'workspace-suite';
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user