From e35260eb9717ad3adf87e54584e65c5bca781d5b Mon Sep 17 00:00:00 2001 From: Tony Date: Sun, 17 Sep 2023 18:16:32 +0300 Subject: [PATCH 1/6] admin/users edit roles --- .../admin/organizers/grid/DeleteModal.tsx | 2 +- src/components/common/form/CheckboxField.tsx | 7 +- .../common/person/grid/PersonForm.tsx | 108 ++++++++++++++++-- src/gql/person.d.ts | 18 ++- src/service/organizer.ts | 6 +- 5 files changed, 127 insertions(+), 14 deletions(-) diff --git a/src/components/admin/organizers/grid/DeleteModal.tsx b/src/components/admin/organizers/grid/DeleteModal.tsx index 0780b23a8..bbdb1e874 100644 --- a/src/components/admin/organizers/grid/DeleteModal.tsx +++ b/src/components/admin/organizers/grid/DeleteModal.tsx @@ -23,7 +23,7 @@ export default observer(function DeleteModal() { const { hideDelete, selectedRecord } = ModalStore const mutation = useMutation, AxiosError, string>({ - mutationFn: deleteOrganizer(selectedRecord.id), + mutationFn: deleteOrganizer(), onError: () => AlertStore.show(t('admin.alerts.delete-error'), 'error'), onSuccess: () => { hideDelete() diff --git a/src/components/common/form/CheckboxField.tsx b/src/components/common/form/CheckboxField.tsx index c9078af5d..58c9e252c 100644 --- a/src/components/common/form/CheckboxField.tsx +++ b/src/components/common/form/CheckboxField.tsx @@ -6,10 +6,11 @@ import { TranslatableField, translateError } from 'common/form/validation' export type CheckboxFieldProps = { name: string + disabled?: boolean label: string | number | React.ReactElement } -export default function CheckboxField({ name, label }: CheckboxFieldProps) { +export default function CheckboxField({ name, disabled, label }: CheckboxFieldProps) { const { t } = useTranslation() const [field, meta] = useField(name) const helperText = meta.touched ? translateError(meta.error as TranslatableField, t) : '' @@ -17,7 +18,9 @@ export default function CheckboxField({ name, label }: CheckboxFieldProps) { } + control={ + + } /> {Boolean(meta.error) && {helperText}} diff --git a/src/components/common/person/grid/PersonForm.tsx b/src/components/common/person/grid/PersonForm.tsx index 2251a9a5e..8bacc578c 100644 --- a/src/components/common/person/grid/PersonForm.tsx +++ b/src/components/common/person/grid/PersonForm.tsx @@ -17,12 +17,20 @@ import { useRouter } from 'next/router' import { useTranslation } from 'next-i18next' import { routes } from 'common/routes' import { usePerson } from 'common/hooks/person' +import CheckboxField from 'components/common/form/CheckboxField' +import { useCreateCoordinator, useDeleteCoordinator } from 'service/coordinator' +import { CoordinatorResponse, CoorinatorInput } from 'gql/coordinators' +import { createOrganizer, deleteOrganizer } from 'service/organizer' +import { OrganizerInput } from 'gql/organizer' const validationSchema: yup.SchemaOf = yup.object().defined().shape({ firstName: name.required(), lastName: name.required(), email: email.required(), phone: phone.notRequired(), + isBeneficiary: yup.bool().required(), + isCoordinator: yup.bool().required(), + isOrganizer: yup.bool().required(), }) const defaults: AdminPersonFormData = { @@ -30,10 +38,20 @@ const defaults: AdminPersonFormData = { lastName: '', email: '', phone: '', + isBeneficiary: false, + isCoordinator: false, + isOrganizer: false, } type FormProps = { - initialValues?: AdminPersonFormData + initialValues?: { + coordinatorId?: string + activeCoordinator?: boolean + organizerId?: string + activeOrganizer?: boolean + beneficiaryId?: string + activeBeneficiary?: boolean + } & AdminPersonFormData } export default function PersonForm({ initialValues = defaults }: FormProps) { @@ -48,14 +66,60 @@ export default function PersonForm({ initialValues = defaults }: FormProps) { >({ mutationFn: editPersonId ? useEditPerson(editPersonId) : useCreatePerson(), onError: () => AlertStore.show(t('common:alerts.error'), 'error'), - onSuccess: () => { - AlertStore.show(t('common:alerts.success'), 'success') - router.push(routes.admin.person.index) - }, }) - function handleSubmit(values: AdminPersonFormData) { - mutation.mutate(values) + const coordinatorCreateMutation = useMutation< + AxiosResponse, + AxiosError, + CoorinatorInput + >({ + mutationFn: useCreateCoordinator(), + onError: () => AlertStore.show(t('common:alerts.error'), 'error'), + }) + + const coordinatorDeleteMutation = useMutation< + AxiosResponse, + AxiosError, + string + >({ + mutationFn: useDeleteCoordinator(), + onError: () => AlertStore.show(t('common:alerts.error'), 'error'), + }) + + const organizerCreateMutation = useMutation< + AxiosResponse, + AxiosError, + OrganizerInput + >({ + mutationFn: createOrganizer(), + onError: () => AlertStore.show(t('common:alerts.error'), 'error'), + }) + + const organizerDeleteMutation = useMutation< + AxiosResponse, + AxiosError, + string + >({ + mutationFn: deleteOrganizer(), + onError: () => AlertStore.show(t('common:alerts.error'), 'error'), + }) + + async function handleSubmit(values: AdminPersonFormData) { + const { data: userResponse } = await mutation.mutateAsync(values) + + if (values.isCoordinator !== initialValues.isCoordinator) { + !values.isCoordinator && initialValues.coordinatorId + ? coordinatorDeleteMutation.mutate(initialValues.coordinatorId) + : coordinatorCreateMutation.mutate({ personId: userResponse.id }) + } + + if (values.isOrganizer !== initialValues.isOrganizer) { + !values.isOrganizer && initialValues.organizerId + ? organizerDeleteMutation.mutate(initialValues.organizerId) + : organizerCreateMutation.mutate({ personId: userResponse.id }) + } + + router.push(routes.admin.person.index) } if (editPersonId) { @@ -67,6 +131,15 @@ export default function PersonForm({ initialValues = defaults }: FormProps) { lastName: data?.lastName ?? '', email: data?.email ?? '', phone: data?.phone ?? '', + isBeneficiary: !!data?.beneficiaries?.length, + beneficiaryId: data?.beneficiaries?.at(0)?.id, + activeBeneficiary: !!data?.beneficiaries?.at(0)?._count?.campaigns, + isCoordinator: !!data?.coordinators, + coordinatorId: data?.coordinators?.id, + activeCoordinator: !!data?.coordinators?._count?.campaigns, + isOrganizer: !!data?.organizer, + organizerId: data?.organizer?.id, + activeOrganizer: !!data?.organizer?._count?.campaigns, } } @@ -112,6 +185,27 @@ export default function PersonForm({ initialValues = defaults }: FormProps) { label="person:admin.fields.phone" /> + + + + + + + + + +export type AdminPersonFormData = Pick< + PersonFormData, + 'firstName' | 'lastName' | 'email' | 'phone' | 'isBeneficiary' | 'isCoordinator' | 'isOrganizer' +> export type AdminPersonResponse = Pick< PersonResponse, diff --git a/src/service/organizer.ts b/src/service/organizer.ts index 92a194318..365471781 100644 --- a/src/service/organizer.ts +++ b/src/service/organizer.ts @@ -18,11 +18,11 @@ export const createOrganizer = () => { } } -export const deleteOrganizer = (id: string) => { +export const deleteOrganizer = () => { const { data: session } = useSession() - return async () => { + return async (data: string) => { return await apiClient.delete>( - endpoints.organizer.removeOrganizer(id).url, + endpoints.organizer.removeOrganizer(data).url, authConfig(session?.accessToken), ) } From 60c8041830a40dc2737b5bb242cec6c9af463f24 Mon Sep 17 00:00:00 2001 From: Tony Date: Sun, 17 Sep 2023 18:24:48 +0300 Subject: [PATCH 2/6] updated validationSchema --- src/components/common/person/PersonForm.tsx | 4 ++++ src/gql/person.d.ts | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/components/common/person/PersonForm.tsx b/src/components/common/person/PersonForm.tsx index e5d6880c3..b3b32a69a 100644 --- a/src/components/common/person/PersonForm.tsx +++ b/src/components/common/person/PersonForm.tsx @@ -22,6 +22,10 @@ const validationSchema: yup.SchemaOf = yup.object().defined().sh companyNumber: yup.string(), legalPersonName: name, address: yup.string(), + // Roles + isBeneficiary: yup.bool().notRequired(), + isCoordinator: yup.bool().notRequired(), + isOrganizer: yup.bool().notRequired(), }) const defaults: PersonFormData = { diff --git a/src/gql/person.d.ts b/src/gql/person.d.ts index 0a4bd0664..cbe0e5628 100644 --- a/src/gql/person.d.ts +++ b/src/gql/person.d.ts @@ -38,9 +38,9 @@ export type PersonFormData = { companyNumber?: string legalPersonName?: string address?: string - isBeneficiary: boolean - isCoordinator: boolean - isOrganizer: boolean + isBeneficiary?: boolean + isCoordinator?: boolean + isOrganizer?: boolean } export type CreateBeneficiaryInput = { From 9049ce00aa81a88fd0b15291f0dfe6c63846633f Mon Sep 17 00:00:00 2001 From: Tony Date: Tue, 19 Sep 2023 20:16:53 +0300 Subject: [PATCH 3/6] added beneficiary form --- public/locales/bg/person.json | 6 +- public/locales/en/person.json | 6 +- src/components/common/form/CheckboxField.tsx | 21 +- .../common/person/grid/CreateForm.tsx | 220 ++++++++++++++++++ .../common/person/grid/CreatePage.tsx | 4 +- .../grid/{PersonForm.tsx => EditForm.tsx} | 193 +++++++++------ .../common/person/grid/EditPage.tsx | 4 +- src/gql/beneficiary.d.ts | 2 +- src/gql/person.d.ts | 17 +- 9 files changed, 393 insertions(+), 80 deletions(-) create mode 100644 src/components/common/person/grid/CreateForm.tsx rename src/components/common/person/grid/{PersonForm.tsx => EditForm.tsx} (52%) diff --git a/public/locales/bg/person.json b/public/locales/bg/person.json index ef8c08897..edf923cf8 100644 --- a/public/locales/bg/person.json +++ b/public/locales/bg/person.json @@ -40,7 +40,11 @@ "address": "Адрес", "organizer": "Организатор", "coordinator": "Координатор", - "beneficiary": "Бенефициент" + "beneficiary": "Бенефициент", + "organizerRelation": "Отношения с организатор", + "countryCode": "Държава", + "city": "Град", + "description": "Описание" }, "cta": { "create": "Създай", diff --git a/public/locales/en/person.json b/public/locales/en/person.json index e9ce8a8cb..2079aea08 100644 --- a/public/locales/en/person.json +++ b/public/locales/en/person.json @@ -41,7 +41,11 @@ "address": "Address", "organizer": "Organizer", "coordinator": "Coordinator", - "beneficiary": "Beneficiary" + "beneficiary": "Beneficiary", + "organizerRelation": "Organizer relation", + "countryCode": "Country code", + "city": "City", + "description": "Description" }, "cta": { "create": "Create", diff --git a/src/components/common/form/CheckboxField.tsx b/src/components/common/form/CheckboxField.tsx index 58c9e252c..17c1c0e8f 100644 --- a/src/components/common/form/CheckboxField.tsx +++ b/src/components/common/form/CheckboxField.tsx @@ -1,3 +1,5 @@ +import { ChangeEvent } from 'react' + import { useField } from 'formik' import { useTranslation } from 'next-i18next' import { Checkbox, FormControl, FormControlLabel, FormHelperText } from '@mui/material' @@ -7,10 +9,16 @@ import { TranslatableField, translateError } from 'common/form/validation' export type CheckboxFieldProps = { name: string disabled?: boolean + onChange?: (e: ChangeEvent) => void label: string | number | React.ReactElement } -export default function CheckboxField({ name, disabled, label }: CheckboxFieldProps) { +export default function CheckboxField({ + name, + disabled, + onChange: handleChange, + label, +}: CheckboxFieldProps) { const { t } = useTranslation() const [field, meta] = useField(name) const helperText = meta.touched ? translateError(meta.error as TranslatableField, t) : '' @@ -19,7 +27,16 @@ export default function CheckboxField({ name, disabled, label }: CheckboxFieldPr + { + field.onChange(e) + if (handleChange) handleChange(e) + }} + /> } /> {Boolean(meta.error) && {helperText}} diff --git a/src/components/common/person/grid/CreateForm.tsx b/src/components/common/person/grid/CreateForm.tsx new file mode 100644 index 000000000..6784baeda --- /dev/null +++ b/src/components/common/person/grid/CreateForm.tsx @@ -0,0 +1,220 @@ +import React, { useState } from 'react' +import * as yup from 'yup' +import { Grid } from '@mui/material' + +import GenericForm from 'components/common/form/GenericForm' +import { name, phone, email } from 'common/form/validation' +import SubmitButton from 'components/common/form/SubmitButton' +import FormTextField from 'components/common/form/FormTextField' +import EmailField from 'components/common/form/EmailField' +import { AdminPersonFormData, AdminPersonResponse } from 'gql/person' +import { useMutation } from '@tanstack/react-query' +import { AxiosError, AxiosResponse } from 'axios' +import { ApiErrors } from 'service/apiErrors' +import { useCreatePerson } from 'service/person' +import { AlertStore } from 'stores/AlertStore' +import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' +import { routes } from 'common/routes' +import CheckboxField from 'components/common/form/CheckboxField' +import { useCreateCoordinator } from 'service/coordinator' +import { CoordinatorResponse, CoorinatorInput } from 'gql/coordinators' +import { createOrganizer } from 'service/organizer' +import { OrganizerInput } from 'gql/organizer' +import { BeneficiaryFormData, BeneficiaryListResponse } from 'gql/beneficiary' +import { BeneficiaryType } from 'components/admin/beneficiary/BeneficiaryTypes' +import { useCreateBeneficiary } from 'service/beneficiary' +import OrganizerRelationSelect from 'components/admin/beneficiary/OrganizerRelationSelect' +import CountrySelect from 'components/admin/countries/CountrySelect' +import CitySelect from 'components/admin/cities/CitySelect' + +const validationSchema = yup + .object() + .defined() + .shape({ + firstName: name.required(), + lastName: name.required(), + email: email.required(), + phone: phone.notRequired(), + isCoordinator: yup.bool().required(), + isOrganizer: yup.bool().required(), + isBeneficiary: yup.bool().required(), + description: yup.string().notRequired(), + cityId: yup.string().when('isBeneficiary', { + is: true, + then: yup.string().required(), + otherwise: yup.string().notRequired(), + }), + countryCode: yup.string().when('isBeneficiary', { + is: true, + then: yup.string().required(), + otherwise: yup.string().notRequired(), + }), + organizerRelation: yup.string().when('isBeneficiary', { + is: true, + then: yup.string().required(), + otherwise: yup.string().notRequired(), + }), + }) + +const initialValues: AdminPersonFormData = { + firstName: '', + lastName: '', + email: '', + phone: '', + isOrganizer: false, + isCoordinator: false, + isBeneficiary: false, + countryCode: 'BG', + cityId: '', + description: '', + organizerRelation: 'none', +} + +export default function CreateForm() { + const router = useRouter() + const { t } = useTranslation() + const [showBenefactor, setShowBenefactor] = useState(false) + + const mutation = useMutation< + AxiosResponse, + AxiosError, + AdminPersonFormData + >({ + mutationFn: useCreatePerson(), + onError: () => AlertStore.show(t('common:alerts.error'), 'error'), + }) + + const coordinatorCreateMutation = useMutation< + AxiosResponse, + AxiosError, + CoorinatorInput + >({ + mutationFn: useCreateCoordinator(), + onError: () => AlertStore.show(t('common:alerts.error'), 'error'), + }) + + const organizerCreateMutation = useMutation< + AxiosResponse, + AxiosError, + OrganizerInput + >({ + mutationFn: createOrganizer(), + onError: () => AlertStore.show(t('common:alerts.error'), 'error'), + }) + + const beneficiaryCreateMutation = useMutation< + AxiosResponse, + AxiosError, + BeneficiaryFormData + >({ + mutationFn: useCreateBeneficiary(), + onError: () => AlertStore.show(t('common:alerts.error'), 'error'), + }) + + async function handleSubmit(values: AdminPersonFormData) { + const { data: userResponse } = await mutation.mutateAsync(values) + + if (values.isCoordinator) coordinatorCreateMutation.mutate({ personId: userResponse.id }) + + if (values.isOrganizer) organizerCreateMutation.mutate({ personId: userResponse.id }) + + if (values.isBeneficiary) + beneficiaryCreateMutation.mutate({ + type: BeneficiaryType.individual, + personId: userResponse.id, + countryCode: values.countryCode, + cityId: values.cityId, + organizerRelation: values.organizerRelation, + description: values.description, + campaigns: [], + }) + + AlertStore.show(t('common:alerts.success'), 'success') + router.push(routes.admin.person.index) + } + + return ( + + + + + + + + + + + + + + + + + + + + + + + { + setShowBenefactor(e.target.checked) + }} + /> + + {showBenefactor && ( + <> + + + + + + + + + + + + + + )} + + + + + + + ) +} diff --git a/src/components/common/person/grid/CreatePage.tsx b/src/components/common/person/grid/CreatePage.tsx index 752ef22d6..9633b6cce 100644 --- a/src/components/common/person/grid/CreatePage.tsx +++ b/src/components/common/person/grid/CreatePage.tsx @@ -4,7 +4,7 @@ import { Container } from '@mui/material' import AdminLayout from 'components/common/navigation/AdminLayout' import AdminContainer from 'components/common/navigation/AdminContainer' -import PersonForm from './PersonForm' +import CreateForm from './CreateForm' export default function CreatePage() { const { t } = useTranslation() @@ -13,7 +13,7 @@ export default function CreatePage() { - + diff --git a/src/components/common/person/grid/PersonForm.tsx b/src/components/common/person/grid/EditForm.tsx similarity index 52% rename from src/components/common/person/grid/PersonForm.tsx rename to src/components/common/person/grid/EditForm.tsx index 8bacc578c..1aeaddcc7 100644 --- a/src/components/common/person/grid/PersonForm.tsx +++ b/src/components/common/person/grid/EditForm.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { useState } from 'react' import * as yup from 'yup' import { Grid } from '@mui/material' @@ -22,42 +22,70 @@ import { useCreateCoordinator, useDeleteCoordinator } from 'service/coordinator' import { CoordinatorResponse, CoorinatorInput } from 'gql/coordinators' import { createOrganizer, deleteOrganizer } from 'service/organizer' import { OrganizerInput } from 'gql/organizer' +import { BeneficiaryFormData, BeneficiaryListResponse } from 'gql/beneficiary' +import { BeneficiaryType } from 'components/admin/beneficiary/BeneficiaryTypes' +import { useCreateBeneficiary, useEditBeneficiary, useRemoveBeneficiary } from 'service/beneficiary' +import OrganizerRelationSelect from 'components/admin/beneficiary/OrganizerRelationSelect' +import CountrySelect from 'components/admin/countries/CountrySelect' +import CitySelect from 'components/admin/cities/CitySelect' -const validationSchema: yup.SchemaOf = yup.object().defined().shape({ - firstName: name.required(), - lastName: name.required(), - email: email.required(), - phone: phone.notRequired(), - isBeneficiary: yup.bool().required(), - isCoordinator: yup.bool().required(), - isOrganizer: yup.bool().required(), -}) - -const defaults: AdminPersonFormData = { - firstName: '', - lastName: '', - email: '', - phone: '', - isBeneficiary: false, - isCoordinator: false, - isOrganizer: false, -} - -type FormProps = { - initialValues?: { - coordinatorId?: string - activeCoordinator?: boolean - organizerId?: string - activeOrganizer?: boolean - beneficiaryId?: string - activeBeneficiary?: boolean - } & AdminPersonFormData -} +const validationSchema = yup + .object() + .defined() + .shape({ + firstName: name.required(), + lastName: name.required(), + email: email.required(), + phone: phone.notRequired(), + isCoordinator: yup.bool().required(), + isOrganizer: yup.bool().required(), + isBeneficiary: yup.bool().required(), + description: yup.string().notRequired(), + cityId: yup.string().when('isBeneficiary', { + is: true, + then: yup.string().required(), + otherwise: yup.string().notRequired(), + }), + countryCode: yup.string().when('isBeneficiary', { + is: true, + then: yup.string().required(), + otherwise: yup.string().notRequired(), + }), + organizerRelation: yup.string().when('isBeneficiary', { + is: true, + then: yup.string().required(), + otherwise: yup.string().notRequired(), + }), + }) -export default function PersonForm({ initialValues = defaults }: FormProps) { +export default function EditForm() { const router = useRouter() const { t } = useTranslation() - let editPersonId = router.query.id as string + const editPersonId = router.query.id as string + const { data }: UseQueryResult = usePerson(editPersonId) + + const beneficiary = data?.beneficiaries?.at(0) + const [showBenefactor, setShowBenefactor] = useState(!!beneficiary) + + const initialValues = { + firstName: data?.firstName ?? '', + lastName: data?.lastName ?? '', + email: data?.email ?? '', + phone: data?.phone ?? '', + isCoordinator: !!data?.coordinators, + coordinatorId: data?.coordinators?.id, + activeCoordinator: !!data?.coordinators?._count?.campaigns, + isOrganizer: !!data?.organizer, + organizerId: data?.organizer?.id, + activeOrganizer: !!data?.organizer?._count?.campaigns, + isBeneficiary: !!data?.beneficiaries?.length, + beneficiaryId: beneficiary?.id, + activeBeneficiary: !!beneficiary?._count?.campaigns, + countryCode: beneficiary?.countryCode ?? 'BG', + cityId: beneficiary?.cityId ?? '', + description: beneficiary?.description ?? '', + organizerRelation: beneficiary?.organizerRelation ?? 'none', + } const mutation = useMutation< AxiosResponse, @@ -104,7 +132,25 @@ export default function PersonForm({ initialValues = defaults }: FormProps) { onError: () => AlertStore.show(t('common:alerts.error'), 'error'), }) - async function handleSubmit(values: AdminPersonFormData) { + const beneficiaryMutation = useMutation< + AxiosResponse, + AxiosError, + BeneficiaryFormData + >({ + mutationFn: beneficiary ? useEditBeneficiary(beneficiary.id) : useCreateBeneficiary(), + onError: () => AlertStore.show(t('common:alerts.error'), 'error'), + }) + + const beneficiaryDeleteMutation = useMutation< + AxiosResponse, + AxiosError, + string + >({ + mutationFn: useRemoveBeneficiary(), + onError: () => AlertStore.show(t('common:alerts.error'), 'error'), + }) + + async function handleSubmit(values: AdminPersonFormData & BeneficiaryFormData) { const { data: userResponse } = await mutation.mutateAsync(values) if (values.isCoordinator !== initialValues.isCoordinator) { @@ -119,28 +165,19 @@ export default function PersonForm({ initialValues = defaults }: FormProps) { : organizerCreateMutation.mutate({ personId: userResponse.id }) } - router.push(routes.admin.person.index) - } + !values.isBeneficiary && initialValues.beneficiaryId + ? beneficiaryDeleteMutation.mutate(initialValues.beneficiaryId) + : beneficiaryMutation.mutate({ + type: BeneficiaryType.individual, + personId: userResponse.id, + countryCode: values.countryCode, + cityId: values.cityId, + organizerRelation: values.organizerRelation, + description: values.description, + campaigns: values.campaigns, + }) - if (editPersonId) { - editPersonId = String(editPersonId) - const { data }: UseQueryResult = usePerson(editPersonId) - - initialValues = { - firstName: data?.firstName ?? '', - lastName: data?.lastName ?? '', - email: data?.email ?? '', - phone: data?.phone ?? '', - isBeneficiary: !!data?.beneficiaries?.length, - beneficiaryId: data?.beneficiaries?.at(0)?.id, - activeBeneficiary: !!data?.beneficiaries?.at(0)?._count?.campaigns, - isCoordinator: !!data?.coordinators, - coordinatorId: data?.coordinators?.id, - activeCoordinator: !!data?.coordinators?._count?.campaigns, - isOrganizer: !!data?.organizer, - organizerId: data?.organizer?.id, - activeOrganizer: !!data?.organizer?._count?.campaigns, - } + router.push(routes.admin.person.index) } return ( @@ -167,12 +204,6 @@ export default function PersonForm({ initialValues = defaults }: FormProps) { autoComplete="family-name" /> - - {/* TODO: */} - @@ -185,32 +216,56 @@ export default function PersonForm({ initialValues = defaults }: FormProps) { label="person:admin.fields.phone" /> - + - + - + { + setShowBenefactor(e.target.checked) + }} /> + {showBenefactor && ( + <> + + + + + + + + + + + + + + )} - + diff --git a/src/components/common/person/grid/EditPage.tsx b/src/components/common/person/grid/EditPage.tsx index a4fcf8226..b4eb6026b 100644 --- a/src/components/common/person/grid/EditPage.tsx +++ b/src/components/common/person/grid/EditPage.tsx @@ -4,7 +4,7 @@ import { Container } from '@mui/material' import AdminLayout from 'components/common/navigation/AdminLayout' import AdminContainer from 'components/common/navigation/AdminContainer' -import PersonForm from './PersonForm' +import EditForm from './EditForm' export default function CreatePage() { const { t } = useTranslation() @@ -13,7 +13,7 @@ export default function CreatePage() { - + diff --git a/src/gql/beneficiary.d.ts b/src/gql/beneficiary.d.ts index 399710002..14a62a945 100644 --- a/src/gql/beneficiary.d.ts +++ b/src/gql/beneficiary.d.ts @@ -31,6 +31,6 @@ export type BeneficiaryFormData = { description?: string publicData?: string privateData?: string - campaigns: [] + campaigns?: [] organizerRelation?: PersonRelation } diff --git a/src/gql/person.d.ts b/src/gql/person.d.ts index cbe0e5628..3cb764cc4 100644 --- a/src/gql/person.d.ts +++ b/src/gql/person.d.ts @@ -1,4 +1,5 @@ import { UUID } from './types' +import { BeneficiaryFormData } from './beneficiary' export type PersonResponse = { id: string @@ -11,7 +12,7 @@ export type PersonResponse = { createdAt: string newsletter: boolean emailConfirmed: boolean - beneficiaries?: PersonRoleResponse[] + beneficiaries?: PersonBeneficiaryResponse[] coordinators?: PersonRoleResponse organizer?: PersonRoleResponse } @@ -23,6 +24,17 @@ export type PersonRoleResponse = { } } +export type PersonBeneficiaryResponse = { + id: string + countryCode: string + cityId: string + description?: string + organizerRelation?: PersonRelation + _count?: { + campaigns: number + } +} + export type PersonPaginatedResponse = { items: PersonResponse[] total: number @@ -97,7 +109,8 @@ export type UpdateUserAccount = { export type AdminPersonFormData = Pick< PersonFormData, 'firstName' | 'lastName' | 'email' | 'phone' | 'isBeneficiary' | 'isCoordinator' | 'isOrganizer' -> +> & + Pick export type AdminPersonResponse = Pick< PersonResponse, From 5307714532b4cc4bcf7e835351a836714f92fc90 Mon Sep 17 00:00:00 2001 From: Tony Date: Tue, 19 Sep 2023 20:22:42 +0300 Subject: [PATCH 4/6] disallow beneficiary toggle --- src/components/common/person/grid/EditForm.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/common/person/grid/EditForm.tsx b/src/components/common/person/grid/EditForm.tsx index 1aeaddcc7..76f39fdf9 100644 --- a/src/components/common/person/grid/EditForm.tsx +++ b/src/components/common/person/grid/EditForm.tsx @@ -67,6 +67,9 @@ export default function EditForm() { const beneficiary = data?.beneficiaries?.at(0) const [showBenefactor, setShowBenefactor] = useState(!!beneficiary) + console.log(data) + console.log('active', !!beneficiary?._count?.campaigns) + const initialValues = { firstName: data?.firstName ?? '', lastName: data?.lastName ?? '', @@ -233,6 +236,7 @@ export default function EditForm() { { setShowBenefactor(e.target.checked) From f4dc18c3e275955836dde115f819edcb00d6dc8b Mon Sep 17 00:00:00 2001 From: Tony Date: Tue, 19 Sep 2023 20:23:31 +0300 Subject: [PATCH 5/6] remove debug logs --- src/components/common/person/grid/EditForm.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/components/common/person/grid/EditForm.tsx b/src/components/common/person/grid/EditForm.tsx index 76f39fdf9..1029755fb 100644 --- a/src/components/common/person/grid/EditForm.tsx +++ b/src/components/common/person/grid/EditForm.tsx @@ -67,9 +67,6 @@ export default function EditForm() { const beneficiary = data?.beneficiaries?.at(0) const [showBenefactor, setShowBenefactor] = useState(!!beneficiary) - console.log(data) - console.log('active', !!beneficiary?._count?.campaigns) - const initialValues = { firstName: data?.firstName ?? '', lastName: data?.lastName ?? '', From db63725f4c18b99e2e176689c7b7d822978200e4 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 20 Sep 2023 14:08:21 +0300 Subject: [PATCH 6/6] show disabled checkbox tooltip --- public/locales/bg/person.json | 3 +- public/locales/en/person.json | 3 +- src/components/common/form/CheckboxField.tsx | 36 ++++++++++--------- .../common/person/grid/EditForm.tsx | 24 +++++++++---- 4 files changed, 42 insertions(+), 24 deletions(-) diff --git a/public/locales/bg/person.json b/public/locales/bg/person.json index edf923cf8..859f7c3b8 100644 --- a/public/locales/bg/person.json +++ b/public/locales/bg/person.json @@ -44,7 +44,8 @@ "organizerRelation": "Отношения с организатор", "countryCode": "Държава", "city": "Град", - "description": "Описание" + "description": "Описание", + "disabled-tooltip": "Ролята не може да бъде премахната, потребителя е {{role}} в {{campaigns}} кампании" }, "cta": { "create": "Създай", diff --git a/public/locales/en/person.json b/public/locales/en/person.json index 2079aea08..d1c490832 100644 --- a/public/locales/en/person.json +++ b/public/locales/en/person.json @@ -45,7 +45,8 @@ "organizerRelation": "Organizer relation", "countryCode": "Country code", "city": "City", - "description": "Description" + "description": "Description", + "disabled-tooltip": "Cannot remove role because the user is {{role}} in {{campaigns}} campaigns" }, "cta": { "create": "Create", diff --git a/src/components/common/form/CheckboxField.tsx b/src/components/common/form/CheckboxField.tsx index 17c1c0e8f..665067c1e 100644 --- a/src/components/common/form/CheckboxField.tsx +++ b/src/components/common/form/CheckboxField.tsx @@ -2,7 +2,7 @@ import { ChangeEvent } from 'react' import { useField } from 'formik' import { useTranslation } from 'next-i18next' -import { Checkbox, FormControl, FormControlLabel, FormHelperText } from '@mui/material' +import { Checkbox, FormControl, FormControlLabel, FormHelperText, Tooltip } from '@mui/material' import { TranslatableField, translateError } from 'common/form/validation' @@ -11,6 +11,7 @@ export type CheckboxFieldProps = { disabled?: boolean onChange?: (e: ChangeEvent) => void label: string | number | React.ReactElement + disabledTooltip?: string } export default function CheckboxField({ @@ -18,27 +19,30 @@ export default function CheckboxField({ disabled, onChange: handleChange, label, + disabledTooltip, }: CheckboxFieldProps) { const { t } = useTranslation() const [field, meta] = useField(name) const helperText = meta.touched ? translateError(meta.error as TranslatableField, t) : '' return ( - { - field.onChange(e) - if (handleChange) handleChange(e) - }} - /> - } - /> + + { + field.onChange(e) + if (handleChange) handleChange(e) + }} + /> + } + /> + {Boolean(meta.error) && {helperText}} ) diff --git a/src/components/common/person/grid/EditForm.tsx b/src/components/common/person/grid/EditForm.tsx index 1029755fb..8fc05ab7a 100644 --- a/src/components/common/person/grid/EditForm.tsx +++ b/src/components/common/person/grid/EditForm.tsx @@ -74,13 +74,13 @@ export default function EditForm() { phone: data?.phone ?? '', isCoordinator: !!data?.coordinators, coordinatorId: data?.coordinators?.id, - activeCoordinator: !!data?.coordinators?._count?.campaigns, + coordinatorCampaigns: data?.coordinators?._count?.campaigns, isOrganizer: !!data?.organizer, organizerId: data?.organizer?.id, - activeOrganizer: !!data?.organizer?._count?.campaigns, + organizerCampaigns: data?.organizer?._count?.campaigns, isBeneficiary: !!data?.beneficiaries?.length, beneficiaryId: beneficiary?.id, - activeBeneficiary: !!beneficiary?._count?.campaigns, + beneficiaryCampaigns: beneficiary?._count?.campaigns, countryCode: beneficiary?.countryCode ?? 'BG', cityId: beneficiary?.cityId ?? '', description: beneficiary?.description ?? '', @@ -219,21 +219,33 @@ export default function EditForm() { { setShowBenefactor(e.target.checked)