feat: optimistically update when deleting an availability (#4648)
* feat: use optimistic updates for deleting * feat: remove loading props * feat: remove loading props from v1 component Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: Alex van Andel <me@alexvanandel.com>pull/4656/head^2
parent
ca859c871c
commit
f14b13a1ba
|
@ -51,7 +51,6 @@ export function AvailabilityList({ schedules }: inferQueryOutput<"viewer.availab
|
||||||
key={schedule.id}
|
key={schedule.id}
|
||||||
schedule={schedule}
|
schedule={schedule}
|
||||||
deleteFunction={deleteMutation.mutate}
|
deleteFunction={deleteMutation.mutate}
|
||||||
isDeleting={deleteMutation.isLoading}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -21,16 +21,32 @@ export function AvailabilityList({ schedules }: inferQueryOutput<"viewer.availab
|
||||||
const meQuery = trpc.useQuery(["viewer.me"]);
|
const meQuery = trpc.useQuery(["viewer.me"]);
|
||||||
|
|
||||||
const deleteMutation = trpc.useMutation("viewer.availability.schedule.delete", {
|
const deleteMutation = trpc.useMutation("viewer.availability.schedule.delete", {
|
||||||
onSuccess: async () => {
|
onMutate: async ({ scheduleId }) => {
|
||||||
await utils.invalidateQueries(["viewer.availability.list"]);
|
await utils.cancelQuery(["viewer.availability.list"]);
|
||||||
showToast(t("schedule_deleted_successfully"), "success");
|
const previousValue = utils.getQueryData(["viewer.availability.list"]);
|
||||||
|
if (previousValue) {
|
||||||
|
const filteredValue = previousValue.schedules.filter(({ id }) => id !== scheduleId);
|
||||||
|
utils.setQueryData(["viewer.availability.list"], { ...previousValue, schedules: filteredValue });
|
||||||
|
}
|
||||||
|
|
||||||
|
return { previousValue };
|
||||||
},
|
},
|
||||||
onError: (err) => {
|
|
||||||
|
onError: (err, variables, context) => {
|
||||||
|
if (context?.previousValue) {
|
||||||
|
utils.setQueryData(["viewer.availability.list"], context.previousValue);
|
||||||
|
}
|
||||||
if (err instanceof HttpError) {
|
if (err instanceof HttpError) {
|
||||||
const message = `${err.statusCode}: ${err.message}`;
|
const message = `${err.statusCode}: ${err.message}`;
|
||||||
showToast(message, "error");
|
showToast(message, "error");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onSettled: () => {
|
||||||
|
utils.invalidateQueries(["viewer.availability.list"]);
|
||||||
|
},
|
||||||
|
onSuccess: () => {
|
||||||
|
showToast(t("schedule_deleted_successfully"), "success");
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Adds smooth delete button - item fades and old item slides into place
|
// Adds smooth delete button - item fades and old item slides into place
|
||||||
|
@ -61,7 +77,6 @@ export function AvailabilityList({ schedules }: inferQueryOutput<"viewer.availab
|
||||||
key={schedule.id}
|
key={schedule.id}
|
||||||
schedule={schedule}
|
schedule={schedule}
|
||||||
deleteFunction={deleteMutation.mutate}
|
deleteFunction={deleteMutation.mutate}
|
||||||
isDeleting={deleteMutation.isLoading}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -13,12 +13,10 @@ import Button from "@calcom/ui/v2/core/Button";
|
||||||
export function ScheduleListItem({
|
export function ScheduleListItem({
|
||||||
schedule,
|
schedule,
|
||||||
deleteFunction,
|
deleteFunction,
|
||||||
isDeleting = false,
|
|
||||||
displayOptions,
|
displayOptions,
|
||||||
}: {
|
}: {
|
||||||
schedule: inferQueryOutput<"viewer.availability.list">["schedules"][number];
|
schedule: inferQueryOutput<"viewer.availability.list">["schedules"][number];
|
||||||
deleteFunction: ({ scheduleId }: { scheduleId: number }) => void;
|
deleteFunction: ({ scheduleId }: { scheduleId: number }) => void;
|
||||||
isDeleting: boolean;
|
|
||||||
displayOptions?: {
|
displayOptions?: {
|
||||||
timeZone?: string;
|
timeZone?: string;
|
||||||
hour12?: boolean;
|
hour12?: boolean;
|
||||||
|
@ -67,7 +65,6 @@ export function ScheduleListItem({
|
||||||
<DropdownMenuContent>
|
<DropdownMenuContent>
|
||||||
<DropdownMenuItem>
|
<DropdownMenuItem>
|
||||||
<Button
|
<Button
|
||||||
disabled={isDeleting}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
deleteFunction({
|
deleteFunction({
|
||||||
scheduleId: schedule.id,
|
scheduleId: schedule.id,
|
||||||
|
@ -76,9 +73,8 @@ export function ScheduleListItem({
|
||||||
type="button"
|
type="button"
|
||||||
color="destructive"
|
color="destructive"
|
||||||
className="w-full font-normal"
|
className="w-full font-normal"
|
||||||
StartIcon={isDeleting ? undefined : Icon.FiTrash}
|
StartIcon={Icon.FiTrash}>
|
||||||
loading={isDeleting}>
|
{t("delete_schedule")}
|
||||||
{isDeleting ? t("deleting") : t("delete_schedule")}
|
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
|
|
Loading…
Reference in New Issue