import {PlusIcon, XMarkIcon} from '@heroicons/react/24/solid' import {Editor} from '@tiptap/react' import clsx from 'clsx' import { DIET_CHOICES, EDUCATION_CHOICES, GENDERS, LANGUAGE_CHOICES, MBTI_CHOICES, POLITICAL_CHOICES, RACE_CHOICES, RELATIONSHIP_CHOICES, RELATIONSHIP_STATUS_CHOICES, RELIGION_CHOICES, ROMANTIC_CHOICES, } from 'common/choices' import {debug} from 'common/logger' import {MultipleChoiceOptions} from 'common/profiles/multiple-choice' import {Profile, ProfileWithoutUser} from 'common/profiles/profile' import {PLATFORM_LABELS, type Site, SITE_ORDER, Socials} from 'common/socials' import {BaseUser} from 'common/user' import {range} from 'lodash' import {Fragment, useEffect, useRef, useState} from 'react' import Textarea from 'react-expanding-textarea' import toast from 'react-hot-toast' import {AddOptionEntry} from 'web/components/add-option-entry' import {SignupBio} from 'web/components/bio/editable-bio' import {Button, IconButton} from 'web/components/buttons/button' import {Col} from 'web/components/layout/col' import {Row} from 'web/components/layout/row' import {MultiCheckbox} from 'web/components/multi-checkbox' import {City, CityRow, profileToCity, useCitySearch} from 'web/components/search-location' import {Carousel} from 'web/components/widgets/carousel' import {ChoicesToggleGroup} from 'web/components/widgets/choices-toggle-group' import {Input} from 'web/components/widgets/input' import {PlatformSelect} from 'web/components/widgets/platform-select' import {RadioToggleGroup} from 'web/components/widgets/radio-toggle-group' import {Select} from 'web/components/widgets/select' import {Slider} from 'web/components/widgets/slider' import {Title} from 'web/components/widgets/title' import {fetchChoices} from 'web/hooks/use-choices' import {useLocale, useT} from 'web/lib/locale' import {track} from 'web/lib/service/analytics' import {db} from 'web/lib/supabase/db' import {colClassName, labelClassName} from 'web/pages/signup' import {SocialIcon} from './user/social' import {AddPhotosWidget} from './widgets/add-photos' export const OptionalProfileUserForm = (props: { profile: ProfileWithoutUser setProfile: (key: K, value: ProfileWithoutUser[K]) => void user: BaseUser buttonLabel?: string bottomNavBarVisible?: boolean onSubmit: () => Promise }) => { const {profile, user, buttonLabel, setProfile, onSubmit, bottomNavBarVisible = true} = props const [isSubmitting, setIsSubmitting] = useState(false) const [lookingRelationship, setLookingRelationship] = useState( (profile.pref_relation_styles || []).includes('relationship'), ) const [ageError, setAgeError] = useState(null) const t = useT() const [heightFeet, setHeightFeet] = useState( profile.height_in_inches ? Math.floor((profile['height_in_inches'] ?? 0) / 12) : undefined, ) const [heightInches, setHeightInches] = useState( profile.height_in_inches ? Math.floor((profile['height_in_inches'] ?? 0) % 12) : undefined, ) const [newLinkPlatform, setNewLinkPlatform] = useState('') const [newLinkValue, setNewLinkValue] = useState('') const [interestChoices, setInterestChoices] = useState({}) const [causeChoices, setCauseChoices] = useState({}) const [workChoices, setWorkChoices] = useState({}) const {locale} = useLocale() const [keywordsString, setKeywordsString] = useState(profile.keywords?.join(', ') || '') useEffect(() => { fetchChoices('interests', locale).then(setInterestChoices) fetchChoices('causes', locale).then(setCauseChoices) fetchChoices('work', locale).then(setWorkChoices) }, [db]) const errorToast = () => { toast.error(t('profile.optional.error.invalid_fields', 'Some fields are incorrect...')) } const handleSubmit = async () => { // Validate age before submitting if (profile['age'] !== null && profile['age'] !== undefined) { if (profile['age'] < 18) { setAgeError(t('profile.optional.age.error_min', 'You must be at least 18 years old')) setIsSubmitting(false) errorToast() return } if (profile['age'] > 100) { setAgeError(t('profile.optional.age.error_max', 'Please enter a valid age')) setIsSubmitting(false) errorToast() return } } setIsSubmitting(true) track('submit optional profile') await onSubmit() setIsSubmitting(false) } const updateUserLink = (platform: string, value: string | null) => { setProfile('links', {...((profile.links as Socials) ?? {}), [platform]: value}) } const addNewLink = () => { if (newLinkPlatform && newLinkValue) { updateUserLink(newLinkPlatform.toLowerCase().trim(), newLinkValue.trim()) setNewLinkPlatform('') setNewLinkValue('') } } function setProfileCity(inputCity: City | undefined) { if (!inputCity) { setProfile('geodb_city_id', null) setProfile('city', '') setProfile('region_code', null) setProfile('country', null) setProfile('city_latitude', null) setProfile('city_longitude', null) } else { const { geodb_city_id, city, region_code, country, latitude: city_latitude, longitude: city_longitude, } = inputCity setProfile('geodb_city_id', geodb_city_id) setProfile('city', city) setProfile('region_code', region_code) setProfile('country', country) setProfile('city_latitude', city_latitude) setProfile('city_longitude', city_longitude) } } function profileToRaisedInCity(profile: Profile): City | undefined { if (profile.raised_in_geodb_city_id && profile.raised_in_lat && profile.raised_in_lon) { return { geodb_city_id: profile.raised_in_geodb_city_id, city: profile.raised_in_city ?? null, region_code: profile.raised_in_region_code ?? '', country: profile.raised_in_country ?? '', country_code: '', latitude: profile.raised_in_lat, longitude: profile.raised_in_lon, } } return undefined } function setProfileRaisedInCity(inputCity: City | undefined) { if (!inputCity) { setProfile('raised_in_geodb_city_id', null) setProfile('raised_in_city', null) setProfile('raised_in_region_code', null) setProfile('raised_in_country', null) setProfile('raised_in_lat', null) setProfile('raised_in_lon', null) } else { const {geodb_city_id, city, region_code, country, latitude, longitude} = inputCity setProfile('raised_in_geodb_city_id', geodb_city_id) setProfile('raised_in_city', city) setProfile('raised_in_region_code', region_code) setProfile('raised_in_country', country) setProfile('raised_in_lat', latitude) setProfile('raised_in_lon', longitude) } } return ( <> {/**/} {/* */} {/* {buttonLabel ?? t('common.next', 'Next')} / {t('common.skip', 'Skip')}*/} {/* */} {/**/} {t('profile.optional.subtitle', 'Optional information')} {profile.city ? ( {}} className="pointer-events-none" /> ) : ( { setProfileCity(city) }} /> )} [t(`profile.gender.${v}`, k), v]), ) as any } setChoice={(c) => setProfile('gender', c)} /> ) => { const value = e.target.value ? Number(e.target.value) : null if (value !== null && value < 18) { setAgeError( t('profile.optional.age.error_min', 'You must be at least 18 years old'), ) } else if (value !== null && value > 100) { setAgeError(t('profile.optional.age.error_max', 'Please enter a valid age')) } else { setAgeError(null) } setProfile('age', value) }} /> {ageError &&

{ageError}

} {t('profile.optional.feet', 'Feet')} ) => { if (e.target.value === '') { setHeightFeet(undefined) } else { setHeightFeet(Number(e.target.value)) const heightInInches = Number(e.target.value) * 12 + (heightInches ?? 0) setProfile('height_in_inches', heightInInches) } }} className={'w-16'} value={typeof heightFeet === 'number' ? Math.floor(heightFeet) : ''} min={0} /> {t('profile.optional.inches', 'Inches')} ) => { if (e.target.value === '') { setHeightInches(undefined) } else { setHeightInches(Number(e.target.value)) const heightInInches = Number(e.target.value) + 12 * (heightFeet ?? 0) setProfile('height_in_inches', heightInInches) } }} className={'w-16'} value={typeof heightInches === 'number' ? Math.floor(heightInches) : ''} min={0} />
{t('common.or', 'OR').toUpperCase()}
{t('profile.optional.centimeters', 'Centimeters')} ) => { if (e.target.value === '') { setHeightFeet(undefined) setHeightInches(undefined) setProfile('height_in_inches', null) } else { // Convert cm to inches const totalInches = Number(e.target.value) / 2.54 setHeightFeet(Math.floor(totalInches / 12)) setHeightInches(totalInches % 12) setProfile('height_in_inches', totalInches) } }} className={'w-20'} value={ heightFeet !== undefined && profile['height_in_inches'] ? Math.round(profile['height_in_inches'] * 2.54) : '' } min={0} />
setProfile('ethnicity', selected)} /> {profile.raised_in_geodb_city_id ? ( {}} className="pointer-events-none" /> ) : ( { setProfileRaisedInCity(city) }} /> )}