Skip to content

Commit

Permalink
[chore] address feedback for onboarding (#90)
Browse files Browse the repository at this point in the history
* update language option text, remove upper limit on hrs/month, add char limit to availability desc, add comment for legal credential

* add legal credential comment to settings

* make discard changes red; fix issue with same value radio input

* modify hooks to prevent recursive checking in roles page

* make comment error instant

* make availability error instant

* address feedback

* chore: removes periods from the inputs' error messages

---------

Co-authored-by: Alvaro Ortiz <[email protected]>
  • Loading branch information
jinkang-0 and varortz authored May 24, 2024
1 parent 67aebb5 commit cd5cd20
Show file tree
Hide file tree
Showing 16 changed files with 296 additions and 65 deletions.
20 changes: 17 additions & 3 deletions src/app/onboarding/availability/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { FormControl, FormField, FormItem, FormLabel } from '@/components/Form';
import Icon from '@/components/Icon';
import TextAreaInput from '@/components/TextAreaInput';
import TextInput from '@/components/TextInput';
import { availabilitySchema } from '@/data/formSchemas';
import { availabilitySchema, CHAR_LIMIT_MSG } from '@/data/formSchemas';
import { CardForm, Flex } from '@/styles/containers';
import { H1Centered } from '@/styles/text';
import {
Expand All @@ -31,6 +31,8 @@ export default function Page() {
const onboarding = useGuardedOnboarding();
const { backlinkHref, ebbTo, pageProgress } = useOnboardingNavigation();
const { push } = useRouter();
const [availabilityError, setAvailabilityError] = useState('');
const [hoursError, setHoursError] = useState('');

// scroll to top
useScrollToTop();
Expand Down Expand Up @@ -106,7 +108,7 @@ export default function Page() {
</FormLabel>
<FormControl>
<TextInput
errorText={fieldState.error?.message}
errorText={fieldState.error?.message ?? hoursError}
placeholder="x hours per month"
inputMode="numeric"
defaultValue={
Expand All @@ -118,12 +120,21 @@ export default function Page() {
onboarding.updateProfile({
hours_per_month: undefined,
});
setHoursError('');
return;
}

const toNum = z.coerce.number().safeParse(newValue);
const num = toNum.success ? toNum.data : undefined;

if (num === undefined) {
setHoursError('Hours per month must be a number.');
} else if (num < 0) {
setHoursError('Hours per month cannot be negative.');
} else {
setHoursError('');
}

field.onChange(num);
onboarding.updateProfile({
hours_per_month: num,
Expand Down Expand Up @@ -184,8 +195,11 @@ export default function Page() {
<TextAreaInput
placeholder="I won't be available from..."
defaultValue={field.value ?? ''}
error={fieldState.error?.message}
error={fieldState.error?.message ?? availabilityError}
onChange={newValue => {
setAvailabilityError(
newValue.length > 400 ? CHAR_LIMIT_MSG : '',
);
onboarding.updateProfile({
availability_description: newValue,
});
Expand Down
108 changes: 91 additions & 17 deletions src/app/onboarding/legal-credentials/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

import { useEffect, useMemo } from 'react';
import { useEffect, useMemo, useState } from 'react';
import { zodResolver } from '@hookform/resolvers/zod';
import { useRouter } from 'next/navigation';
import { FormProvider, useForm } from 'react-hook-form';
Expand All @@ -17,9 +17,10 @@ import {
import Icon from '@/components/Icon';
import InputDropdown from '@/components/InputDropdown';
import RadioGroup from '@/components/RadioGroup';
import TextAreaInput from '@/components/TextAreaInput';
import TextInput from '@/components/TextInput';
import { usStates } from '@/data/citiesAndStates';
import { attorneyCredentialSchema } from '@/data/formSchemas';
import { attorneyCredentialSchema, CHAR_LIMIT_MSG } from '@/data/formSchemas';
import { CardForm, Flex } from '@/styles/containers';
import { H1Centered } from '@/styles/text';
import { formatTruthy, identity } from '@/utils/helpers';
Expand All @@ -34,6 +35,7 @@ export default function Page() {
const onboarding = useGuardedOnboarding();
const { backlinkHref, ebbTo, pageProgress } = useOnboardingNavigation();
const { push } = useRouter();
const [commentError, setCommentError] = useState('');

// scroll to top
useScrollToTop();
Expand All @@ -45,14 +47,18 @@ export default function Page() {
stateBarred: onboarding.profile.state_barred ?? undefined,
barNumber: onboarding.profile.bar_number ?? undefined,
eoirRegistered: onboarding.profile.eoir_registered ?? undefined,
legalCredentialComment:
onboarding.profile.legal_credential_comment ?? undefined,
barred: onboarding.profile.has_bar_number ?? undefined,
},
});

const formValues = form.watch();
const isEmpty = useMemo(
() =>
!(formValues.stateBarred && formValues.barNumber) ||
formValues.eoirRegistered === undefined,
formValues.eoirRegistered === undefined ||
(!formValues.barred && !formValues.legalCredentialComment),
[formValues],
);

Expand Down Expand Up @@ -108,8 +114,8 @@ export default function Page() {
/>
</FormControl>
<FormDescription>
If you are barred in multiple states, choose your preferred
state
If you are barred in multiple states, please choose your
preferred state
</FormDescription>
<FormMessage />
</FormItem>
Expand All @@ -118,30 +124,65 @@ export default function Page() {

<FormField
control={form.control}
name="barNumber"
name="barred"
render={({ field, fieldState }) => (
<FormItem>
<FormLabel>
What is your attorney bar number in this state?
</FormLabel>
<FormLabel>Do you have a bar number in this state?</FormLabel>
<FormControl>
<TextInput
errorText={fieldState.error?.message}
placeholder="123456"
type="text"
defaultValue={field.value}
<RadioGroup
name="barred"
defaultValue={formatTruthy(
field.value,
'Yes',
'No',
undefined,
)}
options={['Yes', 'No']}
error={fieldState.error?.message}
onChange={newValue => {
const bool = newValue === 'Yes';
const barNum = bool ? '' : 'N/A';
onboarding.updateProfile({
bar_number: newValue,
has_bar_number: bool,
bar_number: barNum,
});
field.onChange(newValue);
form.setValue('barNumber', barNum);
field.onChange(bool);
}}
/>
</FormControl>
</FormItem>
)}
/>

{formValues.barred && (
<FormField
control={form.control}
name="barNumber"
render={({ field, fieldState }) => (
<FormItem>
<FormLabel>
What is your attorney bar number in this state?
</FormLabel>
<FormControl>
<TextInput
errorText={fieldState.error?.message}
placeholder="123456"
type="text"
defaultValue={field.value}
onChange={newValue => {
onboarding.updateProfile({
bar_number: newValue,
});
field.onChange(newValue);
}}
/>
</FormControl>
</FormItem>
)}
/>
)}

<FormField
control={form.control}
name="eoirRegistered"
Expand All @@ -153,7 +194,7 @@ export default function Page() {
</FormLabel>
<FormControl>
<RadioGroup
name="registered"
name="eoirRegistered"
defaultValue={formatTruthy(
field.value,
'Yes',
Expand All @@ -173,6 +214,39 @@ export default function Page() {
)}
/>

<FormField
control={form.control}
name="legalCredentialComment"
render={({ field, fieldState }) => (
<FormItem>
<FormLabel $required={!formValues.barred}>
Is there anything about your bar status we should know?
{formValues.barred && ' (optional)'}
</FormLabel>
<FormControl>
<TextAreaInput
placeholder="There are some extenuating circumstances with..."
defaultValue={field.value ?? ''}
error={fieldState.error?.message ?? commentError}
onChange={newValue => {
setCommentError(
newValue.length > 400 ? CHAR_LIMIT_MSG : '',
);
onboarding.updateProfile({
legal_credential_comment: newValue,
});
field.onChange(newValue);
}}
/>
</FormControl>
<FormDescription>
For example, if you were formerly barred but are not
currently; or, if your state does not have a bar number.
</FormDescription>
</FormItem>
)}
/>

<Flex $gap="40px">
<BigButton type="button" onClick={() => ebbTo(backlinkHref)}>
Back
Expand Down
18 changes: 16 additions & 2 deletions src/app/onboarding/review/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,18 @@ export default function Page() {
</Flex>
<Flex>
<Styles.SectionField>
<H4>What is your attorney bar number?</H4>
<P>{onboarding.profile.bar_number || 'N/A'}</P>
<H4>Do you have a bar number in this state?</H4>
<P>{onboarding.profile.has_bar_number ? 'Yes' : 'No'}</P>
</Styles.SectionField>
</Flex>
{onboarding.profile.has_bar_number && (
<Flex>
<Styles.SectionField>
<H4>What is your attorney bar number?</H4>
<P>{onboarding.profile.bar_number || 'N/A'}</P>
</Styles.SectionField>
</Flex>
)}
<Flex>
<Styles.SectionField>
<H4>
Expand All @@ -173,6 +181,12 @@ export default function Page() {
</P>
</Styles.SectionField>
</Flex>
<Flex>
<Styles.SectionField>
<H4>Is there anything about your bar status we should know?</H4>
<P>{onboarding.profile.legal_credential_comment ?? 'N/A'}</P>
</Styles.SectionField>
</Flex>
</Styles.SectionBox>
)}

Expand Down
1 change: 1 addition & 0 deletions src/app/onboarding/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export const SectionField = styled.div<{ $optional?: boolean }>`
flex-direction: column;
gap: 16px;
width: 100%;
overflow-wrap: break-word;
& > h4 {
${({ $optional }) =>
Expand Down
9 changes: 5 additions & 4 deletions src/components/Buttons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ interface ButtonProps {
const ButtonStyles = css<ButtonProps>`
${sans.style}
appearance: none;
color: ${({ $primaryColor }) => ($primaryColor ? 'white' : COLORS.blueMid)};
color: ${({ $primaryColor, $secondaryColor }) =>
$primaryColor ? 'white' : $secondaryColor || COLORS.blueMid};
background: ${({ $primaryColor }) => $primaryColor || 'white'};
padding: 10px 20px;
border-radius: 5px;
Expand Down Expand Up @@ -85,9 +86,9 @@ const ButtonStyles = css<ButtonProps>`
}
&:active {
color: ${COLORS.greyMid};
border-color: ${COLORS.greyLight};
background: ${COLORS.greyLight};
color: ${COLORS.greyMid} !important;
border-color: ${COLORS.greyLight} !important;
background: ${COLORS.greyLight} !important;
}
`
: null};
Expand Down
4 changes: 2 additions & 2 deletions src/components/NavBar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ const navlinks: NavLink[] = [

export default function NavBar() {
const profile = useProfile();
if (!profile) throw new Error('Profile must be defined.');
if (!profile) throw new Error('Profile must be defined');

const currentPath = usePathname();

const auth = useAuth();
if (!auth) throw new Error('Auth must be defined.');
if (!auth) throw new Error('Auth must be defined');

const authButtonView = useMemo(() => {
if (profile.profileReady && auth.userId)
Expand Down
8 changes: 4 additions & 4 deletions src/components/RadioGroup/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ export default function RadioGroup({
)}
<GroupContainer>
{options.map(o => (
<RadioLabel key={o} htmlFor={o}>
<RadioLabel key={o} htmlFor={`${name}${o}`}>
<RadioInput
type="radio"
id={o}
id={`${name}${o}`}
name={name}
value={value}
checked={value ? value === o : undefined}
value={`${name}${o}`}
checked={value ? value === `${name}${o}` : undefined}
defaultChecked={defaultValue === o}
onChange={() => handleChange(o)}
/>
Expand Down
13 changes: 10 additions & 3 deletions src/components/SettingsSection/AvailabilitySection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { zodResolver } from '@hookform/resolvers/zod';
import { FormProvider, useForm } from 'react-hook-form';
import { z } from 'zod';
import { availabilitySchema } from '@/data/formSchemas';
import { availabilitySchema, CHAR_LIMIT_MSG } from '@/data/formSchemas';
import { Box } from '@/styles/containers';
import { Profile } from '@/types/schema';
import {
Expand Down Expand Up @@ -37,6 +37,7 @@ export default function AvailabilitySection() {
const [startDate, setStartDate] = useState<string>(
getDateDefault(profile.profileData ?? {}),
);
const [availabilityError, setAvailabilityError] = useState('');

const form = useForm<z.infer<typeof availabilitySchema>>({
resolver: zodResolver(availabilitySchema),
Expand Down Expand Up @@ -65,6 +66,7 @@ export default function AvailabilitySection() {
setIsEditing(false);
form.reset(getFormDefaults(profile.profileData ?? {}));
setStartDate(getDateDefault(profile.profileData ?? {}));
setAvailabilityError('');
}}
isSubmitting={form.formState.isSubmitting}
>
Expand Down Expand Up @@ -123,8 +125,13 @@ export default function AvailabilitySection() {
<TextAreaInput
placeholder="I won't be available from..."
defaultValue={field.value ?? ''}
error={fieldState.error?.message}
onChange={field.onChange}
error={fieldState.error?.message ?? availabilityError}
onChange={newValue => {
setAvailabilityError(
newValue.length > 400 ? CHAR_LIMIT_MSG : '',
);
field.onChange(newValue);
}}
/>
)}
/>
Expand Down
Loading

0 comments on commit cd5cd20

Please sign in to comment.