Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(frontend): Add before unload to form when isDirty is true #251

Merged
merged 2 commits into from
Mar 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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-[calc(100vh_-_2rem)]",
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
28 changes: 24 additions & 4 deletions frontend/components/ui/form.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import * as LabelPrimitive from "@radix-ui/react-label";
import { Slot } from "@radix-ui/react-slot";
import { useBeforeUnload } from "react-use";
import {
Controller,
FormProvider,
useFormContext,
type ControllerProps,
type FieldPath,
type FieldValues
type FieldValues,
type FormProviderProps
} from "react-hook-form";
import {
createContext,
Expand All @@ -15,13 +17,31 @@ 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";

const Form = FormProvider;
import { useDialog } from "./dialog";

function Form<
TFieldValues extends FieldValues,
TContext = unknown,
TTransformedValues extends FieldValues = TFieldValues
>(props: FormProviderProps<TFieldValues, TContext, TTransformedValues>) {
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} />;
}

type FormFieldContextValue<
TFieldValues extends FieldValues = FieldValues,
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
Loading