diff --git a/src/hooks/api/organizers.ts b/src/hooks/api/organizers.ts index 088ea0d47..66091c60c 100644 --- a/src/hooks/api/organizers.ts +++ b/src/hooks/api/organizers.ts @@ -251,6 +251,41 @@ const useCreateOrganizerMutation = (configuration: UseMutationOptions = {}) => ...configuration, }); +type UpdateOrganizerArguments = CreateOrganizerArguments & { + organizerId: string; +}; + +const updateOrganizer = ({ + headers, + url, + organizerId, + name, + address, + mainLanguage, + contact, +}: UpdateOrganizerArguments) => + fetchFromApi({ + path: `/organizers/${organizerId}`, + options: { + headers, + method: 'PUT', + body: JSON.stringify({ + mainLanguage, + name, + url, + address, + contact, + }), + }, + }); + +const useUpdateOrganizerMutation = (configuration: UseMutationOptions = {}) => + useAuthenticatedMutation({ + mutationFn: updateOrganizer, + mutationKey: 'organizers-update', + ...configuration, + }); + export { useCreateOrganizerMutation, useDeleteOrganizerByIdMutation, @@ -258,4 +293,5 @@ export { useGetOrganizersByCreatorQuery, useGetOrganizersByQueryQuery, useGetOrganizersByWebsiteQuery, + useUpdateOrganizerMutation, }; diff --git a/src/i18n/de.json b/src/i18n/de.json index a36126a7b..628e908e1 100644 --- a/src/i18n/de.json +++ b/src/i18n/de.json @@ -441,6 +441,9 @@ "not_found": "Diese Veranstaltung ist dem UiTPAS noch nicht bekannt." } }, + "location": { + "title": "Standort" + }, "place": { "add_new_label": "Ort nicht gefunden? Neuen Standort hinzufügen" }, @@ -476,7 +479,8 @@ }, "title": { "events": "Stellen Sie sicher, dass Ihr Publikum keine Informationen verpasst", - "places": "Stellen Sie sicher, dass Ihr Publikum keine Informationen verpasst" + "places": "Stellen Sie sicher, dass Ihr Publikum keine Informationen verpasst", + "organizers": "Stellen Sie sicher, dass Ihr Publikum keine Informationen verpasst" }, "title_events": "Machen Sie dieses Ereignis zu etwas Besonderem", "title_places": "Heben Sie diesen Standort hervor" @@ -976,7 +980,8 @@ } }, "step2": { - "description_tips": "Beschreiben Sie Ihre Organisation mit Begeisterung\nAn welche Zielgruppe richtet sich die Organisation?\nWelche Aktivitäten organisiert diese Organisation?" + "description_tips": "Beschreiben Sie Ihre Organisation mit Begeisterung\nAn welche Zielgruppe richtet sich die Organisation?\nWelche Aktivitäten organisiert diese Organisation?", + "save": "Speichern" } } }, diff --git a/src/i18n/fr.json b/src/i18n/fr.json index 21f785fae..b898cc36c 100644 --- a/src/i18n/fr.json +++ b/src/i18n/fr.json @@ -443,6 +443,9 @@ "not_found": "Cette activité n'est pas encore connue par UiTPAS." } }, + "location": { + "title": "Lieu" + }, "place": { "add_new_label": "Lieu introuvable ? Ajouter un nouveau lieu" }, @@ -478,7 +481,8 @@ }, "title": { "events": "Assurez-vous que votre public ne manque aucune information", - "places": "Assurez-vous que votre public ne manque aucune information" + "places": "Assurez-vous que votre public ne manque aucune information", + "organizers": "Assurez-vous que votre public ne manque aucune information" } }, "footer": { @@ -978,6 +982,10 @@ "step2": { "description_tips": "Décrivez avec enthousiasme votre organisation\nQuel public l'organisation cible-t-elle ?\nQuel type d'activités cette organisation organise-t-elle ?" } + }, + "step2": { + "description_tips": "Décrivez avec enthousiasme votre organisation\nQuel public l'organisation cible-t-elle ?\nQuel type d'activités cette organisation organise-t-elle ?", + "save": "Enregistrer" } }, "selectionTable": { diff --git a/src/i18n/nl.json b/src/i18n/nl.json index 8b189125d..36d695c03 100644 --- a/src/i18n/nl.json +++ b/src/i18n/nl.json @@ -443,6 +443,9 @@ "not_found": "Deze activiteit is nog niet gekend bij UiTPAS." } }, + "location": { + "title": "Locatie" + }, "place": { "add_new_label": "Locatie niet gevonden? Nieuwe locatie toevoegen" }, @@ -478,7 +481,8 @@ }, "title": { "events": "Zorg dat je publiek geen informatie mist", - "places": "Zorg dat je publiek geen informatie mist" + "places": "Zorg dat je publiek geen informatie mist", + "organizers": "Zorg dat je publiek geen informatie mist" } }, "footer": { @@ -976,7 +980,8 @@ } }, "step2": { - "description_tips": "Geef een enthousiaste omschrijving van je organisatie\nTot welke doelgroep richt de organisatie zich?\nWat voor activiteiten organiseert deze organisatie?" + "description_tips": "Geef een enthousiaste omschrijving van je organisatie\nTot welke doelgroep richt de organisatie zich?\nWat voor activiteiten organiseert deze organisatie?", + "save": "Bewaren" } } }, diff --git a/src/pages/create/OfferForm.tsx b/src/pages/create/OfferForm.tsx index 4deeec531..eec03c5c6 100644 --- a/src/pages/create/OfferForm.tsx +++ b/src/pages/create/OfferForm.tsx @@ -106,7 +106,7 @@ const getAddress = ( }; const parseLocationAttributes = ( - offer: Offer, + offer: Offer | Organizer, language: SupportedLanguage, mainLanguage: SupportedLanguage, ) => { @@ -131,7 +131,7 @@ const parseLocationAttributes = ( postalCode: postalCode, place: isEvent(offer) ? offer.location : undefined, country: addressCountry, - ...(isPlace(offer) && { streetAndNumber: streetAddress }), + ...(!isEvent(offer) && { streetAndNumber: streetAddress }), ...(isEvent(offer) && !!offer.onlineUrl && { onlineUrl: offer.onlineUrl }), }, diff --git a/src/pages/organizers/create/OrganizerForm.tsx b/src/pages/organizers/create/OrganizerForm.tsx index 2b6c1d121..b9185ab41 100644 --- a/src/pages/organizers/create/OrganizerForm.tsx +++ b/src/pages/organizers/create/OrganizerForm.tsx @@ -8,13 +8,16 @@ import { URL_REGEX } from '@/constants/Regex'; import { useCreateOrganizerMutation, useGetOrganizerByIdQuery, + useUpdateOrganizerMutation, } from '@/hooks/api/organizers'; import { SupportedLanguage, SupportedLanguages } from '@/i18n/index'; +import { parseLocationAttributes } from '@/pages/create/OfferForm'; import { additionalInformationStepConfiguration, AdditionalInformationStepVariant, } from '@/pages/steps/AdditionalInformationStep'; import { useParseStepConfiguration } from '@/pages/steps/hooks/useParseStepConfiguration'; +import { locationStepConfiguration } from '@/pages/steps/LocationStep'; import { Steps, StepsConfiguration } from '@/pages/steps/Steps'; import { Organizer } from '@/types/Organizer'; import { Button, ButtonVariants } from '@/ui/Button'; @@ -42,8 +45,11 @@ const configurations = [ typeAndThemeStepConfiguration, { ...additionalInformationStepConfiguration, - shouldShowStep: () => true, + shouldShowStep: (form) => + form.getValues('nameAndUrl.name') && form.getValues('nameAndUrl.url'), variant: AdditionalInformationStepVariant.ORGANIZER, + name: 'location' as StepsConfiguration['name'], + defaultValue: locationStepConfiguration.defaultValue, }, ]; @@ -55,12 +61,20 @@ const OrganizerForm = (props) => { const { handleSubmit, formState, getValues, reset } = form; - const organizerId = useMemo( + const urlOrganizerId = useMemo( () => query.organizerId as string, [query.organizerId], ); const convertOrganizerToFormData = (organizer: Organizer) => { + const locationAttributes = !organizer?.address + ? {} + : parseLocationAttributes( + organizer, + i18n.language as SupportedLanguage, + organizer.mainLanguage as SupportedLanguage, + ); + return { nameAndUrl: { name: getLanguageObjectOrFallback( @@ -69,6 +83,7 @@ const OrganizerForm = (props) => { ) as string, url: organizer.url, }, + ...locationAttributes, }; }; @@ -76,7 +91,7 @@ const OrganizerForm = (props) => { // TODO better type query const getOrganizerByIdQuery = useGetOrganizerByIdQuery( - { id: organizerId }, + { id: urlOrganizerId }, { onSuccess: (organizer: Organizer) => { reset(convertOrganizerToFormData(organizer), { @@ -90,13 +105,33 @@ const OrganizerForm = (props) => { const organizer = getOrganizerByIdQuery?.data; const createOrganizerMutation = useCreateOrganizerMutation(); + const updateOrganizerMutation = useUpdateOrganizerMutation(); - const createOrganizer = async ({ onSuccess }) => { - const { organizerId } = await createOrganizerMutation.mutateAsync({ + const upsertOrganizer = async ({ onSuccess }) => { + let mutation = createOrganizerMutation; + let attributes: { [key: string]: any } = { name: getValues('nameAndUrl.name'), url: getValues('nameAndUrl.url'), mainLanguage: i18n.language, - }); + }; + + if (urlOrganizerId) { + mutation = updateOrganizerMutation; + attributes = { + ...attributes, + organizerId: urlOrganizerId, + address: { + [i18n.language]: { + addressCountry: getValues('location.country'), + addressLocality: getValues('location.municipality.name'), + postalCode: getValues('location.municipality.zip'), + streetAddress: getValues('location.streetAndNumber'), + }, + }, + }; + } + + const { organizerId } = await mutation.mutateAsync(attributes); onSuccess(organizerId); }; @@ -104,7 +139,7 @@ const OrganizerForm = (props) => { const hasErrors = Object.keys(formState.errors).length > 0; const onSuccess = () => { - createOrganizer({ + upsertOrganizer({ onSuccess: async (organizerId) => await push(`/organizers/${organizerId}/edit`), }); @@ -118,21 +153,30 @@ const OrganizerForm = (props) => { ({})} form={form} /> - + {urlOrganizerId ? ( + + ) : ( + + )} ); diff --git a/src/pages/organizers/create/steps/UrlStep.tsx b/src/pages/organizers/create/steps/UrlStep.tsx index ce555b8c4..41358b2f5 100644 --- a/src/pages/organizers/create/steps/UrlStep.tsx +++ b/src/pages/organizers/create/steps/UrlStep.tsx @@ -1,3 +1,4 @@ +import { useRouter } from 'next/router'; import { FormEvent, useEffect, useMemo } from 'react'; import { Controller, useWatch } from 'react-hook-form'; import { Trans, useTranslation } from 'react-i18next'; @@ -11,6 +12,7 @@ import { FormElement } from '@/ui/FormElement'; import { Input } from '@/ui/Input'; import { getStackProps, Stack, StackProps } from '@/ui/Stack'; import { getLanguageObjectOrFallback } from '@/utils/getLanguageObjectOrFallback'; +import { parseOfferId } from '@/utils/parseOfferId'; import { prefixUrlWithHttps } from '@/utils/url'; type UrlStepProps = StackProps & StepProps; @@ -26,6 +28,7 @@ const UrlStep = ({ name, ...props }: UrlStepProps) => { + const { query } = useRouter(); const { t, i18n } = useTranslation(); const [watchedUrl] = useWatch({ @@ -46,10 +49,11 @@ const UrlStep = ({ const isUrlAlreadyTaken = errors.nameAndUrl?.url?.type === 'not_unique'; - console.log({ existingOrganizer }); - useEffect(() => { - if (existingOrganizer) { + if ( + existingOrganizer && + parseOfferId(existingOrganizer['@id']) !== query.organizerId + ) { console.log('should set error'); setError('nameAndUrl.url', { type: 'not_unique' }); return; diff --git a/src/pages/steps/AdditionalInformationStep/AdditionalInformationStep.tsx b/src/pages/steps/AdditionalInformationStep/AdditionalInformationStep.tsx index 0024cb0a6..edd9313b4 100644 --- a/src/pages/steps/AdditionalInformationStep/AdditionalInformationStep.tsx +++ b/src/pages/steps/AdditionalInformationStep/AdditionalInformationStep.tsx @@ -7,6 +7,8 @@ import { useQueryClient } from 'react-query'; import { OfferType, Scope } from '@/constants/OfferType'; import { useIntersectionObserver } from '@/hooks/useIntersectionObserver'; import { LabelsStep } from '@/pages/steps/AdditionalInformationStep/LabelsStep'; +import { PhysicalLocationStep } from '@/pages/steps/AdditionalInformationStep/PhysicalLocationStep'; +import { Countries } from '@/types/Country'; import type { Values } from '@/types/Values'; import { parseSpacing } from '@/ui/Box'; import { Icon, Icons } from '@/ui/Icon'; @@ -21,8 +23,8 @@ import { StepsConfiguration } from '../Steps'; import { BookingInfoStep } from './BookingInfoStep'; import { ContactInfoStep } from './ContactInfoStep'; import { DescriptionStep } from './DescriptionStep'; +import { FormScore } from './FormScore'; import { MediaStep } from './MediaStep'; -import { OfferScore } from './OfferScore'; import { OrganizerStep } from './OrganizerStep'; import { PriceInformation } from './PriceInformation'; @@ -44,6 +46,7 @@ const Fields = { MEDIA: 'media', AUDIENCE: 'audience', LABELS: 'labels', + LOCATION: 'location', }; type Field = Values; @@ -111,6 +114,12 @@ const tabConfigurations: TabConfig[] = [ AdditionalInformationStepVariant.MOVIE, ], }, + { + field: Fields.LOCATION, + TabContent: PhysicalLocationStep, + shouldInvalidate: false, + shouldShowOn: [AdditionalInformationStepVariant.ORGANIZER], + }, { field: Fields.LABELS, TabContent: LabelsStep, @@ -181,7 +190,7 @@ const AdditionalInformationStep = ({ if (shouldInvalidate) { await queryClient.invalidateQueries([scope, { id: offerId }]); } - onChangeSuccess(field); + onChangeSuccess?.(field); }, // eslint-disable-next-line react-hooks/exhaustive-deps [scope, offerId, queryClient], @@ -279,6 +288,7 @@ const AdditionalInformationStep = ({ onSuccessfulChange={() => invalidateOfferQuery(field, shouldInvalidate) } + {...props} {...stepProps} /> @@ -286,7 +296,7 @@ const AdditionalInformationStep = ({ }, )} - { ); }; -const scoreWeightMapping = { +type Weights = { [key: string]: { weight: number; mandatory: boolean } }; + +const scoreWeightMapping: Weights = { type: { weight: 12, mandatory: true, @@ -132,24 +134,34 @@ type Props = { completedFields: Record; }; -const getMinimumScore = (): number => { +const getScopeWeights = (scope: Scope): Weights => { + let weights = scoreWeightMapping; + if (scope === ScopeTypes.ORGANIZERS) { + weights.location.weight = 10; + weights.description.weight = 15; + } + + return weights; +}; + +const getMinimumScore = (weights: Weights): number => { let minimumScore = 0; - Object.values(scoreWeightMapping).forEach((scoreWeight) => { + Object.values(weights).forEach((scoreWeight) => { if (scoreWeight.mandatory) minimumScore += scoreWeight.weight; }); return minimumScore; }; -const minimumScore = getMinimumScore(); - -const OfferScore = ({ completedFields, offerId, scope, ...props }: Props) => { +const FormScore = ({ completedFields, offerId, scope, ...props }: Props) => { const { t } = useTranslation(); const router = useRouter(); const getOfferByIdQuery = useGetOfferByIdQuery({ id: offerId, scope }); + const weights = getScopeWeights(scope); + const minimumScore = useMemo(() => getMinimumScore(weights), [weights]); // @ts-expect-error const offer: Offer | undefined = getOfferByIdQuery.data; @@ -180,8 +192,8 @@ const OfferScore = ({ completedFields, offerId, scope, ...props }: Props) => { const score = useMemo(() => { let completeScore = 0; Object.keys(fullCompletedFields).forEach((field) => { - if (fullCompletedFields[field] && scoreWeightMapping[field]) { - completeScore += scoreWeightMapping[field].weight; + if (fullCompletedFields[field] && weights[field]) { + completeScore += weights[field].weight; } }); @@ -212,11 +224,11 @@ const OfferScore = ({ completedFields, offerId, scope, ...props }: Props) => { unCompletedFieldKeys.forEach((fieldKey: string) => { if ( - scoreWeightMapping[fieldKey] && - scoreWeightMapping[fieldKey].weight > highestUncompletedValue.weight + weights[fieldKey] && + weights[fieldKey].weight > highestUncompletedValue.weight ) { highestUncompletedValue = { - weight: scoreWeightMapping[fieldKey].weight, + weight: weights[fieldKey].weight, fieldName: fieldKey, }; } @@ -282,4 +294,4 @@ const OfferScore = ({ completedFields, offerId, scope, ...props }: Props) => { ); }; -export { OfferScore }; +export { FormScore }; diff --git a/src/pages/steps/AdditionalInformationStep/LabelsStep.tsx b/src/pages/steps/AdditionalInformationStep/LabelsStep.tsx index bc5e9bc0e..74abf845d 100644 --- a/src/pages/steps/AdditionalInformationStep/LabelsStep.tsx +++ b/src/pages/steps/AdditionalInformationStep/LabelsStep.tsx @@ -6,14 +6,15 @@ import { UseQueryResult } from 'react-query'; import { useGetLabelsByQuery } from '@/hooks/api/labels'; import { useAddOfferLabelMutation, - useGetOfferByIdQuery, useRemoveOfferLabelMutation, } from '@/hooks/api/offers'; +import { useGetEntityByIdAndScope } from '@/hooks/api/scope'; import { TabContentProps, ValidationStatus, } from '@/pages/steps/AdditionalInformationStep/AdditionalInformationStep'; import { Label, Offer } from '@/types/Offer'; +import { Organizer } from '@/types/Organizer'; import { Alert } from '@/ui/Alert'; import { Badge, BadgeVariants } from '@/ui/Badge'; import { FormElement } from '@/ui/FormElement'; @@ -36,9 +37,9 @@ function LabelsStep({ }: LabelsStepProps) { const { t } = useTranslation(); - const getOfferByIdQuery = useGetOfferByIdQuery({ id: offerId, scope }); + const getEntityByIdQuery = useGetEntityByIdAndScope({ id: offerId, scope }); // @ts-expect-error - const offer: Offer | undefined = getOfferByIdQuery.data; + const entity: Offer | Organizer | undefined = getEntityByIdQuery.data; const ref = useRef(null); @@ -49,7 +50,7 @@ function LabelsStep({ }); const options = labelsQuery.data?.member ?? []; - const [labels, setLabels] = useState(offer?.labels ?? []); + const [labels, setLabels] = useState(entity?.labels ?? []); const addLabelMutation = useAddOfferLabelMutation(); const removeLabelMutation = useRemoveOfferLabelMutation(); diff --git a/src/pages/steps/AdditionalInformationStep/PhysicalLocationStep.tsx b/src/pages/steps/AdditionalInformationStep/PhysicalLocationStep.tsx new file mode 100644 index 000000000..1a9861ed6 --- /dev/null +++ b/src/pages/steps/AdditionalInformationStep/PhysicalLocationStep.tsx @@ -0,0 +1,29 @@ +import React, { useEffect } from 'react'; + +import { + TabContentProps, + ValidationStatus, +} from '@/pages/steps/AdditionalInformationStep/AdditionalInformationStep'; +import { isLocationSet, LocationStep } from '@/pages/steps/LocationStep'; +import { StepProps } from '@/pages/steps/Steps'; +import { StackProps } from '@/ui/Stack'; + +type PhysicalLocationStepProps = StackProps & TabContentProps & StepProps; + +function PhysicalLocationStep({ + onValidationChange, + ...props +}: PhysicalLocationStepProps) { + const location = props.watch('location'); + useEffect(() => { + onValidationChange( + location?.streetAndNumber + ? ValidationStatus.SUCCESS + : ValidationStatus.WARNING, + ); + }, [onValidationChange, location]); + + return ; +} + +export { PhysicalLocationStep }; diff --git a/src/pages/steps/LocationStep.tsx b/src/pages/steps/LocationStep.tsx index eeb08e6c2..48ad6445e 100644 --- a/src/pages/steps/LocationStep.tsx +++ b/src/pages/steps/LocationStep.tsx @@ -7,7 +7,12 @@ import { useTranslation } from 'react-i18next'; import * as yup from 'yup'; import { EventTypes } from '@/constants/EventTypes'; -import { OfferType, OfferTypes, Scope } from '@/constants/OfferType'; +import { + OfferType, + OfferTypes, + Scope, + ScopeTypes, +} from '@/constants/OfferType'; import { useChangeAttendanceModeMutation, useChangeAudienceMutation, @@ -722,9 +727,9 @@ const useEditLocation = ({ scope, offerId }: UseEditArguments) => { type PlaceStepProps = StackProps & StepProps & { - terms: Array>; - chooseLabel: (t: TFunction) => string; - placeholderLabel: (t: TFunction) => string; + terms?: Array>; + chooseLabel?: (t: TFunction) => string; + placeholderLabel?: (t: TFunction) => string; } & { offerId?: string }; const isLocationSet = ( @@ -732,7 +737,7 @@ const isLocationSet = ( location: FormDataUnion['location'], formState, ) => { - if (location.isOnline || location.place) { + if (location?.isOnline || location?.place) { return true; } @@ -740,7 +745,7 @@ const isLocationSet = ( return ( isCultuurKuur || - (location.municipality?.name && + (location?.municipality?.name && formState.touchedFields.location?.streetAndNumber) ); }; @@ -753,8 +758,8 @@ const LocationStep = ({ name, offerId, onChange, - chooseLabel, - placeholderLabel, + chooseLabel = (t) => t('create.location.place.choose_label'), + placeholderLabel = (t) => t('create.location.place.placeholder'), setValue, trigger, watch, @@ -766,17 +771,11 @@ const LocationStep = ({ const [audienceType, setAudienceType] = useState(''); const [onlineUrl, setOnlineUrl] = useState(''); const [hasOnlineUrlError, setHasOnlineUrlError] = useState(false); - - const [scope, locationStreetAndNumber, locationOnlineUrl, location] = - useWatch({ - control, - name: [ - 'scope', - 'location.streetAndNumber', - 'location.onlineUrl', - 'location', - ], - }); + const scope = watch('scope') ?? props.scope; + const [locationStreetAndNumber, locationOnlineUrl, location] = useWatch({ + control, + name: ['location.streetAndNumber', 'location.onlineUrl', 'location'], + }); const shouldAddSpaceBelowTypeahead = useMemo(() => { if (offerId) return false; @@ -1069,7 +1068,7 @@ const LocationStep = ({ )} - {scope === OfferTypes.EVENTS && ( + {scope === ScopeTypes.EVENTS && ( )} - {scope === OfferTypes.PLACES && ( + {[ScopeTypes.PLACES, ScopeTypes.ORGANIZERS].includes(scope) && ( {isPlaceAddressComplete ? ( @@ -1114,7 +1113,7 @@ const LocationStep = ({ ) : ( - {['NL', 'DE'].includes(location.country) && ( + {['NL', 'DE'].includes(location?.country) && ( = { name: 'location', shouldShowStep: ({ watch }) => !!watch('typeAndTheme')?.type?.id, title: ({ t, scope }) => t(`create.location.title.${scope}`), - stepProps: { - chooseLabel: (t) => t('create.location.place.choose_label'), - placeholderLabel: (t) => t('create.location.place.placeholder'), - }, defaultValue: { isOnline: false, country: Countries.BE, @@ -1251,6 +1246,7 @@ export { DUTCH_ZIP_REGEX, GERMAN_ZIP_REGEX, isLocationSet, + LocationStep, locationStepConfiguration, useEditLocation, }; diff --git a/src/pages/steps/Steps.tsx b/src/pages/steps/Steps.tsx index c9b233f58..df41a492c 100644 --- a/src/pages/steps/Steps.tsx +++ b/src/pages/steps/Steps.tsx @@ -119,6 +119,7 @@ StepWrapper.defaultProps = { const getValue = getValueFromTheme('createPage'); type StepProps = UseFormReturn & { + scope: string; loading: boolean; name: Path; onChange: (value: any) => void; diff --git a/src/types/Address.ts b/src/types/Address.ts index 5a21e2b58..b24e4b88b 100644 --- a/src/types/Address.ts +++ b/src/types/Address.ts @@ -1,10 +1,12 @@ +import { Country } from '@/types/Country'; + import type { SupportedLanguages } from '../i18n'; import type { Values } from './Values'; type AddressLocality = string; type AddressInternal = { - addressCountry: string; + addressCountry: Country; addressLocality: AddressLocality; postalCode: string; streetAddress: string; diff --git a/src/types/Organizer.ts b/src/types/Organizer.ts index 36833b87e..0ba72a029 100644 --- a/src/types/Organizer.ts +++ b/src/types/Organizer.ts @@ -20,6 +20,7 @@ type Organizer = { latitude: number; longitude: number; }; + location?: Address; url?: string; };