Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<body>
<div id="root"></div>
<div id="toast-root"></div>
<div id="modal-root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
1 change: 1 addition & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { RouterProvider } from "react-router-dom";

import { router } from "./Router";

import ToastContainer from "@/components/Toast/ToastContainer";

function App() {
Expand Down
51 changes: 51 additions & 0 deletions src/components/Modal/AlertModalLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import Button from "../Button";

import { Check, Notice } from "@/assets/icon";

interface ModalButton {
label: string;
style: "primary" | "white";
onClick: () => void;
}

interface Props {
iconType?: "check" | "warning" | "none";
message: string;
button: ModalButton;
onClose: () => void;
}

const ICONS = {
check: Check,
warning: Notice,
};

export default function AlertModalLayout({
iconType = "none",
message,
button,
onClose,
}: Props) {
const Icon = iconType !== "none" ? ICONS[iconType] : null;

return (
<div
className="bg-white p-7 rounded-lg text-center w-[18.625rem] h-[11.5rem] flex flex-col justify-between items-center"
onClick={(e) => e.stopPropagation()}
>
{Icon && <Icon className="w-6 h-6 mb-3" />}
<p className="text-base text-black font-normal mb-5">{message}</p>
<Button
variant={button.style}
onClick={() => {
button.onClick();
onClose();
}}
textSize="sm"
className="py-2 px-4 cursor-pointer"
>
{button.label}
</Button>
</div>
);
}
33 changes: 33 additions & 0 deletions src/components/Modal/ConfirmModalLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
interface ConfirmModalLayoutProps {
message: string;
onClose: () => void;
onConfirm: () => void;
}

export default function ConfirmModalLayout({
message,
onClose,
onConfirm,
}: ConfirmModalLayoutProps) {
return (
<div className="w-[18.625rem] md:w-[18.625rem] bg-white rounded-lg p-6 text-center">
<p className="text-gray-900 text-base md:text-lg font-normal mb-6">
{message}
</p>
<div className="flex justify-end gap-3">
<button
onClick={onClose}
className="w-[7.5rem] h-[3rem] border border-red-500 text-red-500 rounded"
>
아니오
</button>
<button
onClick={onConfirm}
className="w-[7.5rem] h-[3rem] bg-red-500 text-white rounded"
>
</button>
</div>
</div>
);
}
55 changes: 55 additions & 0 deletions src/components/Modal/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import AlertModalLayout from "./AlertModalLayout";
import ConfirmModalLayout from "./ConfirmModalLayout";

import { useModalStore } from "@/store/useModalStore";

export default function Modal() {
const { isOpen, options, closeModal } = useModalStore();

if (!isOpen || !options) return null;

const handleClose = () => {
options.onClose?.();
closeModal();
};

return (
<div className="fixed inset-0 z-[9999] flex items-center justify-center bg-black/50">
{options.type === "alert" && (
<AlertModalLayout
message={options.message}
onClose={handleClose}
iconType={options.iconType ?? "none"}
button={{
label: "확인",
style: "primary",
onClick: handleClose,
}}
/>
)}

{options.type === "confirm" && (
<ConfirmModalLayout
message={options.message}
onClose={handleClose}
onConfirm={() => {
options.onConfirm?.();
closeModal();
}}
/>
)}

{options.type === "message" && (
<AlertModalLayout
message={options.message}
onClose={handleClose}
button={{
label: "확인",
style: "primary",
onClick: handleClose,
}}
/>
)}
</div>
);
}
Empty file removed src/components/index.ts
Empty file.
32 changes: 32 additions & 0 deletions src/store/useModalStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { create } from "zustand";

export type ModalType = "alert" | "confirm" | "message";

export interface ModalButton {
label: string;
style: "primary" | "white";
onClick: () => void;
}

export interface ModalOptions {
type: "alert" | "confirm" | "message";
message: string;
iconType?: "check" | "warning" | "none";
buttons?: ModalButton[];
onClose?: () => void;
onConfirm?: () => void;
}

interface ModalState {
isOpen: boolean;
options: ModalOptions | null;
openModal: (options: ModalOptions) => void;
closeModal: () => void;
}

export const useModalStore = create<ModalState>((set) => ({
isOpen: false,
options: null,
openModal: (options) => set({ isOpen: true, options }),
closeModal: () => set({ isOpen: false, options: null }),
}));
10 changes: 10 additions & 0 deletions src/types/svg.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
declare module "*.svg?react" {
import * as React from "react";
const ReactComponent: React.FC<React.SVGProps<SVGSVGElement>>;
export default ReactComponent;
}

declare module "*.svg" {
const content: string;
export default content;
}
6 changes: 5 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,9 @@
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
],
"compilerOptions": {
"typeRoots": ["./src/types", "./node_modules/@types"]
},
"includes": ["src", "src/types"]
}