Fix people deletion

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2025-12-22 14:30:25 +01:00
parent 0da25edc15
commit 233e197fdb
5 changed files with 186 additions and 36 deletions

View File

@@ -11,6 +11,7 @@ import {
ActionDropdown,
DropdownItem,
IconTrashCan,
IconCalendar2,
} from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import type { PeopleGraphPaginatedQuery } from "/hooks/graph/__generated__/PeopleGraphPaginatedQuery.graphql";
@@ -22,9 +23,10 @@ import type { NodeOf } from "/types";
import { usePageTitle } from "@probo/hooks";
import { getRole } from "@probo/helpers";
import { CreatePeopleDialog } from "./dialogs/CreatePeopleDialog";
import { SetEndOfContractDialog, type SetEndOfContractDialogRef } from "./dialogs/SetEndOfContractDialog";
import { useOrganizationId } from "/hooks/useOrganizationId";
import { PermissionsContext } from "/providers/PermissionsContext";
import { use } from "react";
import { use, useRef } from "react";
type People = NodeOf<PeopleGraphPaginatedFragment$data["peoples"]>;
@@ -108,40 +110,56 @@ function PeopleRow({
const deletePeople = useDeletePeople(people, connectionId);
const contractEnded = isContractEnded(people);
const { isAuthorized } = use(PermissionsContext);
const dialogRef = useRef<SetEndOfContractDialogRef>(null);
return (
<Tr
to={`/organizations/${organizationId}/people/${people.id}/tasks`}
className={contractEnded ? "opacity-50" : ""}
>
<Td>
<div className="flex gap-3 items-center">
<Avatar name={people.fullName} />
<div>
<div className="text-sm">{people.fullName}</div>
<div className="text-xs text-txt-tertiary">
{people.primaryEmailAddress}
<>
<SetEndOfContractDialog
peopleId={people.id}
currentContractEndDate={people.contractEndDate}
ref={dialogRef}
/>
<Tr
to={`/organizations/${organizationId}/people/${people.id}/profile`}
className={contractEnded ? "opacity-50" : ""}
>
<Td>
<div className="flex gap-3 items-center">
<Avatar name={people.fullName} />
<div>
<div className="text-sm">{people.fullName}</div>
<div className="text-xs text-txt-tertiary">
{people.primaryEmailAddress}
</div>
</div>
</div>
</div>
</Td>
<Td className="text-sm">{getRole(__, people.kind)}</Td>
<Td className="text-sm">{people.position}</Td>
{hasAnyAction && (
<Td noLink width={50} className="text-end">
<ActionDropdown>
{isAuthorized("People", "deletePeople") && (
<DropdownItem
icon={IconTrashCan}
variant="danger"
onClick={deletePeople}
>
{__("Delete")}
</DropdownItem>
)}
</ActionDropdown>
</Td>
)}
</Tr>
<Td className="text-sm">{getRole(__, people.kind)}</Td>
<Td className="text-sm">{people.position}</Td>
{hasAnyAction && (
<Td noLink width={50} className="text-end">
<ActionDropdown>
{isAuthorized("People", "updatePeople") && (
<DropdownItem
icon={IconCalendar2}
onClick={() => dialogRef.current?.open()}
>
{__("Set end of contract")}
</DropdownItem>
)}
{isAuthorized("People", "deletePeople") && (
<DropdownItem
icon={IconTrashCan}
variant="danger"
onClick={deletePeople}
>
{__("Delete")}
</DropdownItem>
)}
</ActionDropdown>
</Td>
)}
</Tr>
</>
);
}

View File

@@ -0,0 +1,107 @@
import { useTranslate } from "@probo/i18n";
import {
Button,
Dialog,
DialogContent,
DialogFooter,
Field,
Input,
Spinner,
useDialogRef,
} from "@probo/ui";
import { forwardRef, useImperativeHandle } from "react";
import { z } from "zod";
import { formatDatetime, toDateInput } from "@probo/helpers";
import { useFormWithSchema } from "/hooks/useFormWithSchema";
import { useMutationWithToasts } from "/hooks/useMutationWithToasts";
import { updatePeopleMutation } from "/hooks/graph/PeopleGraph";
const schema = z.object({
contractEndDate: z.string().optional(),
});
export type SetEndOfContractDialogRef = {
open: () => void;
close: () => void;
};
type Props = {
peopleId: string;
currentContractEndDate?: string | null;
};
export const SetEndOfContractDialog = forwardRef<SetEndOfContractDialogRef, Props>(function SetEndOfContractDialog(
{
peopleId,
currentContractEndDate,
},
ref
) {
const { __ } = useTranslate();
const dialogRef = useDialogRef();
useImperativeHandle(ref, () => ({
open: () => dialogRef.current?.open(),
close: () => dialogRef.current?.close(),
}));
const {
register,
handleSubmit,
formState: { isSubmitting },
reset,
} = useFormWithSchema(schema, {
defaultValues: {
contractEndDate: toDateInput(currentContractEndDate),
},
});
const [mutate] = useMutationWithToasts(updatePeopleMutation, {
successMessage: __("End of contract updated successfully"),
errorMessage: __("Failed to update end of contract"),
});
const onSubmit = handleSubmit(async (data) => {
await mutate({
variables: {
input: {
id: peopleId,
contractEndDate: formatDatetime(data.contractEndDate),
},
},
});
dialogRef.current?.close();
});
const handleClose = () => {
reset();
};
return (
<Dialog
title={__("Set End of Contract")}
ref={dialogRef}
className="max-w-lg"
onClose={handleClose}
>
<form onSubmit={onSubmit}>
<DialogContent padded className="space-y-4">
<Field label={__("End of contract")}>
<Input {...register("contractEndDate")} type="date" />
</Field>
</DialogContent>
<DialogFooter>
<Button
type="submit"
disabled={isSubmitting}
icon={isSubmitting ? Spinner : undefined}
>
{__("Update")}
</Button>
</DialogFooter>
</form>
</Dialog>
);
});