diff --git a/apps/app/public/locales/en/common.json b/apps/app/public/locales/en/common.json index 783ce73e04..c0c29dcbf9 100644 --- a/apps/app/public/locales/en/common.json +++ b/apps/app/public/locales/en/common.json @@ -34,8 +34,8 @@ "back-to-dynamic": "Back to {{page}}", "back-to-search": "Back to search" }, - "cancel": "Cancel", "can-help-people-in": "Can help people located anywhere in {{location}}", + "cancel": "Cancel", "claim-org-modal": { "list": "🔗 Claim your organization’s profile page and build trust with your audience on InReach\n✍🏾 Update your organization's information on InReach\n📨 Invite other staff to join your organization on InReach\n🔑 Gain access to future features built specifically for affiliated service providers on InReach", "title": "🏠\nThis organization has not yet been claimed by a service provider.\nWith a free InReach Service Provider account, you will soon be able to:" @@ -211,6 +211,9 @@ "photo_one": "Photo", "photo_other": "Photos", "please-specify": "Please specify", + "portal-module": { + "service-area": "Service Area" + }, "powered-by-vercel": "Powered by Vercel", "prefer-not-to-say": "Prefer not to say", "privacy-policy": "Privacy policy", @@ -265,6 +268,9 @@ "organization-placeholder-searchby": "Search by organization name...", "suggest-resource": "Can't find it? Suggest an organization you think should be included." }, + "select": { + "base": "Select {{- item}}" + }, "send-email": "Send email", "service": { "additional-info": "Additional eligibility information", diff --git a/packages/ui/modals/CoverageArea/hooks.ts b/packages/ui/modals/CoverageArea/hooks.ts new file mode 100644 index 0000000000..8280909c3f --- /dev/null +++ b/packages/ui/modals/CoverageArea/hooks.ts @@ -0,0 +1,14 @@ +import { useState } from 'react' + +export const useServiceAreaSelections = () => { + const [selected, setSelected] = useState({ country: null, govDist: null, subDist: null }) + const setVal = { + country: (value: string) => setSelected({ country: value, govDist: null, subDist: null }), + govDist: (value: string) => setSelected((prev) => ({ ...prev, govDist: value, subDist: null })), + subDist: (value: string) => setSelected((prev) => ({ ...prev, subDist: value })), + blank: () => setSelected({ country: null, govDist: null, subDist: null }), + } + + return [selected, setVal] as [typeof selected, typeof setVal] +} +type SelectionState = { country: string | null; govDist: string | null; subDist: string | null } diff --git a/packages/ui/modals/CoverageArea/index.stories.tsx b/packages/ui/modals/CoverageArea/index.stories.tsx index 82f4f31867..baa3794681 100644 --- a/packages/ui/modals/CoverageArea/index.stories.tsx +++ b/packages/ui/modals/CoverageArea/index.stories.tsx @@ -22,6 +22,7 @@ export default { fieldOpt.countries, fieldOpt.govDists, serviceArea.getServiceArea, + serviceArea.update, ], rqDevtools: true, whyDidYouRender: { collapseGroups: true }, diff --git a/packages/ui/modals/CoverageArea/index.tsx b/packages/ui/modals/CoverageArea/index.tsx index c146972c36..a36969aace 100644 --- a/packages/ui/modals/CoverageArea/index.tsx +++ b/packages/ui/modals/CoverageArea/index.tsx @@ -15,33 +15,37 @@ import { Title, } from '@mantine/core' import { useDisclosure } from '@mantine/hooks' +import { compareArrayVals } from 'crud-object-diff' import compact from 'just-compact' -import { useTranslation } from 'next-i18next' -import { forwardRef, useState } from 'react' +import { type TFunction, useTranslation } from 'next-i18next' +import { forwardRef } from 'react' import { useForm } from 'react-hook-form' -import { Icon } from '~ui/icon' import { trpc as api } from '~ui/lib/trpcClient' +import { useServiceAreaSelections } from './hooks' import { ServiceAreaForm, type ZServiceAreaForm } from './schema' import { useStyles } from './styles' import { ModalTitle } from '../ModalTitle' +const reduceDistType = (data: { tsNs: string; tsKey: string }[] | undefined, t: TFunction) => { + if (!data) return '' + const valueSet = data.reduce((prev, curr) => { + const translated = t(curr.tsKey, { ns: curr.tsNs, count: 1 }) + prev.add(translated) + return prev + }, new Set()) + return [...valueSet].sort().join('/') +} + const CoverageAreaModal = forwardRef(({ id, ...props }, ref) => { const { classes } = useStyles() const { t, i18n } = useTranslation(['common', 'gov-dist']) const countryTranslation = new Intl.DisplayNames(i18n.language, { type: 'region' }) const [opened, { open, close }] = useDisclosure(true) //TODO: remove `true` when done with dev - const [selected, setSelected] = useState({ country: null, govDist: null, subDist: null }) - const setVal = { - country: (value: string) => setSelected({ country: value, govDist: null, subDist: null }), - govDist: (value: string) => setSelected((prev) => ({ ...prev, govDist: value, subDist: null })), - subDist: (value: string) => setSelected((prev) => ({ ...prev, subDist: value })), - blank: () => setSelected({ country: null, govDist: null, subDist: null }), - } + const [selected, setVal] = useServiceAreaSelections() - const { data: dataServiceArea } = api.serviceArea.getServiceArea.useQuery(id) const { data: dataCountry } = api.fieldOpt.countries.useQuery( { activeForOrgs: true }, { @@ -60,6 +64,7 @@ const CoverageAreaModal = forwardRef(({ id, ...props } label: t(tsKey, { ns: tsNs }), tsKey, tsNs, + parent: null, ...rest, })) ?? [], placeholderData: [], @@ -78,6 +83,9 @@ const CoverageAreaModal = forwardRef(({ id, ...props } placeholderData: [], }) const apiUtils = api.useUtils() + + const updateServiceArea = api.serviceArea.update.useMutation() + const form = useForm({ resolver: zodResolver(ServiceAreaForm), defaultValues: async () => { @@ -94,7 +102,13 @@ const CoverageAreaModal = forwardRef(({ id, ...props } const serviceAreaCountries = form.watch('countries') const serviceAreaDistricts = form.watch('districts') - console.log(serviceAreaCountries, serviceAreaDistricts) + const placeHolders = { + first: t('select.base', { item: 'Country' }), + second: t('select.base', { + item: reduceDistType(dataDistrict?.map(({ govDistType }) => govDistType), t), + }), + third: t('select.base', { item: reduceDistType(dataSubDist?.map(({ govDistType }) => govDistType), t) }), + } const handleAdd = () => { switch (true) { @@ -107,7 +121,16 @@ const CoverageAreaModal = forwardRef(({ id, ...props } if (!valToAdd) return form.setValue( 'districts', - [...serviceAreaDistricts, { id: valToAdd.value, tsKey: valToAdd.tsKey, tsNs: valToAdd.tsNs }], + [ + ...serviceAreaDistricts, + { + id: valToAdd.value, + tsKey: valToAdd.tsKey, + tsNs: valToAdd.tsNs, + parent: valToAdd.parent, + country: valToAdd.country, + }, + ], { shouldValidate: true, } @@ -127,68 +150,70 @@ const CoverageAreaModal = forwardRef(({ id, ...props } } } - // const LocationSelect = ({ placeholder, data /*, inputPropsName*/ }: SelectFieldProps) => { - // // Display close button when field is not empty - // // const displayClose = form.getInputProps(inputPropsName).value.length > 0 - // const rightSection = ( - // - // { - // //displayClose && ( - // <> - // console.log('clicked')} - // variant='transparent' - // style={{ pointerEvents: 'all' }} - // > - // - // - // - // - // /*)*/ - // } - // - // - // ) - - // // Disable Select fields unless it's the state select field, or the state field has a value - // // const disabled = inputPropsName.includes('state) || form.getInputProps('state').value.length === 0 - - // return ( - // {selected.country && !!dataDistrict?.length && ( )} @@ -239,7 +271,7 @@ const CoverageAreaModal = forwardRef(({ id, ...props } - @@ -256,11 +288,3 @@ export const CoverageArea = createPolymorphicComponent interface Props extends ButtonProps { id: string } - -type SelectFieldProps = { - placeholder: string - data: string[] - // inputPropsName: string -} - -type SelectionState = { country: string | null; govDist: string | null; subDist: string | null }