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