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

[ Fix ] 모달 내 버그 해결 및 리팩토링 #195

Merged
merged 5 commits into from
Sep 23, 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
35 changes: 17 additions & 18 deletions src/pages/HomePage/components/ModalAddCategory.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@

import { useState, useRef } from 'react';

import React, { useRef, useState } from 'react';

import { useQueryClient } from '@tanstack/react-query';

Expand Down Expand Up @@ -35,6 +33,7 @@ interface ModalAddCategoryProps {
const ModalAddCategory = ({ handleCloseModal }: ModalAddCategoryProps) => {
const [totalUrlInfos, setTotalUrlInfos] = useState<UrlInfo[]>([]);
const [rightModalUrlInfos, setRightModalUrlInfos] = useState<UrlInfo[]>([]);

const [name, setName] = useState('');
const queryClient = useQueryClient();
const {
Expand All @@ -54,7 +53,7 @@ const ModalAddCategory = ({ handleCloseModal }: ModalAddCategoryProps) => {
} = useCalendar();
const dialogRef = useRef<HTMLDialogElement>(null);

const handleUrlInfos = () => {
const handleClearUrlInfos = () => {
setRightModalUrlInfos([]);
};

Expand Down Expand Up @@ -87,8 +86,6 @@ const ModalAddCategory = ({ handleCloseModal }: ModalAddCategoryProps) => {
handlePeriodEnd();
};



const handleDeleteUrlInfo = (urlInfoToDelete: UrlInfo) => {
setRightModalUrlInfos((prevUrlInfos) => prevUrlInfos.filter((urlInfo) => urlInfo.url !== urlInfoToDelete.url));
};
Expand Down Expand Up @@ -149,9 +146,8 @@ const ModalAddCategory = ({ handleCloseModal }: ModalAddCategoryProps) => {
setName(event.target.value);
};


const showModal = () => {
handleUrlInfos();
handleClearUrlInfos();
dialogRef.current?.showModal();
};

Expand All @@ -165,7 +161,7 @@ const ModalAddCategory = ({ handleCloseModal }: ModalAddCategoryProps) => {

const handleClose = () => {
handleClearData();
handleCloseModal();
closeModal();
};

const handleCategoryModalClose = () => {
Expand All @@ -189,11 +185,10 @@ const ModalAddCategory = ({ handleCloseModal }: ModalAddCategoryProps) => {
};

return (

<>
<header>
<div>
<h1 className="head-bold-24 text-gray-04">카테고리 추가</h1>
</header>
</div>
<section className="flex-start my-[2rem] mt-[1.6rem] inline-flex gap-[4.4rem]">
<section className="flex-col">
<h2 className="subhead-bold-22 pb-[1rem] pt-[1rem] text-white">이름 *</h2>
Expand Down Expand Up @@ -254,15 +249,19 @@ const ModalAddCategory = ({ handleCloseModal }: ModalAddCategoryProps) => {
</button>
<AddCategoryListModal
handleSubmitModal={handleMsetSubmit}
handleClose={handleCategoryModalClose}
handleClose={handleClose}
dialogRef={dialogRef}
rightModalUrlInfos={rightModalUrlInfos}
handleRightModalUrlInfos={handleRightModalUrlInfos}
handleDeleteUrlInfo={(url: UrlInfo) => handleDeleteUrlInfo(url)}
moribSetName={name}
/>
</div>
<InputCategoryUrl variant="basic" onUrlInputChange={(url: string) => handleUrlInputChange(url)} />
<InputCategoryUrl
currentUrlInfos={totalUrlInfos}
variant="basic"
onUrlInputChange={(url: string) => handleUrlInputChange(url)}
/>
</section>

<CategoryCommonMoribSet urlInfos={totalUrlInfos} variant="basic">
Expand All @@ -274,14 +273,14 @@ const ModalAddCategory = ({ handleCloseModal }: ModalAddCategoryProps) => {
</CategoryCommonMoribSet>
</main>

<footer className="mt-[3rem] flex justify-end gap-[1.6rem]">
<ButtonCategoryCommon variant="취소" handleCloseModal={handleClose}>
<div className="mt-[3rem] flex justify-end gap-[1.6rem]">
<ButtonCategoryCommon variant="취소" onClick={handleCategoryModalClose}>
취소
</ButtonCategoryCommon>
<ButtonCategoryCommon variant="완료" handleSubmit={handlePostDataClick} disabled={!isFormValid()}>
<ButtonCategoryCommon variant="완료" onClick={handlePostDataClick} disabled={!isFormValid()}>
완료
</ButtonCategoryCommon>
</footer>
</div>
</>
);
};
Expand Down
141 changes: 120 additions & 21 deletions src/shared/components/AddCategoryListModal.tsx
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p5: 컴포넌트 구성에 대해서 고민이 많으시군요. 필요에 따라서 컴포넌트를 유동적으로 분리하여 사용하면 좋을것 같아요. 재사용성만 생각했을 때 컴포넌트를 굳이 분리 안해도 될것 같지만 내가, 또는 협업자가 봤을 때 어느 역할을 하는지 명확히 하기위해 분리하는것도 정말 좋다고 생각해요.

예시로 한서님 코드를 변경해보자면,

<Container>
  <Header/>

  <ListUrl variant='left'>
      {data.map((item) => <ItemUrl {...item}/>
  <ListCategory/>
  
  <ListUrl variant='right'>
      {data.map((item) => <ItemUrl {...item}/>
  <ListCategory/>

<Container/>

이렇게 완벽하게 컴포넌트를 분리하기 쉽지 않지만, 위와 같이 분리한다면 협업자가 봐도 어떤 내용이 있는지 명확하게 파악이 가능할거에요. 이처럼 직관적으로 코드를 알아보기 쉽게 하는것도 좋은 근거라고 생각합니다.

제가 한 얘기들과 관련이 크게 없지만 토스 컴포넌트 관련 영상 링크 첨부해드릴게요.
https://www.youtube.com/watch?v=fR8tsJ2r7Eg&t=1s

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋은 의견 감사합니다! 역할을 명확히 하기 위한 용도만으로도 컴포넌트를 분리하는 방법도 가독성에 도움이 되겠네요. 저도 더 고민해보고 유동적으로 적용해보도록 하겠습니다!

Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
import { RefObject, useState } from 'react';

import CategoryModalLeft from '@/shared/components/CategoryModalLeft';
import CategoryModalRight from '@/shared/components/CategoryModalRight';
import ButtonCategoryCommon from '@/shared/components/ButtonCategoryCommon';
import CategoryMsetUrlInfo from '@/shared/components/CategoryMsetUrlInfo';
import CategoryTabSelect from '@/shared/components/CategoryTabSelect';
import DropdownCategory from '@/shared/components/DropdownCategory';
import TitleMoribSet from '@/shared/components/TitleMoribSet';

import { getTabName } from '@/shared/apis/modal/axios';
import { useCategoryLists, useGetMsets } from '@/shared/apis/modal/queries';

import { CATEGORY_MODALTABS } from '@/shared/constants/tabSelections';

import AddBtn from '@/shared/assets/svgs/add_btn.svg?react';
import MinusBtn from '@/shared/assets/svgs/minus_btn.svg?react';

import CategoryCommonMoribSet from './CategoryCommonMoribSet';
import InputCategoryUrl from './InputCategoryUrl';

interface UrlInfo {
url: string;
Expand All @@ -14,9 +26,9 @@ interface UrlInfo {
type CategoryListModalProp = {
dialogRef: RefObject<HTMLDialogElement>;
handleSubmitModal: () => void;

rightModalUrlInfos: UrlInfo[];
handleRightModalUrlInfos: (url: UrlInfo) => void;

handleDeleteUrlInfo: (url: UrlInfo) => void;
moribSetName: string;
handleClose: () => void;
Expand All @@ -26,15 +38,28 @@ const AddCategoryListModal = ({
dialogRef,
handleSubmitModal,
handleClose,

rightModalUrlInfos,

handleRightModalUrlInfos,
handleDeleteUrlInfo,
moribSetName,
}: CategoryListModalProp) => {
const [isClicked, setIsClicked] = useState(false);
const [selectedOption, setSelectedOption] = useState('카테고리 추가');
const [selectedTabId, setSelectedTabId] = useState(CATEGORY_MODALTABS[0].id);
const { data: categoryData } = useCategoryLists();
const categories = categoryData?.data || [];
const [categoryId, setCategoryId] = useState<number>(0);
const { data: msetsList } = useGetMsets(categoryId);
const msetUrlInfos = msetsList || [];
const handleOptionId = (id: number) => {
setCategoryId(id);
};

const handleTabChange = (tab: number) => {
setSelectedTabId(tab);
};

const disabled = selectedTabId === 2;

const handleUrlInputChange = async (url: string) => {
try {
Expand Down Expand Up @@ -65,22 +90,96 @@ const AddCategoryListModal = ({
return (
<dialog ref={dialogRef} className="rounded-[10px]">
<div className="flex">
<CategoryModalLeft
handleClickButton={handleClickButton}
handleSelectOption={handleSelectOption}
isClicked={isClicked}
selectedOption={selectedOption}
handleRightModalUrlInfos={handleRightModalUrlInfos}
/>
<CategoryModalRight
rightModalUrlInfos={rightModalUrlInfos}
handleUrlInputChange={(url: string) => handleUrlInputChange(url)}
handleDeleteUrlInfo={(url: UrlInfo) => handleDeleteUrlInfo(url)}
handleClose={handleClose}
handleSubmitModal={handleSubmitModal}
moribSetName={moribSetName}
handleClearModalData={handleClearModalData}
/>
<div className="h-[80rem] w-[68.8rem] rounded-l-[10px] bg-gray-bg-04 py-[2.8rem] pl-[4.4rem] pr-[4.3rem]">
<div className="mb-[3.3rem]">
<h1 className="head-bold-24 text-gray-04">카테고리 추가</h1>
</div>
<aside className="mb-[8px]">
<div className="my-[8px]">
<CategoryTabSelect
tabs={CATEGORY_MODALTABS}
handleTabChange={handleTabChange}
selectedTabId={selectedTabId}
/>
</div>

<div className="relative mt-[0px]">
<DropdownCategory
optionData={categories}
disabled={disabled}
handleOptionId={handleOptionId}
handleClickButton={handleClickButton}
handleSelectOption={handleSelectOption}
isClicked={isClicked}
selectedOption={selectedOption}
/>
</div>
</aside>

<CategoryCommonMoribSet variant="smallLeft" urlInfos={msetUrlInfos}>
{selectedTabId !== 2 &&
msetUrlInfos.map((urlInfo: UrlInfo) => (
<div
key={urlInfo.url}
className="group flex h-[4.6rem] w-[100%] gap-[1.2rem] border-b border-gray-bg-04 px-[0.8rem] hover:bg-gray-bg-04"
onClick={() => handleRightModalUrlInfos(urlInfo)}
>
<CategoryMsetUrlInfo urlInfo={urlInfo} variant="smallLeft">
<div className="p-[1.25rem]">
<button type="button">
<AddBtn className="fill-gray-bg-07 group-hover:fill-mint-02-hover group-active:fill-mint-02-press" />
</button>
</div>
</CategoryMsetUrlInfo>
</div>
))}
</CategoryCommonMoribSet>
</div>
<div className="flex h-[80rem] w-[61.2rem] flex-col items-end justify-between rounded-r-[1rem] bg-gray-bg-03 pb-[3rem] pl-[3rem] pr-[4.3rem] pt-[9.7rem]">
<TitleMoribSet moribSetName={moribSetName} />

<InputCategoryUrl
currentUrlInfos={rightModalUrlInfos}
variant="small"
onUrlInputChange={(url: string) => handleUrlInputChange(url)}
/>
<CategoryCommonMoribSet urlInfos={rightModalUrlInfos} variant="smallRight">
{rightModalUrlInfos.map((urlInfo, url) => (
<div key={url} className="flex h-[4.6rem] gap-[2rem] border-b border-gray-bg-04 px-[0.8rem]">
<CategoryMsetUrlInfo urlInfo={urlInfo} variant="smallRight">
<div className="p-[1.25rem]">
<button type="button" onClick={() => handleDeleteUrlInfo(urlInfo)}>
<MinusBtn className="fill-gray-bg-07 hover:fill-error-01 active:fill-error-03" />
</button>
</div>
</CategoryMsetUrlInfo>
</div>
))}
</CategoryCommonMoribSet>

<div className="mt-[3rem] flex gap-[16px]">
<ButtonCategoryCommon
variant="취소"
onClick={() => {
handleClearModalData();
handleClose();
setCategoryId(0);
}}
>
취소
</ButtonCategoryCommon>
<ButtonCategoryCommon
variant="완료"
onClick={() => {
handleClearModalData();
handleSubmitModal();
setCategoryId(0);
}}
>
완료
</ButtonCategoryCommon>
</div>
</div>
</div>
</dialog>
);
Expand Down
32 changes: 3 additions & 29 deletions src/shared/components/ButtonCategoryCommon.tsx
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코드도 훨씬 깔끔해지고 공통컴포넌트로서의 역할이 더욱 명확해졌네요👍

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

공통 컴포넌트로서 활용성이 더 좋아진 것 같네요! 너무 좋습니다!

Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,9 @@ import { ButtonHTMLAttributes, ReactNode } from 'react';
interface CategoryBtnProps extends ButtonHTMLAttributes<HTMLButtonElement> {
variant?: '취소' | '완료';
children: ReactNode;
handleCloseModal?: () => void;
handleSubmit?: () => void;
handleClearModalData?: () => void;
}

const ButtonCategoryCommon = ({
disabled,
variant,
children,
handleCloseModal,
handleSubmit,
handleClearModalData,
...props
}: CategoryBtnProps) => {
const ButtonCategoryCommon = ({ variant, children, ...props }: CategoryBtnProps) => {
const btnVariant = {
취소: 'text-white bg-gray-bg-06 hover:bg-gray-bg-04 active:bg-gray-bg-05',
완료: 'text-gray-bg-01 bg-mint-02 hover:bg-mint-02-hover active:bg-mint-02-press',
Expand All @@ -25,25 +14,10 @@ const ButtonCategoryCommon = ({

const commonStyle = ' px-[4.8rem] py-[1rem] rounded-[5px] subhead-semibold-18';

const styledBtn = disabled ? disabledBtn : variant ? btnVariant[variant] : '';
const styledBtn = props.disabled ? disabledBtn : variant ? btnVariant[variant] : '';

const handleClick = () => {
if (handleSubmit) {
handleSubmit();
} else if (handleCloseModal) {
handleCloseModal();
}
};
return (
<button
className={`${styledBtn} ${commonStyle}`}
disabled={disabled}
{...props}
onClick={() => {
handleClick();
handleClearModalData?.();
}}
>
<button className={`${styledBtn} ${commonStyle}`} {...props}>
{children}
</button>
);
Expand Down
Loading