Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion lib/components/core/map/place-autocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@ export function PlaceAutoComplete({
value,
onSelect,
autoFocus,
error,
hint,
}: {
label?: string;
placeholder?: string;
value?: string;
onSelect?: (address: Address | undefined) => void;
autoFocus?: boolean;
error?: boolean;
hint?: string;
}) {
const [toggle, setToggle] = React.useState(false);
const [query, setQuery] = React.useState('');
Expand Down Expand Up @@ -84,8 +88,10 @@ export function PlaceAutoComplete({
label={label}
autoFocus={autoFocus}
iconLeft="icon-location-outline text-tertiary"
right={{ icon: 'icon-cancel text-tertiary size-5 cursor-pointer', onClick: handleClear }}
right={query ? { icon: 'icon-cancel text-tertiary size-5 cursor-pointer', onClick: handleClear } : undefined}
value={query}
error={error}
hint={hint}
placeholder={placeholder}
onChange={(e) => {
setQuery(e.currentTarget.value);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { useState, useEffect } from "react";
import { useState, useEffect } from 'react';

import { Button, Input, LabeledInput, ModalContent, modal, Toggle, Select } from "$lib/components/core";
import { ApplicationProfileField } from "$lib/graphql/generated/backend/graphql";
import { Button, Input, LabeledInput, ModalContent, modal, Toggle, Select } from '$lib/components/core';
import { ApplicationProfileField } from '$lib/graphql/generated/backend/graphql';

import { AddQuestionModal } from "./AddQuestionModal";
import { useSaveApplicationProfileField } from "../hooks";
import { AddQuestionModal } from './AddQuestionModal';
import { useSaveApplicationProfileField } from '../hooks';

const INFO_OPTIONS = ['Bio', 'Location', 'Pronouns'];

const FIELD_CONFIG: Record<string, { field: string; defaultQuestion: string }> = {
'Bio': { field: 'description', defaultQuestion: 'Tell us about yourself' },
// 'Location': { field: 'location_line', defaultQuestion: 'Where are you based?' },
'Pronouns': { field: 'pronoun', defaultQuestion: 'What are your pronouns?' }
Bio: { field: 'description', defaultQuestion: 'Tell us about yourself' },
// Location: { field: 'location_line', defaultQuestion: 'Where are you based?' },
Location: { field: 'addresses', defaultQuestion: 'Where are you based?' },
Pronouns: { field: 'pronoun', defaultQuestion: 'What are your pronouns?' },
};

interface AddPersonalDetailsQuestionProps {
Expand All @@ -21,14 +22,14 @@ interface AddPersonalDetailsQuestionProps {
export function AddPersonalDetailsQuestion({ field }: AddPersonalDetailsQuestionProps) {
const getInitialInfoType = () => {
if (!field) return INFO_OPTIONS[0];

const fieldConfig = Object.entries(FIELD_CONFIG).find(([_, config]) => config.field === field.field);
return fieldConfig ? fieldConfig[0] : INFO_OPTIONS[0];
};

const getInitialQuestion = () => {
if (field?.question) return field.question;

const infoType = getInitialInfoType();
return FIELD_CONFIG[infoType]?.defaultQuestion || INFO_OPTIONS[0];
};
Expand All @@ -37,7 +38,7 @@ export function AddPersonalDetailsQuestion({ field }: AddPersonalDetailsQuestion
const [required, setRequired] = useState<boolean>(field?.required || false);
const [selectedInfoType, setSelectedInfoType] = useState<string>(getInitialInfoType());
const { saveApplicationProfileField, loading } = useSaveApplicationProfileField();

useEffect(() => {
if (field) {
const infoType = getInitialInfoType();
Expand All @@ -46,17 +47,17 @@ export function AddPersonalDetailsQuestion({ field }: AddPersonalDetailsQuestion
setRequired(field.required || false);
}
}, [field]);

const handleSaveClick = () => {
const fieldConfig = FIELD_CONFIG[selectedInfoType];
if (!fieldConfig) {
return;
}

const questionText = question || fieldConfig.defaultQuestion || selectedInfoType;
saveApplicationProfileField(fieldConfig.field, required, questionText);
};

return (
<ModalContent
title={'Add Question'}
Expand Down Expand Up @@ -96,23 +97,17 @@ export function AddPersonalDetailsQuestion({ field }: AddPersonalDetailsQuestion
/>
</LabeledInput>
<LabeledInput label="Question">
<Input
variant="outlined"
value={question}
onChange={(e) => setQuestion(e.target.value)}
/>
<p className="text-sm text-secondary">We'll automatically get this information from their profile if available.</p>
<Input variant="outlined" value={question} onChange={(e) => setQuestion(e.target.value)} />
<p className="text-sm text-secondary">
We'll automatically get this information from their profile if available.
</p>
</LabeledInput>
<div className="flex items-center justify-between">
<p className="text-sm text-secondary">Required</p>
<Toggle
id="required"
checked={required}
onChange={(value) => setRequired(value)}
/>
<Toggle id="required" checked={required} onChange={(value) => setRequired(value)} />
</div>
<Button
variant="secondary"
<Button
variant="secondary"
className="w-full"
onClick={handleSaveClick}
disabled={!selectedInfoType.trim()}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export function AddQuestionModal() {
className="justify-start"
onClick={() => {
modal.close();
modal.open(AddPersonalDetailsQuestion);
modal.open(AddPersonalDetailsQuestion, { className: 'overflow-visible' });
}}
>
Personal Details
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
import { ApplicationProfileField } from "$lib/graphql/generated/backend/graphql";
import { modal } from "$lib/components/core";
import { AddJobTitleQuestion } from "./AddJobTitleQuestion";
import { AddOrganizationQuestion } from "./AddOrganizationQuestion";
import { AddPersonalDetailsQuestion } from "./AddPersonalDetailsQuestion";
import { AddSocialProfileQuestion } from "./AddSocialProfileQuestion";
import { AddWebsiteQuestion } from "./AddWebsiteQuestion";
import { ApplicationProfileField } from '$lib/graphql/generated/backend/graphql';
import { modal } from '$lib/components/core';
import { AddJobTitleQuestion } from './AddJobTitleQuestion';
import { AddOrganizationQuestion } from './AddOrganizationQuestion';
import { AddPersonalDetailsQuestion } from './AddPersonalDetailsQuestion';
import { AddSocialProfileQuestion } from './AddSocialProfileQuestion';
import { AddWebsiteQuestion } from './AddWebsiteQuestion';

const FIELD_LABELS: Record<string, string> = {
'job_title': 'Job Title',
'company_name': 'Organization',
'description': 'Bio',
'location_line': 'Location',
'pronoun': 'Pronouns',
'website': 'Website',
'handle_twitter': 'X (Twitter)',
'handle_linkedin': 'LinkedIn',
'handle_farcaster': 'Farcaster',
'handle_instagram': 'Instagram',
'handle_github': 'Github',
'calendly_url': 'Calendly'
job_title: 'Job Title',
company_name: 'Organization',
description: 'Bio',
location_line: 'Location',
addresses: 'Location',
pronoun: 'Pronouns',
website: 'Website',
handle_twitter: 'X (Twitter)',
handle_linkedin: 'LinkedIn',
handle_farcaster: 'Farcaster',
handle_instagram: 'Instagram',
handle_github: 'Github',
calendly_url: 'Calendly',
};

export function ApplicationProfileCard({ field }: { field: ApplicationProfileField; }) {
export function ApplicationProfileCard({ field }: { field: ApplicationProfileField }) {
const getFieldLabel = (fieldName: string) => {
return FIELD_LABELS[fieldName] || fieldName;
};
Expand All @@ -39,6 +40,7 @@ export function ApplicationProfileCard({ field }: { field: ApplicationProfileFie
break;
case 'description':
case 'location_line':
case 'addresses':
case 'pronoun':
modal.open(AddPersonalDetailsQuestion, { props: { field } });
break;
Expand Down Expand Up @@ -70,10 +72,8 @@ export function ApplicationProfileCard({ field }: { field: ApplicationProfileFie
</div>
</div>

<i
className="icon-edit-sharp size-5 text-tertiary cursor-pointer"
onClick={() => handleEdit(field)}
/>
<i className="icon-edit-sharp size-5 text-tertiary cursor-pointer" onClick={() => handleEdit(field)} />
</div>
);
}
}

73 changes: 47 additions & 26 deletions lib/components/features/event-registration/forms/UserInfoForm.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { useForm, UseFormRegister, FieldErrors, Control, FieldError } from 'react-hook-form';
import { useForm, Controller, UseFormReturn, FieldError } from 'react-hook-form';
import * as React from 'react';

import { UserInput, ApplicationProfileField } from '$lib/graphql/generated/backend/graphql';
import { Input, LabeledInput, SelectController } from '$lib/components/core';
import { formInstancesAtom, requiredProfileFieldsAtom, submitHandlersAtom, useAtomValue, userInfoAtom, useSetAtom } from '../store';
import { Input, LabeledInput, PlaceAutoComplete, SelectController } from '$lib/components/core';
import {
formInstancesAtom,
requiredProfileFieldsAtom,
submitHandlersAtom,
useAtomValue,
userInfoAtom,
useSetAtom,
} from '../store';
import { useMe } from '$lib/hooks/useMe';
import { ETHNICITIES, INDUSTRY_OPTIONS, PRONOUNS } from '$lib/utils/constants';

Expand Down Expand Up @@ -33,6 +40,7 @@ export function UserForm() {
calendly_url: me?.calendly_url,
ethnicity: me?.ethnicity,
industry: me?.industry,
addresses: me?.addresses,
},
mode: 'onChange',
});
Expand All @@ -42,25 +50,21 @@ export function UserForm() {
};

React.useEffect(() => {
setFormInstances(prev => ({ ...prev, userInfo: form }));
setSubmitHandlers(prev => ({ ...prev, userInfo: onSubmit }));
setFormInstances((prev) => ({ ...prev, userInfo: form }));
setSubmitHandlers((prev) => ({ ...prev, userInfo: onSubmit }));
}, []);

if (!requiredProfileFields?.length) return <></>;

const { register, formState: { errors }, control } = form;

return (
<>
{requiredProfileFields.map((profileField) => (
<ProfileField
key={profileField.field}
profileField={profileField}
name={profileField.field as keyof UserInput}
register={register}
errors={errors}
control={control}
required={!!profileField.required}
form={form}
/>
))}
</>
Expand All @@ -70,18 +74,21 @@ export function UserForm() {
function ProfileField({
profileField,
name,
register,
errors,
control,
required
required,
form,
}: {
profileField: ApplicationProfileField;
name: keyof UserInput;
register: UseFormRegister<UserInput>;
errors: FieldErrors<UserInput>;
control: Control<UserInput>;
required?: boolean;
form: UseFormReturn<UserInput>;
}) {
const {
setValue,
control,
register,
formState: { errors },
} = form;

const getFieldLabel = (fieldName: string) => {
const labels: Record<string, string> = {
display_name: 'Name',
Expand All @@ -103,9 +110,10 @@ function ProfileField({
ethnicity: 'Ethnicity / Race',
industry: 'Industry',
date_of_birth: 'Date of Birth',
email: 'Email'
email: 'Email',
addresses: 'Location',
};

return labels[fieldName] || fieldName;
};

Expand Down Expand Up @@ -140,13 +148,26 @@ function ProfileField({
);
}

return (
<Input
{...register(name, { required })}
placeholder={placeholder}
error={!!errors[name]}
/>
);
if (name === 'addresses') {
return (
<Controller
control={control}
name="addresses"
rules={{ required }}
render={({ field }) => {
return (
<PlaceAutoComplete
error={!!errors[name]}
value={field.value?.[0]?.title || ''}
onSelect={(value) => (value ? setValue('addresses', [value]) : setValue('addresses', []))}
/>
);
}}
/>
);
}

return <Input {...register(name, { required })} placeholder={placeholder} error={!!errors[name]} />;
};

return (
Expand Down
6 changes: 3 additions & 3 deletions lib/graphql/generated/backend/gql.ts

Large diffs are not rendered by default.

Loading