|
| 1 | +import { Dispatch, FC, SetStateAction, useState } from 'react' |
| 2 | +import { toast } from 'react-toastify' |
| 3 | +import { bind, trim } from 'lodash' |
| 4 | +import classNames from 'classnames' |
| 5 | + |
| 6 | +import { |
| 7 | + Button, |
| 8 | + Collapsible, InputSelect, InputText, |
| 9 | +} from '~/libs/ui' |
| 10 | +import { |
| 11 | + CountryLookup, |
| 12 | + updateMemberProfileAsync, |
| 13 | + useCountryLookup, |
| 14 | + UserProfile, |
| 15 | +} from '~/libs/core' |
| 16 | + |
| 17 | +import styles from './MemberAddress.module.scss' |
| 18 | + |
| 19 | +interface MemberAddressProps { |
| 20 | + profile: UserProfile |
| 21 | +} |
| 22 | + |
| 23 | +const MemberAddress: FC<MemberAddressProps> = (props: MemberAddressProps) => { |
| 24 | + const countryLookup: CountryLookup[] | undefined |
| 25 | + = useCountryLookup() |
| 26 | + |
| 27 | + const [formValues, setFormValues]: [any, Dispatch<any>] = useState({ |
| 28 | + country: props.profile.homeCountryCode || props.profile.competitionCountryCode, |
| 29 | + ...props.profile.addresses ? props.profile.addresses[0] : {}, |
| 30 | + }) |
| 31 | + |
| 32 | + const [formErrors, setFormErrors]: [ |
| 33 | + { [key: string]: string }, |
| 34 | + Dispatch<SetStateAction<{ [key: string]: string }>> |
| 35 | + ] |
| 36 | + = useState<{ [key: string]: string }>({}) |
| 37 | + |
| 38 | + const [isSaving, setIsSaving]: [boolean, Dispatch<SetStateAction<boolean>>] |
| 39 | + = useState<boolean>(false) |
| 40 | + |
| 41 | + const [isFormChanged, setIsFormChanged]: [boolean, Dispatch<SetStateAction<boolean>>] |
| 42 | + = useState<boolean>(false) |
| 43 | + |
| 44 | + function handleFormValueChange(key: string, event: React.ChangeEvent<HTMLInputElement>): void { |
| 45 | + const oldFormValues = { ...formValues } |
| 46 | + |
| 47 | + setFormValues({ |
| 48 | + ...oldFormValues, |
| 49 | + [key]: event.target.value, |
| 50 | + }) |
| 51 | + setIsFormChanged(true) |
| 52 | + } |
| 53 | + |
| 54 | + function handleFormAction(): void { |
| 55 | + if (!trim(formValues.city)) { |
| 56 | + setFormErrors({ city: 'Please select a city' }) |
| 57 | + return |
| 58 | + } |
| 59 | + |
| 60 | + if (!formValues.country) { |
| 61 | + setFormErrors({ country: 'Please select a country' }) |
| 62 | + return |
| 63 | + } |
| 64 | + |
| 65 | + setIsSaving(true) |
| 66 | + |
| 67 | + updateMemberProfileAsync( |
| 68 | + props.profile.handle, |
| 69 | + { |
| 70 | + addresses: [{ |
| 71 | + city: formValues.city, |
| 72 | + stateCode: formValues.stateCode, |
| 73 | + streetAddr1: formValues.streetAddr1, |
| 74 | + streetAddr2: formValues.streetAddr2, |
| 75 | + zip: formValues.zip, |
| 76 | + }], |
| 77 | + competitionCountryCode: formValues.country, |
| 78 | + homeCountryCode: formValues.country, |
| 79 | + }, |
| 80 | + ) |
| 81 | + .then(() => { |
| 82 | + toast.success('Your account has been updated.', { position: toast.POSITION.BOTTOM_RIGHT }) |
| 83 | + setFormErrors({}) |
| 84 | + }) |
| 85 | + .catch(() => { |
| 86 | + toast.error('Something went wrong. Please try again.', { position: toast.POSITION.BOTTOM_RIGHT }) |
| 87 | + }) |
| 88 | + .finally(() => { |
| 89 | + setIsFormChanged(false) |
| 90 | + setIsSaving(false) |
| 91 | + }) |
| 92 | + } |
| 93 | + |
| 94 | + return ( |
| 95 | + <Collapsible |
| 96 | + header={<h3>Address</h3>} |
| 97 | + containerClass={styles.container} |
| 98 | + contentClass={styles.content} |
| 99 | + > |
| 100 | + <p> |
| 101 | + By keeping this information up to date we may surprise you with a cool T-shirt. |
| 102 | + Sharing your contact details will never result in robocalls about health insurance plans or junk mail. |
| 103 | + </p> |
| 104 | + |
| 105 | + <form |
| 106 | + className={classNames(styles.formWrap)} |
| 107 | + > |
| 108 | + <div className={styles.form}> |
| 109 | + <InputText |
| 110 | + name='address' |
| 111 | + label='Address' |
| 112 | + error={formErrors.streetAddr1} |
| 113 | + placeholder='Your address' |
| 114 | + dirty |
| 115 | + tabIndex={0} |
| 116 | + type='text' |
| 117 | + onChange={bind(handleFormValueChange, this, 'streetAddr1')} |
| 118 | + value={formValues.streetAddr1} |
| 119 | + /> |
| 120 | + <InputText |
| 121 | + name='address2' |
| 122 | + label='Address 2' |
| 123 | + error={formErrors.streetAddr2} |
| 124 | + placeholder='Your address continued' |
| 125 | + dirty |
| 126 | + tabIndex={0} |
| 127 | + type='text' |
| 128 | + onChange={bind(handleFormValueChange, this, 'streetAddr2')} |
| 129 | + value={formValues.streetAddr2} |
| 130 | + /> |
| 131 | + <InputText |
| 132 | + name='city' |
| 133 | + label='City *' |
| 134 | + error={formErrors.city} |
| 135 | + placeholder='Which city do you live in?' |
| 136 | + dirty |
| 137 | + tabIndex={0} |
| 138 | + type='text' |
| 139 | + onChange={bind(handleFormValueChange, this, 'city')} |
| 140 | + value={formValues.city} |
| 141 | + /> |
| 142 | + <InputText |
| 143 | + name='state' |
| 144 | + label='State' |
| 145 | + error={formErrors.stateCode} |
| 146 | + placeholder='State' |
| 147 | + dirty |
| 148 | + tabIndex={0} |
| 149 | + type='text' |
| 150 | + onChange={bind(handleFormValueChange, this, 'stateCode')} |
| 151 | + value={formValues.stateCode} |
| 152 | + /> |
| 153 | + <InputText |
| 154 | + name='zip' |
| 155 | + label='Zip/Postal Code' |
| 156 | + error={formErrors.zip} |
| 157 | + placeholder='Your Zip or Postal Code' |
| 158 | + dirty |
| 159 | + tabIndex={0} |
| 160 | + type='text' |
| 161 | + onChange={bind(handleFormValueChange, this, 'zip')} |
| 162 | + value={formValues.zip} |
| 163 | + /> |
| 164 | + <InputSelect |
| 165 | + options={(countryLookup || []).map((cl: CountryLookup) => ({ |
| 166 | + label: cl.country, |
| 167 | + value: cl.countryCode, |
| 168 | + }))} |
| 169 | + value={formValues.country} |
| 170 | + onChange={bind(handleFormValueChange, this, 'country')} |
| 171 | + name='country' |
| 172 | + label='Country *' |
| 173 | + error={formErrors.country} |
| 174 | + placeholder='Select a Country' |
| 175 | + dirty |
| 176 | + /> |
| 177 | + |
| 178 | + <div className={styles.formCTAs}> |
| 179 | + <Button |
| 180 | + secondary |
| 181 | + size='lg' |
| 182 | + label='Save Changes' |
| 183 | + onClick={handleFormAction} |
| 184 | + disabled={isSaving || !isFormChanged} |
| 185 | + /> |
| 186 | + </div> |
| 187 | + </div> |
| 188 | + </form> |
| 189 | + </Collapsible> |
| 190 | + ) |
| 191 | +} |
| 192 | + |
| 193 | +export default MemberAddress |
0 commit comments