Clean forms and prevent from changing username after creation

This commit is contained in:
MartinBraquet
2025-09-08 22:35:57 +02:00
parent 4c1c7fc514
commit 8498480b9c
3 changed files with 168 additions and 154 deletions

View File

@@ -26,6 +26,8 @@ import {SocialIcon} from './user/social'
import {Select} from 'web/components/widgets/select'
import {City, CityRow, loverToCity, useCitySearch} from "web/components/search-location";
import {AddPhotosWidget} from './widgets/add-photos'
import {RadioToggleGroup} from "web/components/widgets/radio-toggle-group";
import {MultipleChoiceOptions} from "common/love/multiple-choice";
export const OptionalLoveUserForm = (props: {
lover: LoverRow
@@ -38,6 +40,7 @@ export const OptionalLoveUserForm = (props: {
const {lover, user, buttonLabel, setLover, fromSignup, onSubmit} = props
const [isSubmitting, setIsSubmitting] = useState(false)
const [lookingRelationship, setlookingRelationship] = useState(false)
const router = useRouter()
const [heightFeet, setHeightFeet] = useState<number | undefined>(
lover.height_in_inches
@@ -138,34 +141,23 @@ export const OptionalLoveUserForm = (props: {
return (
<>
<Row className={'justify-end'}>
<Button
disabled={isSubmitting}
loading={isSubmitting}
onClick={handleSubmit}
>
{buttonLabel ?? 'Next / Skip'}
</Button>
</Row>
{/*<Row className={'justify-end'}>*/}
{/* <Button*/}
{/* disabled={isSubmitting}*/}
{/* loading={isSubmitting}*/}
{/* onClick={handleSubmit}*/}
{/* >*/}
{/* {buttonLabel ?? 'Next / Skip'}*/}
{/* </Button>*/}
{/*</Row>*/}
<Title>More about me</Title>
<div className="text-ink-500 mb-6 text-lg">Optional information</div>
<Col className={'gap-8'}>
{/*<Col className={clsx(colClassName)}>*/}
{/* <label className={clsx(labelClassName)}>Looking for matches</label>*/}
{/* <ChoicesToggleGroup*/}
{/* currentChoice={lover.looking_for_matches}*/}
{/* choicesMap={{*/}
{/* Yes: true,*/}
{/* No: false,*/}
{/* }}*/}
{/* setChoice={(c) => setLover('looking_for_matches', c)}*/}
{/* />*/}
{/*</Col>*/}
<Col className={clsx(colClassName)}>
<label className={clsx(labelClassName)}>Your location</label>
<label className={clsx(labelClassName)}>Location</label>
{lover.city ? (
<Row className="border-primary-500 w-full justify-between rounded border px-4 py-2">
<CityRow
@@ -220,7 +212,7 @@ export const OptionalLoveUserForm = (props: {
</Row>
<Col className={clsx(colClassName)}>
<label className={clsx(labelClassName)}>Interested in</label>
<label className={clsx(labelClassName)}>Interested in connecting with</label>
<MultiCheckbox
choices={{
Women: 'female',
@@ -232,24 +224,8 @@ export const OptionalLoveUserForm = (props: {
/>
</Col>
{/*<Col className={clsx(colClassName)}>*/}
{/* <label className={clsx(labelClassName)}>Relationship style</label>*/}
{/* <MultiCheckbox*/}
{/* choices={{*/}
{/* Monogamous: 'mono',*/}
{/* Polyamorous: 'poly',*/}
{/* 'Open Relationship': 'open',*/}
{/* Other: 'other',*/}
{/* }}*/}
{/* selected={lover['pref_relation_styles']}*/}
{/* onChange={(selected) =>*/}
{/* setLover('pref_relation_styles', selected)*/}
{/* }*/}
{/* />*/}
{/*</Col>*/}
<Col className={clsx(colClassName)}>
<label className={clsx(labelClassName)}>Partner age range</label>
<label className={clsx(labelClassName)}>Aged between</label>
<Row className={'gap-2'}>
<Col>
<span>Min</span>
@@ -286,36 +262,6 @@ export const OptionalLoveUserForm = (props: {
</Row>
</Col>
{/*<Col className={clsx(colClassName)}>*/}
{/* <label className={clsx(labelClassName)}>*/}
{/* You want to have kids*/}
{/* </label>*/}
{/* <RadioToggleGroup*/}
{/* className={'w-44'}*/}
{/* choicesMap={MultipleChoiceOptions}*/}
{/* setChoice={(choice) => {*/}
{/* setLover('wants_kids_strength', choice)*/}
{/* }}*/}
{/* currentChoice={lover.wants_kids_strength ?? -1}*/}
{/* />*/}
{/*</Col>*/}
<Col className={clsx(colClassName)}>
<label className={clsx(labelClassName)}>Photos</label>
{/*<div className="mb-1">*/}
{/* A real or stylized photo of you is required.*/}
{/*</div>*/}
<AddPhotosWidget
user={user}
photo_urls={lover.photo_urls}
pinned_url={lover.pinned_url}
setPhotoUrls={(urls) => setLover('photo_urls', urls)}
setPinnedUrl={(url) => setLover('pinned_url', url)}
/>
</Col>
<Col className={clsx(colClassName, 'pb-4')}>
<label className={clsx(labelClassName)}>Socials</label>
@@ -408,21 +354,6 @@ export const OptionalLoveUserForm = (props: {
/>
</Col>
<Col className={clsx(colClassName)}>
<label className={clsx(labelClassName)}>Current number of kids</label>
<Input
type="number"
onChange={(e) => {
const value =
e.target.value === '' ? null : Number(e.target.value)
setLover('has_kids', value)
}}
className={'w-20'}
min={0}
value={lover['has_kids'] ?? undefined}
/>
</Col>
<Col className={clsx(colClassName)}>
<label className={clsx(labelClassName)}>Do you smoke?</label>
<ChoicesToggleGroup
@@ -562,8 +493,83 @@ export const OptionalLoveUserForm = (props: {
value={lover['occupation_title'] ?? undefined}
/>
</Col>
<Col className={clsx(colClassName)}>
<label className={clsx(labelClassName)}>Current number of kids</label>
<Input
type="number"
onChange={(e) => {
const value =
e.target.value === '' ? null : Number(e.target.value)
setLover('has_kids', value)
}}
className={'w-20'}
min={0}
value={lover['has_kids'] ?? undefined}
/>
</Col>
<Col className={clsx(colClassName)}>
<label className={clsx(labelClassName)}>Looking for a relationship?</label>
<ChoicesToggleGroup
currentChoice={lookingRelationship}
choicesMap={{Yes: true, No: false}}
setChoice={(c) => setlookingRelationship(c)}
/>
</Col>
{lookingRelationship && <>
<Col className={clsx(colClassName)}>
<label className={clsx(labelClassName)}>
You want to have kids
</label>
<RadioToggleGroup
className={'w-44'}
choicesMap={MultipleChoiceOptions}
setChoice={(choice) => {
setLover('wants_kids_strength', choice)
}}
currentChoice={lover.wants_kids_strength ?? -1}
/>
</Col>
<Col className={clsx(colClassName)}>
<label className={clsx(labelClassName)}>Relationship style</label>
<MultiCheckbox
choices={{
Monogamous: 'mono',
Polyamorous: 'poly',
'Open Relationship': 'open',
Other: 'other',
}}
selected={lover['pref_relation_styles']}
onChange={(selected) =>
setLover('pref_relation_styles', selected)
}
/>
</Col>
</>}
<Col className={clsx(colClassName)}>
<label className={clsx(labelClassName)}>Photos</label>
{/*<div className="mb-1">*/}
{/* A real or stylized photo of you is required.*/}
{/*</div>*/}
<AddPhotosWidget
user={user}
photo_urls={lover.photo_urls}
pinned_url={lover.pinned_url}
setPhotoUrls={(urls) => setLover('photo_urls', urls)}
setPinnedUrl={(url) => setLover('pinned_url', url)}
/>
</Col>
<Row className={'justify-end'}>
<Button
className="fixed bottom-4 right-4 z-50 text-xl"
disabled={isSubmitting}
loading={isSubmitting}
onClick={handleSubmit}

View File

@@ -1,4 +1,4 @@
import {useEffect, useRef, useState} from 'react'
import {useEffect} from 'react'
import {Title} from 'web/components/widgets/title'
import {Col} from 'web/components/layout/col'
import clsx from 'clsx'
@@ -85,6 +85,7 @@ export const RequiredLoveUserForm = (props: {
return (
<>
<Title>The Basics</Title>
{!loverCreatedAlready && <div className="text-ink-500 mb-6 text-lg">No endless formswrite your own bio, your own way.</div>}
<Col className={'gap-8'}>
<Col>
<label className={clsx(labelClassName)}>Display name</label>
@@ -104,35 +105,38 @@ export const RequiredLoveUserForm = (props: {
{errorName && <span className="text-error text-sm">{errorName}</span>}
</Col>
<Col>
<label className={clsx(labelClassName)}>Username</label>
<Row className={'items-center gap-2'}>
<Input
disabled={loadingUsername}
type="text"
placeholder="Username"
value={username}
onChange={(e) => {
updateUserState({username: e.target.value || ''})
}}
onBlur={updateUsername}
/>
{loadingUsername && <LoadingIndicator className={'ml-2'}/>}
</Row>
{errorUsername && (
<span className="text-error text-sm">{errorUsername}</span>
)}
</Col>
{!loverCreatedAlready && <>
<Col>
<label className={clsx(labelClassName)}>Username</label>
<Row className={'items-center gap-2'}>
<Input
disabled={loadingUsername}
type="text"
placeholder="Username"
value={username}
onChange={(e) => {
updateUserState({username: e.target.value || ''})
}}
onBlur={updateUsername}
/>
{loadingUsername && <LoadingIndicator className={'ml-2'}/>}
</Row>
{errorUsername && (
<span className="text-error text-sm">{errorUsername}</span>
)}
</Col>
<Col>
<label className={clsx(labelClassName)}>Bio</label>
<SignupBio
onChange={(e: JSONContent) => {
console.log('bio changed', e, lover.bio)
setLover('bio', e)
}}
/>
</Col>
<Col>
<label className={clsx(labelClassName)}>Bio</label>
<SignupBio
onChange={(e: JSONContent) => {
console.log('bio changed', e, lover.bio)
setLover('bio', e)
}}
/>
</Col>
</>
}
{onSubmit && (
<Row className={'justify-end'}>

View File

@@ -1,18 +1,19 @@
import { Lover, LoverRow } from 'common/love/lover'
import { Column } from 'common/supabase/utils'
import { User } from 'common/user'
import { OptionalLoveUserForm } from 'web/components/optional-lover-form'
import { RequiredLoveUserForm } from 'web/components/required-lover-form'
import { useLoverByUser } from 'web/hooks/use-lover'
import {Lover, LoverRow} from 'common/love/lover'
import {Column} from 'common/supabase/utils'
import {User} from 'common/user'
import {OptionalLoveUserForm} from 'web/components/optional-lover-form'
import {RequiredLoveUserForm} from 'web/components/required-lover-form'
import {useLoverByUser} from 'web/hooks/use-lover'
import Router from 'next/router'
import { useEffect, useState } from 'react'
import { Col } from 'web/components/layout/col'
import { useUser } from 'web/hooks/use-user'
import { api } from 'web/lib/api'
import {useEffect, useState} from 'react'
import {Col} from 'web/components/layout/col'
import {useUser} from 'web/hooks/use-user'
import {api} from 'web/lib/api'
import {LovePage} from "web/components/love-page";
export default function ProfilePage() {
const user = useUser()
const { lover } = useLoverByUser(user ?? undefined)
const {lover} = useLoverByUser(user ?? undefined)
useEffect(() => {
if (user === null || lover === null) {
@@ -20,49 +21,52 @@ export default function ProfilePage() {
}
}, [user])
return user && lover && <ProfilePageInner user={user} lover={lover} />
return user && lover && <ProfilePageInner user={user} lover={lover}/>
}
function ProfilePageInner(props: { user: User; lover: Lover }) {
const { user } = props
const {user} = props
const [lover, setLover] = useState<Lover>({
...props.lover,
user,
})
const setLoverState = <K extends Column<'lovers'>> (key: K, value: LoverRow[K] | undefined) => {
setLover((prevState) => ({ ...prevState, [key]: value }))
const setLoverState = <K extends Column<'lovers'>>(key: K, value: LoverRow[K] | undefined) => {
setLover((prevState) => ({...prevState, [key]: value}))
}
const [displayName, setDisplayName] = useState(user.name)
const [username, setUsername] = useState(user.username)
return (
<Col className="items-center">
<Col className={'bg-canvas-0 w-full max-w-2xl px-6 py-4'}>
<RequiredLoveUserForm
user={user}
setLover={setLoverState}
lover={lover}
loverCreatedAlready={true}
isSubmitting={false}
setEditUsername={setUsername}
setEditDisplayName={setDisplayName}
/>
<div className={'h-4'} />
<OptionalLoveUserForm
lover={lover}
user={user}
setLover={setLoverState}
buttonLabel={'Save'}
onSubmit={async () => {
api('me/update', {
name: displayName === user.name ? undefined : displayName,
username: username === user.username ? undefined : username,
})
}}
/>
<LovePage trackPageView={'profile'}>
<Col className="items-center">
<Col className={'w-full px-6 py-4'}>
<RequiredLoveUserForm
user={user}
setLover={setLoverState}
lover={lover}
loverCreatedAlready={true}
isSubmitting={false}
setEditUsername={setUsername}
setEditDisplayName={setDisplayName}
/>
<div className={'h-4'}/>
<OptionalLoveUserForm
lover={lover}
user={user}
setLover={setLoverState}
buttonLabel={'Save'}
onSubmit={async () => {
api('me/update', {
name: displayName === user.name ? undefined : displayName,
username: username === user.username ? undefined : username,
})
}}
/>
</Col>
</Col>
</Col>
</LovePage>
)
}