fix(ui): backup-reminder timing + stray X, and event spot-link layout

- BackupReminder: wait while the signup dialog is open (the key is minted
  mid-flow), so "Save your login" no longer pops before signup is finished.
  Uses a small non-reactive signup flag set by SignupDialog.
- BackupReminder: removed the custom close button — the Sheet already renders
  its own X (the sheet's close now snoozes for the session).
- CreateEventPage: the "Link to a Skate Spot" row no longer overlaps — the
  label/hint can shrink and the Select Spot button stays put.
This commit is contained in:
SkateSpots 2026-10-03 21:18:40 +07:00
parent 3d60798496
commit 90cb429dc3
4 changed files with 49 additions and 25 deletions

View file

@ -1,10 +1,11 @@
import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { AlertTriangle, X, Download, CheckCircle } from 'lucide-react';
import { AlertTriangle, Download, CheckCircle } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { useCurrentUser } from '@/hooks/useCurrentUser';
import { useLocalStorage } from '@/hooks/useLocalStorage';
import { backupConfirmedKey } from '@/lib/backup';
import { isSignupOpen } from '@/lib/uiFlags';
import { useTranslation } from '@/contexts/language';
import {
Sheet,
@ -42,18 +43,25 @@ export function BackupReminder() {
return;
}
// Show reminder if:
// 1. User is logged in
// 2. Not snoozed for THIS session (resets when they come back)
// 3. Not confirmed they backed up (the only permanent stop)
// Add a small delay so it doesn't immediately pop up on login.
const timer = setTimeout(() => {
// Wait out the signup dialog (the key is minted mid-flow), then show unless
// snoozed for this session or already confirmed.
let cancelled = false;
let timer: ReturnType<typeof setTimeout>;
const attempt = () => {
if (cancelled) return;
if (isSignupOpen()) {
timer = setTimeout(attempt, 2000);
return;
}
const snoozed = sessionStorage.getItem(BACKUP_SNOOZE_KEY) === 'true';
const shouldShow = !snoozed && !confirmed;
setShowReminder(shouldShow);
}, 2000);
setShowReminder(!snoozed && !confirmed);
};
timer = setTimeout(attempt, 2000);
return () => clearTimeout(timer);
return () => {
cancelled = true;
clearTimeout(timer);
};
}, [user, confirmed]);
const handleDismiss = () => {
@ -84,7 +92,7 @@ export function BackupReminder() {
if (!showReminder) return null;
return (
<Sheet open={showReminder} onOpenChange={setShowReminder}>
<Sheet open={showReminder} onOpenChange={(open) => { if (!open) handleDismiss(); }}>
<SheetContent
side="bottom"
className="rounded-t-2xl border-t-4 border-amber-500 bg-gradient-to-b from-amber-950/90 to-black/95 backdrop-blur-lg"
@ -105,14 +113,6 @@ export function BackupReminder() {
</SheetDescription>
</div>
</div>
<Button
variant="ghost"
size="icon"
onClick={handleDismiss}
className="ml-2 -mt-1 text-gray-500 hover:text-gray-300"
>
<X className="h-5 w-5" />
</Button>
</div>
</SheetHeader>

View file

@ -15,6 +15,7 @@ import { useLoginActions } from '@/hooks/useLoginActions';
import { useNostrPublish } from '@/hooks/useNostrPublish';
import { useUploadFile } from '@/hooks/useUploadFile';
import { useLocalStorage } from '@/hooks/useLocalStorage';
import { setSignupOpen } from '@/lib/uiFlags';
import { useCurrentUser } from '@/hooks/useCurrentUser';
import { backupConfirmedKey } from '@/lib/backup';
import { generateSecretKey, nip19 } from 'nostr-tools';
@ -346,6 +347,13 @@ const SignupDialog: React.FC<SignupDialogProps> = ({ isOpen, onClose, onComplete
}
}, [isOpen]);
// Tell the global backup reminder to wait while signup is open — the key is
// minted mid-flow, and the reminder belongs *after* the skater finishes.
useEffect(() => {
setSignupOpen(isOpen);
return () => setSignupOpen(false);
}, [isOpen]);
// Offer a handle derived from the display name until the skater edits it
// themselves (or has already claimed one).
useEffect(() => {

16
src/lib/uiFlags.ts Normal file
View file

@ -0,0 +1,16 @@
/**
* Tiny cross-component UI flags (module-level, non-reactive).
*
* Used so the global backup reminder can tell that the signup dialog is open and
* wait — the key is minted mid-flow, and the reminder belongs *after* the skater
* finishes, not while they're still choosing a name.
*/
let signupOpen = false;
export function setSignupOpen(value: boolean): void {
signupOpen = value;
}
export function isSignupOpen(): boolean {
return signupOpen;
}

View file

@ -648,10 +648,10 @@ export default function CreateEventPage() {
{/* Link to Spot from Map */}
<div className="space-y-3 p-4 rounded-lg border-2 border-[#ff0040]/30 bg-[#ff0040]/5">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<Map className="h-5 w-5 text-[#ff0040]" />
<div>
<div className="flex items-center justify-between gap-3">
<div className="flex items-center gap-2 min-w-0">
<Map className="h-5 w-5 text-[#ff0040] shrink-0" />
<div className="min-w-0">
<Label className="text-base font-bold text-[#ff0040]">{t('placesUi.createEvent.linkToSpot')}</Label>
<p className="text-xs text-gray-400">
{selectedSpot ? t('placesUi.createEvent.selectedSpot', { name: selectedSpot.title }) : t('placesUi.createEvent.selectSpotHint')}
@ -664,7 +664,7 @@ export default function CreateEventPage() {
size="sm"
onClick={() => setShowSpotSelector(!showSpotSelector)}
className={cn(
'border-[#ff0040]/50',
'shrink-0 border-[#ff0040]/50',
selectedSpot
? 'bg-[#ff0040] text-white hover:bg-[#ff0040]/90'
: 'text-[#ff0040] hover:bg-[#ff0040]/10'