diff --git a/app/Dashboard/Households/HouseholdDetail/_components/MemberForm/MemberForm.tsx b/app/Dashboard/Households/HouseholdDetail/_components/MemberForm/MemberForm.tsx index 6e1c2353..a54ec369 100644 --- a/app/Dashboard/Households/HouseholdDetail/_components/MemberForm/MemberForm.tsx +++ b/app/Dashboard/Households/HouseholdDetail/_components/MemberForm/MemberForm.tsx @@ -1,5 +1,9 @@ /* eslint-disable max-lines-per-function */ -import { useUpsertMemberMutation } from '@camp/data-layer'; +import { + useDeleteMemberMutation, + useUpsertMemberMutation, +} from '@camp/data-layer'; +import { debug } from '@camp/debug'; import { ControlledDateInput, ControlledSelect, @@ -24,6 +28,7 @@ import { import { ArrowDownIcon, CheckIcon, EditIcon, TrashIcon } from '@camp/icons'; import { messages } from '@camp/messages'; import { createTestAttr } from '@camp/test'; +import { isNull } from '@fullstacksjs/toolbox'; import { ActionIcon, Button, @@ -78,6 +83,7 @@ const resolver = createResolver({ const t = messages.member; const tt = t.createForm; +const tNotification = messages.notification.member; interface Props { initialMember?: MemberListItem; @@ -100,6 +106,34 @@ export const MemberForm = ({ !initialMember, ); const { classes } = useStyles(); + const [deleteMember] = useDeleteMemberMutation(); + + const onDeleteMember = async () => { + const member = initialMember; + const id = memberId; + + if (!member || !id) return; + + try { + const { data } = await deleteMember({ + variables: { id }, + }); + + if (isNull(data.member)) throw Error('Assert: data is null'); + showNotification({ + title: tNotification.delete.title, + message: tNotification.delete.success(member.name), + type: 'success', + }); + } catch (err) { + debug.error(err); + showNotification({ + title: tNotification.delete.title, + message: tNotification.delete.failed(member.name), + type: 'failure', + }); + } + }; const { handleSubmit, @@ -255,6 +289,7 @@ export const MemberForm = ({ variant="outline" color="red" leftIcon={} + onClick={() => onDeleteMember()} > {messages.actions.delete} diff --git a/app/Dashboard/Households/HouseholdDetail/_components/MemberList/MemberList.tsx b/app/Dashboard/Households/HouseholdDetail/_components/MemberList/MemberList.tsx index d1868475..4090565d 100644 --- a/app/Dashboard/Households/HouseholdDetail/_components/MemberList/MemberList.tsx +++ b/app/Dashboard/Households/HouseholdDetail/_components/MemberList/MemberList.tsx @@ -19,6 +19,7 @@ export const MemberList = ({ householdId }: Props) => { const { data, error, loading } = useMemberListQuery({ variables: { id: householdId }, }); + const member = data?.members; const isMemberEmpty = member?.length === 0 && newMembers.length === 0; debug.trace('MemberList', member); diff --git a/app/messages.ts b/app/messages.ts index eed7975e..f0d6db75 100644 --- a/app/messages.ts +++ b/app/messages.ts @@ -22,6 +22,14 @@ export const messages = { `مشکلی در تکمیل خانوار "${name}" به وجود آمده است. لطفا دوباره تلاش کنید.`, }, }, + member: { + delete: { + title: 'حذف عضو', + success: (name: string) => `عضو “${name}” با موفقیت حذف شد.`, + failed: (name: string) => + `مشکلی در مرحله حذف عضو "${name}" به وجود آمده است. لطفا دوباره تلاش کنید.`, + }, + }, }, date: { format: (date: Date) => new Intl.DateTimeFormat('fa-IR').format(date), diff --git a/libs/data-layer/ApiOperations.ts b/libs/data-layer/ApiOperations.ts index 05a2d212..14ce3753 100644 --- a/libs/data-layer/ApiOperations.ts +++ b/libs/data-layer/ApiOperations.ts @@ -13,9 +13,9 @@ export type ApiHouseholderKeysFragment = { __typename?: 'householder', id: strin export type ApiHouseholderIdentityFragment = { __typename?: 'householder', name: string, father_name?: string | null, surname?: string | null, nationality?: SchemaTypes.NationalityEnum | null, religion?: SchemaTypes.ReligionEnum | null, city?: SchemaTypes.CityEnum | null, gender?: SchemaTypes.GenderEnum | null, status?: string | null, national_id?: string | null, dob?: string | null }; -export type ApiMemberKeysFragment = { __typename?: 'member', id: string }; +export type ApiMemberKeysFragment = { __typename?: 'member', id: string, household_id: string }; -export type ApiMemberListItemFragment = { __typename?: 'member', dob?: string | null, father_name?: string | null, gender?: SchemaTypes.GenderEnum | null, name: string, national_id?: string | null, nationality?: SchemaTypes.NationalityEnum | null, religion?: SchemaTypes.ReligionEnum | null, surname?: string | null, household_id: string, status?: string | null }; +export type ApiMemberListItemFragment = { __typename?: 'member', dob?: string | null, father_name?: string | null, gender?: SchemaTypes.GenderEnum | null, name: string, national_id?: string | null, nationality?: SchemaTypes.NationalityEnum | null, religion?: SchemaTypes.ReligionEnum | null, surname?: string | null, status?: string | null }; export type ApiProjectKeysFragment = { __typename?: 'project', id: string }; @@ -44,12 +44,19 @@ export type ApiCreateProjectMutationVariables = SchemaTypes.Exact<{ export type ApiCreateProjectMutation = { __typename?: 'mutation_root', insert_project_one?: { __typename?: 'project', id: string, name: string, description?: string | null, start_date?: string | null, due_date?: string | null, status: SchemaTypes.ProjectStatusEnum, created_at: string, updated_at: string } | null }; -export type ApiDeleteHouseholdMutationMutationVariables = SchemaTypes.Exact<{ +export type ApiDeleteHouseholdMutationVariables = SchemaTypes.Exact<{ id: SchemaTypes.Scalars['uuid']['input']; }>; -export type ApiDeleteHouseholdMutationMutation = { __typename?: 'mutation_root', delete_household_by_pk?: { __typename?: 'household', name: string, id: string } | null }; +export type ApiDeleteHouseholdMutation = { __typename?: 'mutation_root', delete_household_by_pk?: { __typename?: 'household', name: string, id: string } | null }; + +export type ApiDeleteMemberMutationVariables = SchemaTypes.Exact<{ + id: SchemaTypes.Scalars['uuid']['input']; +}>; + + +export type ApiDeleteMemberMutation = { __typename?: 'mutation_root', delete_member_by_pk?: { __typename?: 'member', name: string, id: string, household_id: string } | null }; export type ApiEditHouseholdMutationVariables = SchemaTypes.Exact<{ id: SchemaTypes.Scalars['uuid']['input']; @@ -71,7 +78,7 @@ export type ApiUpsertMemberMutationVariables = SchemaTypes.Exact<{ }>; -export type ApiUpsertMemberMutation = { __typename?: 'mutation_root', insert_member_one?: { __typename?: 'member', id: string, dob?: string | null, father_name?: string | null, gender?: SchemaTypes.GenderEnum | null, name: string, national_id?: string | null, nationality?: SchemaTypes.NationalityEnum | null, religion?: SchemaTypes.ReligionEnum | null, surname?: string | null, household_id: string, status?: string | null, household: { __typename?: 'household', id: string, name: string, status: SchemaTypes.HouseholdStatusEnum, severity: SchemaTypes.HouseholdSeverityEnum, code?: string | null, created_at: string, updated_at: string } } | null }; +export type ApiUpsertMemberMutation = { __typename?: 'mutation_root', insert_member_one?: { __typename?: 'member', id: string, household_id: string, dob?: string | null, father_name?: string | null, gender?: SchemaTypes.GenderEnum | null, name: string, national_id?: string | null, nationality?: SchemaTypes.NationalityEnum | null, religion?: SchemaTypes.ReligionEnum | null, surname?: string | null, status?: string | null, household: { __typename?: 'household', id: string, name: string, status: SchemaTypes.HouseholdStatusEnum, severity: SchemaTypes.HouseholdSeverityEnum, code?: string | null, created_at: string, updated_at: string } } | null }; export type ApiHouseholdListQueryVariables = SchemaTypes.Exact<{ [key: string]: never; }>; @@ -97,7 +104,7 @@ export type ApiMemberListQueryVariables = SchemaTypes.Exact<{ }>; -export type ApiMemberListQuery = { __typename?: 'query_root', member: Array<{ __typename?: 'member', id: string, dob?: string | null, father_name?: string | null, gender?: SchemaTypes.GenderEnum | null, name: string, national_id?: string | null, nationality?: SchemaTypes.NationalityEnum | null, religion?: SchemaTypes.ReligionEnum | null, surname?: string | null, household_id: string, status?: string | null, household: { __typename?: 'household', id: string, name: string, status: SchemaTypes.HouseholdStatusEnum, severity: SchemaTypes.HouseholdSeverityEnum, code?: string | null, created_at: string, updated_at: string } }> }; +export type ApiMemberListQuery = { __typename?: 'query_root', member: Array<{ __typename?: 'member', id: string, household_id: string, dob?: string | null, father_name?: string | null, gender?: SchemaTypes.GenderEnum | null, name: string, national_id?: string | null, nationality?: SchemaTypes.NationalityEnum | null, religion?: SchemaTypes.ReligionEnum | null, surname?: string | null, status?: string | null, household: { __typename?: 'household', id: string, name: string, status: SchemaTypes.HouseholdStatusEnum, severity: SchemaTypes.HouseholdSeverityEnum, code?: string | null, created_at: string, updated_at: string } }> }; export type ApiProjectListQueryVariables = SchemaTypes.Exact<{ offset?: SchemaTypes.InputMaybe; diff --git a/libs/data-layer/operations/fragments/index.ts b/libs/data-layer/operations/fragments/index.ts index 21537d75..ea9629d7 100644 --- a/libs/data-layer/operations/fragments/index.ts +++ b/libs/data-layer/operations/fragments/index.ts @@ -2,6 +2,8 @@ export * from './household.fragments'; export * from './household.mapper'; export * from './householder.fragments'; export * from './householder.mapper'; +export * from './member.fragments'; +export * from './member.mapper'; export * from './project.fragment'; export * from './project.mapper'; export * from './scalar.mapper'; diff --git a/libs/data-layer/operations/fragments/member.fragments.ts b/libs/data-layer/operations/fragments/member.fragments.ts index f262011d..f2946e0d 100644 --- a/libs/data-layer/operations/fragments/member.fragments.ts +++ b/libs/data-layer/operations/fragments/member.fragments.ts @@ -3,6 +3,7 @@ import { gql } from '@apollo/client'; export const MemberKeysFragment = gql` fragment MemberKeys on member { id + household_id } `; @@ -16,7 +17,6 @@ export const MemberListItemFragment = gql` nationality religion surname - household_id status } `; diff --git a/libs/data-layer/operations/mutations/index.ts b/libs/data-layer/operations/mutations/index.ts index f8feadb0..bfe95c33 100644 --- a/libs/data-layer/operations/mutations/index.ts +++ b/libs/data-layer/operations/mutations/index.ts @@ -2,6 +2,7 @@ export * from './useCompleteHousehold'; export * from './useCreateHouseholdMutation'; export * from './useCreateProjectMutation'; export * from './useDeleteHouseholdMutation'; +export * from './useDeleteMemberMutation'; export * from './useEditHouseholdMutation'; export * from './useUpsertHouseholderMutation'; export * from './useUpsertMemberMutation'; diff --git a/libs/data-layer/operations/mutations/useDeleteHouseholdMutation.ts b/libs/data-layer/operations/mutations/useDeleteHouseholdMutation.ts index 692a0515..2a581dbd 100644 --- a/libs/data-layer/operations/mutations/useDeleteHouseholdMutation.ts +++ b/libs/data-layer/operations/mutations/useDeleteHouseholdMutation.ts @@ -2,19 +2,19 @@ import { gql } from '@apollo/client'; import type { MutationOptions } from '@camp/api-client'; import { useMutation } from '@camp/api-client'; import type { - ApiDeleteHouseholdMutationMutation, - ApiDeleteHouseholdMutationMutationVariables, + ApiDeleteHouseholdMutation, + ApiDeleteHouseholdMutationVariables, ApiHouseholdListQuery, ApiHouseholdListQueryVariables, } from '@camp/data-layer'; import type { Household, HouseholdKeys } from '@camp/domain'; import { isNull } from '@fullstacksjs/toolbox'; -import { HouseholdKeysFragment } from '../fragments'; +import { getHouseholdKeys, HouseholdKeysFragment } from '../fragments'; import { HouseholdListDocument } from '../queries'; const Document = gql` - mutation DeleteHouseholdMutation($id: uuid!) { + mutation DeleteHousehold($id: uuid!) { delete_household_by_pk(id: $id) { ...HouseholdKeys name @@ -27,14 +27,12 @@ export interface DeleteHousehold { household: (HouseholdKeys & Pick) | undefined; } -const toClient = ( - data: ApiDeleteHouseholdMutationMutation | null, -): DeleteHousehold => { +const toClient = (data: ApiDeleteHouseholdMutation | null): DeleteHousehold => { const deleted = data?.delete_household_by_pk; return { household: !isNull(deleted) - ? { id: deleted.id, name: deleted.name } + ? { ...getHouseholdKeys(deleted), name: deleted.name } : undefined, }; }; @@ -45,7 +43,7 @@ interface Variables { const toApiVariables = ( variables: Variables, -): ApiDeleteHouseholdMutationMutationVariables => ({ +): ApiDeleteHouseholdMutationVariables => ({ id: variables.id, }); diff --git a/libs/data-layer/operations/mutations/useDeleteMemberMutation.ts b/libs/data-layer/operations/mutations/useDeleteMemberMutation.ts new file mode 100644 index 00000000..c994391b --- /dev/null +++ b/libs/data-layer/operations/mutations/useDeleteMemberMutation.ts @@ -0,0 +1,76 @@ +import { gql } from '@apollo/client'; +import type { MutationOptions } from '@camp/api-client'; +import { useMutation } from '@camp/api-client'; +import type { + ApiDeleteMemberMutation, + ApiDeleteMemberMutationVariables, + ApiMemberListQuery, + ApiMemberListQueryVariables, +} from '@camp/data-layer'; +import type { Member, MemberKeys } from '@camp/domain'; +import { isNull } from '@fullstacksjs/toolbox'; + +import { getMemberKeys, MemberKeysFragment } from '../fragments'; +import { MemberListDocument } from '../queries'; + +const Document = gql` + mutation DeleteMember($id: uuid!) { + delete_member_by_pk(id: $id) { + ...MemberKeys + name + } + } + ${MemberKeysFragment} +`; + +export interface DeleteMember { + member: (MemberKeys & Pick) | undefined; +} + +const toClient = (data: ApiDeleteMemberMutation | null): DeleteMember => { + const deleted = data?.delete_member_by_pk; + + return { + member: !isNull(deleted) + ? { ...getMemberKeys(deleted), name: deleted.name } + : undefined, + }; +}; + +interface Variables { + id: string; +} + +const toApiVariables = ( + variables: Variables, +): ApiDeleteMemberMutationVariables => ({ + id: variables.id, +}); + +export const useDeleteMemberMutation = ( + options?: MutationOptions, +) => { + return useMutation(Document, { + ...options, + toClient, + toApiVariables, + update(cache, { data }) { + const { id, household_id: householdId } = data?.delete_member_by_pk ?? {}; + if (!id || !householdId) return; + + cache.updateQuery( + { + query: MemberListDocument, + variables: { household_id: householdId }, + overwrite: true, + }, + value => { + return { + ...value, + member: value?.member.filter(h => h.id !== id) ?? [], + }; + }, + ); + }, + }); +}; diff --git a/libs/data-layer/operations/mutations/useUpsertMemberMutation.ts b/libs/data-layer/operations/mutations/useUpsertMemberMutation.ts index 918e93d3..3281cfd8 100644 --- a/libs/data-layer/operations/mutations/useUpsertMemberMutation.ts +++ b/libs/data-layer/operations/mutations/useUpsertMemberMutation.ts @@ -13,12 +13,14 @@ import type { ApiUpsertMemberMutation, ApiUpsertMemberMutationVariables, } from '../../ApiOperations'; -import { HouseholdDetailFragment, HouseholdKeysFragment } from '../fragments'; import { + getMemberKeys, + getMemberListItem, + HouseholdDetailFragment, + HouseholdKeysFragment, MemberKeysFragment, MemberListItemFragment, -} from '../fragments/member.fragments'; -import { getMemberKeys, getMemberListItem } from '../fragments/member.mapper'; +} from '../fragments'; import { MemberListDocument } from '../queries'; const Document = gql` diff --git a/libs/data-layer/operations/queries/useMemberListQuery.ts b/libs/data-layer/operations/queries/useMemberListQuery.ts index 678982e0..c3fc3942 100644 --- a/libs/data-layer/operations/queries/useMemberListQuery.ts +++ b/libs/data-layer/operations/queries/useMemberListQuery.ts @@ -8,12 +8,14 @@ import type { ApiMemberListQuery, ApiMemberListQueryVariables, } from '../../ApiOperations'; -import { HouseholdDetailFragment, HouseholdKeysFragment } from '../fragments'; import { + getMemberKeys, + getMemberListItem, + HouseholdDetailFragment, + HouseholdKeysFragment, MemberKeysFragment, MemberListItemFragment, -} from '../fragments/member.fragments'; -import { getMemberKeys, getMemberListItem } from '../fragments/member.mapper'; +} from '../fragments'; export const MemberListDocument = gql` query MemberList($household_id: uuid!) {