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

refactor(CLAP-184): ModalContainer 리팩토링 #132

Merged
merged 3 commits into from
Aug 26, 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
14 changes: 9 additions & 5 deletions packages/core/src/contexts/ModalContext.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { createContext, Dispatch, SetStateAction } from "react";

export interface ModalState {
type: any;
props?: any;
export interface ModalState<T, P> {
type: T;
props?: P;
}

export const ModalStateContext = createContext<ModalState | null>(null);
export const ModalStateContext = createContext<ModalState<
unknown,
unknown
> | null>(null);

export const ModalSetterContext = createContext<Dispatch<
SetStateAction<ModalState>
SetStateAction<ModalState<unknown, unknown>>
> | null>(null);
8 changes: 4 additions & 4 deletions packages/core/src/hooks/useModal.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { useContext } from "react";
import { ModalSetterContext, ModalState } from "../contexts/ModalContext";

export const useModal = () => {
export const useModal = <T = unknown, P = unknown>() => {
const setModalState = useContext(ModalSetterContext);

if (!setModalState) {
throw new Error("useModal must be used within a ModalProvider");
}

const openModal = ({ type, props = null }: ModalState) => {
setModalState({ type, props });
const openModal = (modalState: ModalState<T, P>) => {
setModalState(modalState);
};

const closeModal = () => {
setModalState({ type: null, props: null });
setModalState({ type: null, props: null } as ModalState<T, P>);
};

return { openModal, closeModal };
Expand Down
5 changes: 4 additions & 1 deletion packages/core/src/providers/ModalProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ interface ModalProviderProps {
}

export const ModalProvider = ({ children }: ModalProviderProps) => {
const [state, setState] = useState<ModalState>({ type: null, props: null });
const [state, setState] = useState<ModalState<unknown, unknown>>({
type: null,
props: null,
});

return (
<ModalSetterContext.Provider value={setState}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
DescriptionModalProps,
} from "./modal";

// ModalType 정의
export type ModalType =
| "login"
| "alert"
Expand All @@ -23,11 +24,13 @@ export type ModalType =
| "confirm"
| "description";

// DefaultModalProps 정의
export interface DefaultModalProps {
isOpen: boolean;
onRequestClose: () => void;
}

// ModalComponentMap 인터페이스 정의
interface ModalComponentMap {
login: React.FC<DefaultModalProps>;
alert: React.FC<AlertModalProps>;
Expand All @@ -37,6 +40,7 @@ interface ModalComponentMap {
description: React.FC<DescriptionModalProps>;
}

// MODAL_COMPONENT_MAP 구현
const MODAL_COMPONENT_MAP: ModalComponentMap = {
login: GoogleLoginModal,
alert: AlertModal,
Expand All @@ -46,27 +50,51 @@ const MODAL_COMPONENT_MAP: ModalComponentMap = {
description: DescriptionModal,
};

// ModalStateMap 정의
export interface ModalStateMap {
login: DefaultModalProps;
alert: AlertModalProps;
pending: DefaultModalProps;
navigate: NavigateModalProps;
confirm: ConfirmModalProps;
description: DescriptionModalProps;
}

// ModalState 제네릭 타입 정의
export interface ModalState<T extends ModalType> {
type: T;
props?: ModalStateMap[T];
}

// ModalContainer 컴포넌트 정의
export const ModalContainer = () => {
const { closeModal } = useModal();
const modalState = useContext(ModalStateContext);
const modalState = useContext(
ModalStateContext,
) as ModalState<ModalType> | null;

if (!modalState || !modalState.type) {
return null;
}

// modalState의 type과 props를 구체적으로 타입 캐스팅
const { type, props } = modalState;

const ModalComponent = MODAL_COMPONENT_MAP[type as ModalType];
// ModalComponent를 동적으로 선택
const ModalComponent = MODAL_COMPONENT_MAP[type] as React.FC<
ModalStateMap[typeof type]
>;

if (!ModalComponent) {
return null;
}

// modalProps 정의
const modalProps = {
...props,
isOpen: !!modalState.type, // boolean 보장을 위해 !! 사용
isOpen: Boolean(modalState.type),
onRequestClose: closeModal,
};
} as ModalStateMap[typeof type]; // modalProps 타입 지정

return createPortal(
<ModalComponent {...modalProps} />,
Expand Down
Loading