Skip to content

Commit

Permalink
feat(frontend): Add confirm alert to dialog when isDirty is true
Browse files Browse the repository at this point in the history
  • Loading branch information
aXenDeveloper committed Mar 3, 2024
1 parent f3b092f commit ce799e2
Show file tree
Hide file tree
Showing 22 changed files with 94 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const useCreateEditLangAdmin = ({ data }: Args) => {
toast(t(data ? "edit.success" : "create.success"), {
description: values.name
});
setOpen(false);
setOpen?.(false);
};

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const useDownloadLangAdmin = ({
return;
}

setOpen(false);
setOpen?.(false);

window.open(
`${CONFIG.backend_url}/files/${mutation.data.admin__core_languages__download}`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export const useUpdateLangAdmin = ({
return;
}

setOpen(false);
setOpen?.(false);
toast.success(t("success"), {
description: name
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const useCreatePluginAdmin = () => {
description: values.name
});

setOpen(false);
setOpen?.(false);
};

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export const useCreateEditNavAdmin = ({ data }: CreateEditNavAdminArgs) => {
description: convertText(values.name)
});

setOpen(false);
setOpen?.(false);
};

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const ContentDeleteActionTableNavAdmin = ({
return (
<form action={onSubmit}>
<AlertDialogHeader>
<AlertDialogTitle>{tCore("are_your_sure")}</AlertDialogTitle>
<AlertDialogTitle>{tCore("are_you_sure")}</AlertDialogTitle>
<AlertDialogDescription>
{t.rich("desc", {
name: () => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export const useCreateThemeAdmin = () => {
description: values.name
});

setOpen(false);
setOpen?.(false);
};

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const useThemeUpload = () => {
return;
}

setOpen(false);
setOpen?.(false);
toast.success(t("success"));
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const useDownloadThemeAdmin = ({
return;
}

setOpen(false);
setOpen?.(false);

window.open(
`${CONFIG.backend_url}/files/${mutation.data.admin__core_themes__download}`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export const useEditThemeAdmin = ({
toast.success(t("success"), {
description: values.name
});
setOpen(false);
setOpen?.(false);
};

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export const useCreateEditFormGroupsMembersAdmin = ({
description: convertText(values.name)
});

setOpen(false);
setOpen?.(false);
};

return { form, formSchema, onSubmit };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const useFormCreateEditFormGroupsMembersAdmin = () => {
return;
}

setOpen(false);
setOpen?.(false);
toast.success(t("administrators.add.success"), {
description:
values.type === "group"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const useFormCreateEditFormGroupsMembersAdmin = () => {
return;
}

setOpen(false);
setOpen?.(false);
toast.success(t("moderators.add.success"), {
description:
values.type === "group"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export const useCreateEditFormForumAdmin = ({
return;
}

setOpen(false);
setOpen?.(false);
};

return { form, onSubmit };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const ContentDeleteActionForumAdmin = ({
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
<AlertDialogHeader>
<AlertDialogTitle>{tCore("are_your_sure")}</AlertDialogTitle>
<AlertDialogTitle>{tCore("are_you_sure")}</AlertDialogTitle>
<AlertDialogDescription>
{t.rich("desc", {
name: () => (
Expand Down
84 changes: 60 additions & 24 deletions frontend/components/ui/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,32 @@

import * as DialogPrimitive from "@radix-ui/react-dialog";
import { X } from "lucide-react";
import { useTranslations } from "next-intl";
import {
createContext,
forwardRef,
useContext,
useState,
type ComponentPropsWithoutRef,
type ElementRef,
type HTMLAttributes
type HTMLAttributes,
type MouseEvent
} from "react";

import { cn } from "@/functions/classnames";

interface DialogContextArgs {
open: boolean;
setOpen: (value: boolean) => void;
isDirty?: boolean;
open?: boolean;
setIsDirty?: (value: boolean) => void;
setOpen?: (value: boolean) => void;
}

export const DialogContext = createContext<DialogContextArgs>({
open: false,
setOpen: () => {}
setOpen: () => {},
isDirty: false,
setIsDirty: () => {}
});

export const useDialog = () => useContext(DialogContext);
Expand All @@ -33,10 +39,16 @@ const Dialog = ({
...props
}: DialogPrimitive.DialogProps) => {
const [open, setOpen] = useState(false);
const [isDirty, setIsDirty] = useState(false);

return (
<DialogContext.Provider
value={{ open: openProp ?? open, setOpen: onOpenChange ?? setOpen }}
value={{
open: openProp ?? open,
setOpen: onOpenChange ?? setOpen,
isDirty,
setIsDirty
}}
>
<DialogPrimitive.Root
open={openProp ?? open}
Expand Down Expand Up @@ -71,25 +83,49 @@ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
const DialogContent = forwardRef<
ElementRef<typeof DialogPrimitive.Content>,
ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ children, className, ...props }, ref) => (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-card p-5 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full overflow-y-auto max-h-screen",
className
)}
{...props}
>
{children}
<DialogPrimitive.Close className="absolute w-9 h-9 flex items-center justify-center right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<X className="h-6 w-6" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPortal>
));
>(({ children, className, ...props }, ref) => {
const t = useTranslations("core");
const { isDirty, setOpen } = useDialog();

const handleBeforeUnload = (
e:
| CustomEvent<{
originalEvent: PointerEvent;
}>
| MouseEvent<HTMLButtonElement>
) => {
if (!isDirty) return;
e.preventDefault();

if (confirm(t("are_you_sure_want_to_leave_form"))) {
setOpen?.(false);
}
};

return (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
ref={ref}
onPointerDownOutside={handleBeforeUnload}
className={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-card p-5 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full overflow-y-auto max-h-screen",
className
)}
{...props}
>
{children}
<DialogPrimitive.Close
onClick={handleBeforeUnload}
className="absolute w-9 h-9 flex items-center justify-center right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"
>
<X className="h-6 w-6" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPortal>
);
});
DialogContent.displayName = DialogPrimitive.Content.displayName;

const DialogHeader = ({
Expand Down
14 changes: 12 additions & 2 deletions frontend/components/ui/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,28 @@ import {
useId,
type ComponentPropsWithoutRef,
type ElementRef,
type HTMLAttributes
type HTMLAttributes,
useEffect
} from "react";
import { useTranslations } from "next-intl";

import { Label } from "@/components/ui/label";
import { cn } from "@/functions/classnames";
import { useDialog } from "./dialog";

function Form<
TFieldValues extends FieldValues,
TContext = unknown,
TTransformedValues extends FieldValues = TFieldValues
>(props: FormProviderProps<TFieldValues, TContext, TTransformedValues>) {
useBeforeUnload(props.formState.isDirty);
const t = useTranslations("core");
const formIsDirty = props.formState.isDirty;
useBeforeUnload(formIsDirty, t("are_you_sure_want_to_leave_form"));
const { setIsDirty } = useDialog();

useEffect(() => {
setIsDirty?.(formIsDirty);
}, [formIsDirty]);

return <FormProvider {...props} />;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const useCopperModalChangeAvatar = () => {
toast.success(t("settings.change_avatar.options.upload.title"), {
description: t("settings.change_avatar.options.upload.success")
});
setOpen(false);
setOpen?.(false);
}

setPending(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const useModalChangeAvatar = () => {
toast.success(t("settings.change_avatar.options.delete.title"), {
description: t("settings.change_avatar.options.delete.success")
});
setOpen(false);
setOpen?.(false);
}

setPending(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export const useCreateTopic = ({ forumId }: Props) => {
push(`/topic/${convertNameToLink({ id, name: title })}`);
}

setOpen(false);
setOpen?.(false);
};

return { form, onSubmit };
Expand Down
3 changes: 2 additions & 1 deletion frontend/langs/en/core.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@
"upload_new_version": "Upload New Version",
"more_actions": "More Actions",
"download": "Download",
"are_your_sure": "Are you sure?",
"are_you_sure": "Are you sure?",
"are_you_absolutely_sure": "Are you absolutely sure?",
"are_you_sure_want_to_leave_form": "Are you sure you want to leave the form? Your changes may not be saved.",
"hands_up": "Hands up!",
"cancel": "Cancel",
"confirm": "Confirm",
Expand Down
3 changes: 2 additions & 1 deletion frontend/langs/pl/core.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"upload_new_version": "Prześlij nową wersję",
"more_actions": "Więcej akcji",
"download": "Pobierz",
"are_your_sure": "Czy jesteś pewien?",
"are_you_sure": "Czy jesteś pewien?",
"are_you_sure_want_to_leave_form": "Czy na pewno chcesz opuścić formularz? Twoje zmiany mogą nie zostać zapisane.",
"are_you_absolutely_sure": "Czy jesteś absolutnie pewien?",
"hands_up": "Uwaga!",
"cancel": "Anuluj",
Expand Down

0 comments on commit ce799e2

Please sign in to comment.