feat: useAlertStore 적용

This commit is contained in:
2025-03-19 18:43:58 +09:00
parent 915543628d
commit e49e3d3b36
6 changed files with 50 additions and 105 deletions
+3 -23
View File
@@ -1,6 +1,5 @@
"use client";
import { useState } from "react";
import { useRouter } from "next/navigation";
import { useForm } from "react-hook-form";
import { useMutation } from "@tanstack/react-query";
@@ -9,25 +8,18 @@ import { SiteApi } from "../api/site-service";
import { siteFormSchema, type SiteFormData } from "../model/site-interface";
import { SitePageLayout } from "./layout";
import { SiteForm } from "./site-form";
import {
Button,
Dialog,
DialogClose,
DialogContent,
DialogFooter,
} from "@common/components/ui";
import { useAlertStore } from "@/shared/lib/use-alert-store";
function CreatePage() {
const router = useRouter();
const { setMessage: alert } = useAlertStore((state) => state);
const { mutateAsync: createSite } = useMutation({
mutationFn: (data: SiteFormData) => SiteApi.createSite(data),
onSuccess: () => {
setIsCreateSuccess(true);
alert("등록되었습니다.", router.back);
},
});
const [isCreateSuccess, setIsCreateSuccess] = useState(false);
const form = useForm<SiteFormData>({
resolver: zodResolver(siteFormSchema),
});
@@ -35,18 +27,6 @@ function CreatePage() {
return (
<SitePageLayout>
<SiteForm form={form} handleSave={createSite} />
<Dialog open={isCreateSuccess} onOpenChange={() => router.back()}>
<DialogContent aria-describedby={undefined}>
<div className="py-10">
<p className="text-center text-[1.4rem]">등록되었습니다.</p>
</div>
<DialogFooter className="!justify-center">
<DialogClose asChild>
<Button>확인</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
</SitePageLayout>
);
}
@@ -47,7 +47,7 @@ function IPManagementDialog({
...props
}: IPManagementDialogProps) {
const { confirm } = useConfirm();
const { setAlertMessage } = useAlertStore((state) => state);
const { setMessage: alert } = useAlertStore((state) => state);
useQuery({
queryKey: [ENDPOINT.CMS_SERVICE.IPS, props.open],
@@ -74,20 +74,15 @@ function IPManagementDialog({
name: "ips",
});
const [isOpen, setIsOpen] = useState<boolean>(false);
const [isOpen, setIsOpen] = useState(false);
const [selectedRows, setSelectedRows] = useState<number[]>([]);
const onSubmit = async (data: IPFormData) => {
setIsOpen(true);
if (await confirm("저장하시겠습니까?")) {
setIsOpen(false);
try {
await mutateAsync(data.ips);
setAlertMessage("저장되었습니다.");
} catch (error) {
console.error(error);
setAlertMessage("저장에 실패했습니다.");
}
await mutateAsync(data.ips);
alert("저장되었습니다.");
}
};
+5 -23
View File
@@ -1,11 +1,12 @@
"use client";
import { useEffect, useState } from "react";
import { useEffect } from "react";
import { useRouter } from "next/navigation";
import { useForm } from "react-hook-form";
import { useMutation, useQuery } from "@tanstack/react-query";
import { zodResolver } from "@hookform/resolvers/zod";
import { ENDPOINT } from "@/shared/config";
import { useAlertStore } from "@/shared/lib/use-alert-store";
import { SiteApi } from "../api/site-service";
import {
siteFormSchema,
@@ -14,18 +15,12 @@ import {
} from "../model/site-interface";
import { SitePageLayout } from "./layout";
import { SiteForm } from "./site-form";
import {
Button,
Dialog,
DialogClose,
DialogContent,
DialogFooter,
} from "@common/components/ui";
function ModifyPage({ siteId }: { siteId: string }) {
const isModifyMode = !!siteId;
const router = useRouter();
const { setMessage: alert } = useAlertStore((state) => state);
const { data: siteDetail } = useQuery({
queryKey: [ENDPOINT.CMS_SERVICE.SITES, siteId],
queryFn: () => SiteApi.siteDetail(siteId),
@@ -40,17 +35,16 @@ function ModifyPage({ siteId }: { siteId: string }) {
const { mutateAsync: modifySite } = useMutation({
mutationFn: (data: SiteFormData) => SiteApi.modifySite(siteId, data),
onSuccess: () => {
setMessage("수정되었습니다.");
alert("수정되었습니다.", router.back);
},
});
const { mutateAsync: deleteSite } = useMutation({
mutationFn: () => SiteApi.deleteSite(siteId),
onSuccess: () => {
setMessage("삭제되었습니다.");
alert("삭제되었습니다.", router.back);
},
});
const [message, setMessage] = useState("");
const form = useForm<SiteFormData>({
resolver: zodResolver(siteFormSchema),
@@ -76,18 +70,6 @@ function ModifyPage({ siteId }: { siteId: string }) {
handleSave={modifySite}
handleDelete={deleteSite}
/>
<Dialog open={!!message} onOpenChange={() => router.back()}>
<DialogContent aria-describedby={undefined}>
<div className="py-10">
<p className="text-center text-[1.4rem]">{message}</p>
</div>
<DialogFooter className="!justify-center">
<DialogClose asChild>
<Button>확인</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
</SitePageLayout>
);
}
+24 -43
View File
@@ -4,10 +4,6 @@ import { useConfirm } from "@frontend-opensource/use-react-hooks";
import { type UseFormReturn } from "react-hook-form";
import {
Button,
Dialog,
DialogClose,
DialogContent,
DialogFooter,
Input,
Label,
RadioGroup,
@@ -26,7 +22,8 @@ import {
Form,
FormMessage,
} from "@/shared/ui/form";
import { type ISiteDetail, type SiteFormData } from "../model/site-interface";
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
import { type SiteFormData } from "../model/site-interface";
import { IPManagementDialog } from "./ip-management-dialog";
import {
DomainManagementDialog,
@@ -36,22 +33,17 @@ import {
type SiteFormProps = {
form: UseFormReturn<SiteFormData>;
siteId?: string;
handleSave: (data: SiteFormData) => void;
handleDelete?: () => void;
handleSave: (data: SiteFormData) => Promise<void>;
handleDelete?: () => Promise<void>;
};
function SiteForm({ form, siteId, handleSave, handleDelete }: SiteFormProps) {
const router = useRouter();
const { message, confirm, onConfirm, onCancel } = useConfirm();
const [viewState, setViewState] = useState<Partial<ISiteDetail>>({});
const [representativeDomain, setRepresentativeDomain] = useState<string>("");
const isModifyMode = !!siteId;
const handleViewStateChange = (key: keyof ISiteDetail) => (value: string) => {
setViewState({ ...viewState, [key]: value });
};
const router = useRouter();
const { confirm } = useConfirm();
const [representativeDomain, setRepresentativeDomain] = useState("");
const [isConfirmOpen, setIsConfirmOpen] = useState(false);
const handleDomainSave = (rows: Domain[]) => {
setRepresentativeDomain(
@@ -59,12 +51,22 @@ function SiteForm({ form, siteId, handleSave, handleDelete }: SiteFormProps) {
);
};
const onSubmit = (data: SiteFormData) => {
handleSave(data);
const onSubmit = async (data: SiteFormData) => {
const confirmMessage = isModifyMode
? "수정하시겠습니까?"
: "저장하시겠습니까?";
setIsConfirmOpen(true);
if (await confirm(confirmMessage)) {
setIsConfirmOpen(false);
handleSave(data);
}
};
const onDelete = async () => {
if (await confirm("정말 삭제하시겠습니까?")) {
setIsConfirmOpen(true);
if (await confirm("삭제하시겠습니까?")) {
setIsConfirmOpen(false);
handleDelete?.();
}
};
@@ -120,10 +122,7 @@ function SiteForm({ form, siteId, handleSave, handleDelete }: SiteFormProps) {
<CodeSelect
{...field}
upCd="SITEKNDCD"
onValueChange={(value) => {
handleViewStateChange("siteKndCd")(value);
field.onChange(value);
}}
onValueChange={field.onChange}
/>
</FormControl>
<FormMessage />
@@ -132,7 +131,7 @@ function SiteForm({ form, siteId, handleSave, handleDelete }: SiteFormProps) {
/>
{isModifyMode && (
<IPManagementDialog
triggerDisabled={viewState.siteKndCd === "O"}
triggerDisabled={form.watch("siteKndCd") === "O"}
/>
)}
</div>
@@ -405,25 +404,7 @@ function SiteForm({ form, siteId, handleSave, handleDelete }: SiteFormProps) {
</div>
</form>
</Form>
<Dialog open={!!message} onOpenChange={onCancel}>
<DialogContent aria-describedby={undefined}>
<div className="py-10">
<p className="text-center text-[1.4rem]">{message}</p>
</div>
<DialogFooter className="!justify-center">
<DialogClose asChild>
<Button color="red" onClick={onConfirm}>
삭제
</Button>
</DialogClose>
<DialogClose asChild>
<Button color="white" onClick={onCancel}>
취소
</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
<ConfirmDialog open={isConfirmOpen} />
</>
);
}
+7 -4
View File
@@ -1,22 +1,25 @@
import { createStore } from "zustand/vanilla";
export type AlertState = {
alertMessage: string;
message: string;
callback?: () => void;
};
export type AlertActions = {
setAlertMessage: (message: string) => void;
setMessage: (message: string, callback?: () => void) => void;
};
export type AlertStore = AlertState & AlertActions;
export const defaultInitState: AlertState = {
alertMessage: "",
message: "",
callback: undefined,
};
export const createAlertStore = (initState: AlertState = defaultInitState) => {
return createStore<AlertStore>()((set) => ({
...initState,
setAlertMessage: (alertMessage: string) => set(() => ({ alertMessage })),
setMessage: (message: string, callback?: () => void) =>
set(() => ({ message, callback })),
}));
};
+7 -3
View File
@@ -8,12 +8,16 @@ import {
import { useAlertStore } from "../lib/use-alert-store";
function AlertDialog() {
const { alertMessage, setAlertMessage } = useAlertStore((state) => state);
const { message, callback, setMessage } = useAlertStore((state) => state);
const handleOpenChange = () => {
setMessage("");
callback?.();
};
return (
<Dialog open={!!alertMessage} onOpenChange={() => setAlertMessage("")}>
<Dialog open={!!message} onOpenChange={handleOpenChange}>
<DialogContent aria-describedby={undefined}>
<div className="py-10">
<p className="text-center text-[1.4rem]">{alertMessage}</p>
<p className="text-center text-[1.4rem]">{message}</p>
</div>
<DialogFooter className="!justify-center">
<DialogClose asChild>