Signup: require a display name (changeable later), remove skip

Per request, a display name is now mandatory when signing up:
- Removed the "Skip for now" button from the profile step — the only forward
  path is Save, which is disabled until a non-empty name is entered.
- Marked the field required (*), added helper copy ("Required — how you'll show
  up across SkateSpots. Change it anytime."), and a hint under the button.
- finishSignup guards against an empty/whitespace name (defense-in-depth for
  keyboard/Enter), trims the name before publishing kind 0.
- Reworded the step copy: name required, bio + avatar still optional.

Only affects the primary nsec signup dialog (also the endpoint the mnemonic
flow feeds into); the mnemonic dialog has no name step.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
shakespeare.diy 2026-09-03 18:32:08 +07:00
parent 39afc00b6e
commit 3833625bde

View file

@ -152,14 +152,26 @@ const SignupDialog: React.FC<SignupDialogProps> = ({ isOpen, onClose, onComplete
};
const finishSignup = async (skipProfile = false) => {
// A display name is mandatory (changeable later). Guard here too so the step
// can't be completed without one, even via keyboard/Enter.
const trimmedName = profileData.name.trim();
if (!skipProfile && !trimmedName) {
toast({
title: 'Display name required',
description: 'Pick a display name so other skaters know who you are. You can change it anytime.',
variant: 'destructive',
});
return;
}
// Mark signup completion time for fallback welcome modal
localStorage.setItem('signup_completed', Date.now().toString());
try {
// Publish profile if user provided information
if (!skipProfile && (profileData.name || profileData.about || profileData.picture)) {
if (!skipProfile && (trimmedName || profileData.about || profileData.picture)) {
const metadata: Record<string, string> = {};
if (profileData.name) metadata.name = profileData.name;
if (trimmedName) metadata.name = trimmedName;
if (profileData.about) metadata.about = profileData.about;
if (profileData.picture) metadata.picture = profileData.picture;
@ -365,11 +377,11 @@ const SignupDialog: React.FC<SignupDialogProps> = ({ isOpen, onClose, onComplete
<div className='relative z-10 space-y-2'>
<p className='text-base font-semibold'>
You're in! 🛹 Add a name so skaters know who you are
You're in! 🛹 Pick a display name so skaters know who you are
</p>
<p className='text-sm text-muted-foreground'>
This is optional — you can skip it and fill it in later.
You can change it anytime later. Bio and avatar are optional.
</p>
</div>
</div>
@ -390,16 +402,22 @@ const SignupDialog: React.FC<SignupDialogProps> = ({ isOpen, onClose, onComplete
<div className={`space-y-4 text-left ${isPublishing ? 'opacity-50 pointer-events-none' : ''}`}>
<div className='space-y-2'>
<label htmlFor='profile-name' className='text-sm font-medium'>
Display Name
Display Name <span className='text-red-500'>*</span>
</label>
<Input
id='profile-name'
value={profileData.name}
onChange={(e) => setProfileData(prev => ({ ...prev, name: e.target.value }))}
placeholder='Your name'
placeholder='e.g. Tony, gnarlyGrind, or your crew name'
className='rounded-lg'
maxLength={64}
required
aria-required='true'
disabled={isPublishing}
/>
<p className='text-xs text-muted-foreground'>
Required — how you'll show up across SkateSpots. Change it anytime.
</p>
</div>
<div className='space-y-2'>
@ -456,12 +474,12 @@ const SignupDialog: React.FC<SignupDialogProps> = ({ isOpen, onClose, onComplete
</div>
</div>
{/* Action buttons */}
{/* Action button — a display name is required to continue. */}
<div className='space-y-3'>
<Button
className='w-full rounded-full py-4 text-base font-semibold bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 transform transition-all duration-200 hover:scale-105 shadow-lg disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none'
className='w-full rounded-full py-4 text-base font-semibold bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 transform transition-all duration-200 hover:scale-105 shadow-lg disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none disabled:hover:scale-100'
onClick={() => finishSignup(false)}
disabled={isPublishing || isUploading}
disabled={isPublishing || isUploading || !profileData.name.trim()}
>
{isPublishing ? (
<>
@ -476,21 +494,11 @@ const SignupDialog: React.FC<SignupDialogProps> = ({ isOpen, onClose, onComplete
)}
</Button>
<Button
variant='outline'
className='w-full rounded-full py-3 disabled:opacity-50 disabled:cursor-not-allowed'
onClick={() => finishSignup(true)}
disabled={isPublishing || isUploading}
>
{isPublishing ? (
<>
<div className='w-4 h-4 mr-2 border-2 border-current border-t-transparent rounded-full animate-spin' />
Setting up account...
</>
) : (
'Skip for now'
)}
</Button>
{!profileData.name.trim() && !isPublishing && (
<p className='text-center text-xs text-muted-foreground'>
Add a display name to continue.
</p>
)}
</div>
</div>
)}