fix(ux): repair broken in-app navigations under HashRouter

Three places used window.location.href to navigate to bare paths (/signers,
/messages/:npub, /settings). Under HashRouter those trigger a full page reload
to a non-hash path the router can't match — the user got a blank/404 flash
instead of the target screen.

- WhosSkating: DM button now uses useNavigate() instead of a reload.
- StashPage: "Learn About Signers" now uses <Link to="/signers"> (asChild).
- BackupReminder: "Back up now" now uses navigate() AND corrects the deep-link
  param from ?tab=security to ?section=security (SettingsPage reads ?section),
  which previously dropped the user on the settings root instead of Security.
  Also closes the reminder sheet on navigate.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
shakespeare.diy 2026-09-07 19:22:40 +07:00
parent f1b8d01144
commit 4aec9539d6
3 changed files with 16 additions and 5 deletions

View file

@ -1,4 +1,5 @@
import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { AlertTriangle, X, Download, CheckCircle } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { useCurrentUser } from '@/hooks/useCurrentUser';
@ -26,6 +27,7 @@ export function BackupReminder() {
const [confirmed, setConfirmed] = useLocalStorage(BACKUP_CONFIRMED_KEY, false);
const [showReminder, setShowReminder] = useState(false);
const { t } = useTranslation();
const navigate = useNavigate();
useEffect(() => {
if (!user) {
@ -57,7 +59,13 @@ export function BackupReminder() {
};
const handleBackupNow = () => {
window.location.href = '/settings?tab=security';
// Client-side nav (HashRouter). window.location.href forced a full reload to
// a non-hash path the router couldn't match — it dropped the user on a blank
// page instead of the security settings. navigate() keeps it in-app.
setShowReminder(false);
// SettingsPage deep-links via ?section=… (NOT ?tab=…) — using the wrong
// param silently dropped the user on the settings root instead of Security.
navigate('/settings?section=security');
};
if (!showReminder) return null;

View file

@ -1,4 +1,4 @@
import { Link } from 'react-router-dom';
import { Link, useNavigate } from 'react-router-dom';
import { nip19 } from 'nostr-tools';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
@ -19,6 +19,7 @@ interface WhosSkatingProps {
}
function SkaterCard({ pubkey, status, emoji }: { pubkey: string; status: string; emoji?: string }) {
const navigate = useNavigate();
const { data: authorData, isLoading } = useAuthor(pubkey);
const metadata = authorData?.metadata;
const displayName = metadata?.name ?? genUserName(pubkey);
@ -68,8 +69,10 @@ function SkaterCard({ pubkey, status, emoji }: { pubkey: string; status: string;
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
// Navigate to DM
window.location.href = `/messages/${npub}`;
// Client-side navigation (HashRouter). Using window.location.href
// here caused a full reload to a non-hash path the router couldn't
// match — a broken jump. useNavigate keeps it in-app and instant.
navigate(`/messages/${npub}`);
}}
>
<MessageCircle className="h-4 w-4" />

View file

@ -733,7 +733,7 @@ export default function StashPage() {
<AlertTriangle className="h-12 w-12 mx-auto mb-4 text-yellow-500" />
<h2 className="text-2xl font-black uppercase text-white mb-3">Encryption Required</h2>
<p className="text-gray-300 mb-6 max-w-md mx-auto">Your Stash is encrypted for privacy. Please use a signer that supports NIP-44 encryption (like Alby, nos2x, or Amber).</p>
<Button variant="outline" onClick={() => window.location.href = '/signers'}>Learn About Signers</Button>
<Button variant="outline" asChild><Link to="/signers">Learn About Signers</Link></Button>
</CardContent>
</Card>
</div>