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 ] 모달 내 버그 해결 및 리팩토링 #200

Merged
merged 7 commits into from
Oct 8, 2024
62 changes: 47 additions & 15 deletions src/pages/HomePage/components/ModalAddCategory.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { useRef, useState } from 'react';


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

import AddCategoryListModal from '@/shared/components/AddCategoryListModal';
Expand Down Expand Up @@ -35,6 +34,9 @@ interface ModalAddCategoryProps {
const ModalAddCategory = ({ handleCloseModal }: ModalAddCategoryProps) => {
const [totalUrlInfos, setTotalUrlInfos] = useState<UrlInfo[]>([]);
const [rightModalUrlInfos, setRightModalUrlInfos] = useState<UrlInfo[]>([]);
const [isFirstUrlValidated, setIsFirstUrlValidated] = useState<boolean | null>(null);
const [isSecondUrlValidated, setIsSecondUrlValidated] = useState<boolean | null>(null);
const [inputUrl, setInputUrl] = useState('');

const [name, setName] = useState('');
const queryClient = useQueryClient();
Expand All @@ -58,9 +60,22 @@ const ModalAddCategory = ({ handleCloseModal }: ModalAddCategoryProps) => {
const handleClearUrlInfos = () => {
setRightModalUrlInfos([]);
};
const handleUrlValidation = (state: boolean | null) => {
setIsFirstUrlValidated(state);
setIsSecondUrlValidated(state);
};
const handleInputUrl = (url: string) => {
setInputUrl(url);
};

const handleAddTotalUrl = () => {
setTotalUrlInfos((prev) => [...prev, ...rightModalUrlInfos]);
setTotalUrlInfos((prev) => {
const existingUrls = new Set(prev.map((totalUrlInfo) => totalUrlInfo.url));
seueooo marked this conversation as resolved.
Show resolved Hide resolved

const newUrls = rightModalUrlInfos.filter((rightUrlInfo) => existingUrls.has(rightUrlInfo.url) === false);

return [...prev, ...newUrls];
});
};

const handleRightModalUrlInfos = (urlInfo: UrlInfo) => {
Expand All @@ -81,6 +96,8 @@ const ModalAddCategory = ({ handleCloseModal }: ModalAddCategoryProps) => {
const { error: queryError } = useGetTabName('');

const handleClearData = () => {
handleInputUrl('');
handleUrlValidation(null);
setName('');
setRightModalUrlInfos([]);
setTotalUrlInfos([]);
Expand Down Expand Up @@ -161,18 +178,13 @@ const ModalAddCategory = ({ handleCloseModal }: ModalAddCategoryProps) => {
showModal();
};

const handleClose = () => {
handleClearData();
const handleSecondModalClose = () => {
dialogRef.current?.close();

};

const handleCategoryModalClose = () => {
handleClearData();
handleCloseModal();
};

const handlePostDataClick = () => {
handleUrlValidation(null);
handleInputUrl('');
handleClearData();
handleCategoryData();
handleCloseModal();
Expand All @@ -182,7 +194,7 @@ const ModalAddCategory = ({ handleCloseModal }: ModalAddCategoryProps) => {
}
};

const handleMsetSubmit = () => {
const handleSecondModalSubmit = () => {
handleAddTotalUrl();
closeModal();
};
Expand Down Expand Up @@ -252,8 +264,12 @@ const ModalAddCategory = ({ handleCloseModal }: ModalAddCategoryProps) => {
</button>
<ModalWrapper ref={dialogRef} backdrop={false}>
<AddCategoryListModal
handleSubmitModal={handleMsetSubmit}
handleClose={handleClose}
inputUrl={inputUrl}
handleInputUrl={handleInputUrl}
isUrlValidated={isSecondUrlValidated}
handleUrlValidation={handleUrlValidation}
handleSubmitModal={handleSecondModalSubmit}
handleSecondModalClose={handleSecondModalClose}
rightModalUrlInfos={rightModalUrlInfos}
handleRightModalUrlInfos={handleRightModalUrlInfos}
handleDeleteUrlInfo={(url: UrlInfo) => handleDeleteUrlInfo(url)}
Expand All @@ -262,6 +278,10 @@ const ModalAddCategory = ({ handleCloseModal }: ModalAddCategoryProps) => {
</ModalWrapper>
</div>
<InputCategoryUrl
inputUrl={inputUrl}
handleInputUrl={handleInputUrl}
isUrlValidated={isFirstUrlValidated}
handleUrlValidation={handleUrlValidation}
currentUrlInfos={totalUrlInfos}
variant="basic"
onUrlInputChange={(url: string) => handleUrlInputChange(url)}
Expand All @@ -278,10 +298,22 @@ const ModalAddCategory = ({ handleCloseModal }: ModalAddCategoryProps) => {
</main>

<div className="mt-[3rem] flex justify-end gap-[1.6rem]">
<ButtonCategoryCommon variant="취소" onClick={handleCategoryModalClose}>
<ButtonCategoryCommon
variant="취소"
onClick={() => {
handleClearData();
handleCloseModal();
}}
>
취소
</ButtonCategoryCommon>
<ButtonCategoryCommon variant="완료" onClick={handlePostDataClick} disabled={!isFormValid()}>
<ButtonCategoryCommon
variant="완료"
onClick={() => {
handlePostDataClick();
}}
disabled={!isFormValid()}
>
완료
</ButtonCategoryCommon>
</div>
Expand Down
24 changes: 18 additions & 6 deletions src/shared/components/AddCategoryListModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,26 @@ type CategoryListModalProp = {
handleSubmitModal: () => void;
rightModalUrlInfos: UrlInfo[];
handleRightModalUrlInfos: (url: UrlInfo) => void;

isUrlValidated: boolean | null;
handleUrlValidation: (state: boolean | null) => void;
handleDeleteUrlInfo: (url: UrlInfo) => void;
moribSetName: string;
handleClose: () => void;
handleSecondModalClose: () => void;
inputUrl: string;
handleInputUrl: (url: string) => void;
};

const AddCategoryListModal = ({
handleSubmitModal,
handleClose,
handleSecondModalClose,
rightModalUrlInfos,
handleRightModalUrlInfos,
handleDeleteUrlInfo,
moribSetName,
isUrlValidated,
handleUrlValidation,
inputUrl,
handleInputUrl,
}: CategoryListModalProp) => {
const [isClicked, setIsClicked] = useState(false);
const [selectedOption, setSelectedOption] = useState('카테고리 추가');
Expand Down Expand Up @@ -82,6 +89,9 @@ const AddCategoryListModal = ({
};

const handleClearModalData = () => {
setCategoryId(0);
handleUrlValidation(null);
handleInputUrl('');
setIsClicked(false);
setSelectedOption('카테고리 추가');
};
Expand Down Expand Up @@ -137,6 +147,10 @@ const AddCategoryListModal = ({
<TitleMoribSet moribSetName={moribSetName} />

<InputCategoryUrl
inputUrl={inputUrl}
handleInputUrl={handleInputUrl}
isUrlValidated={isUrlValidated}
handleUrlValidation={handleUrlValidation}
currentUrlInfos={rightModalUrlInfos}
variant="small"
onUrlInputChange={(url: string) => handleUrlInputChange(url)}
Expand All @@ -160,8 +174,7 @@ const AddCategoryListModal = ({
variant="취소"
onClick={() => {
handleClearModalData();
handleClose();
setCategoryId(0);
handleSecondModalClose();
}}
>
취소
Expand All @@ -171,7 +184,6 @@ const AddCategoryListModal = ({
onClick={() => {
handleClearModalData();
handleSubmitModal();
setCategoryId(0);
}}
>
완료
Expand Down
11 changes: 9 additions & 2 deletions src/shared/components/DropdownCategory.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { ButtonHTMLAttributes } from 'react';
import { ButtonHTMLAttributes, useRef } from 'react';

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

import ButtonCategoryDropdown from '@/shared/components/ButtonCategoryDropdown';
import ButtonDropdownOptions from '@/shared/components/ButtonDropdownOptions';

import useClickOutside from '@/shared/hooks/useClickOutside';

interface DropdownBtnProps extends ButtonHTMLAttributes<HTMLButtonElement> {
optionData: Category[];
handleOptionId: (id: number) => void;
Expand Down Expand Up @@ -42,6 +44,8 @@ const DropdownCategory = ({

handleClickButton(!prev);
};
const dropdownRef = useRef<HTMLUListElement>(null);
useClickOutside(dropdownRef, () => handleClickButton(false), isClicked);

return (
<>
Expand All @@ -52,7 +56,10 @@ const DropdownCategory = ({
selectedOption={selectedOption}
/>
{isClicked && (
<ul className="absolute top-[5.6rem] max-h-[41.4rem] w-[27.2rem] flex-col overflow-scroll rounded-[5px] shadow-[0_3px_30px_0_rgba(0,0,0,0.40)]">
<ul
ref={dropdownRef}
className="absolute top-[5.6rem] max-h-[41.4rem] w-[27.2rem] flex-col overflow-scroll rounded-[5px] shadow-[0_3px_30px_0_rgba(0,0,0,0.40)]"
>
{optionData?.map((item) => {
return (
<li
Expand Down
47 changes: 23 additions & 24 deletions src/shared/components/InputCategoryUrl.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import React, { useState } from 'react';

import { isUrlValid } from '@/shared/utils/isUrlValid/index';

Expand All @@ -14,11 +14,21 @@ interface InputCategoryUrlProps {
variant?: 'basic' | 'small';
onUrlInputChange: (url: string) => void;
currentUrlInfos?: UrlInfo[];
isUrlValidated: boolean | null;
handleUrlValidation: (state: boolean | null) => void;
inputUrl: string;
handleInputUrl: (url: string) => void;
}

const InputCategoryUrl = ({ variant = 'basic', onUrlInputChange, currentUrlInfos }: InputCategoryUrlProps) => {
const [url, setUrl] = useState('');
const [isUrlValidated, setIsUrlValidated] = useState<boolean | null>(null);
const InputCategoryUrl = ({
variant = 'basic',
onUrlInputChange,
currentUrlInfos,
isUrlValidated,
handleUrlValidation,
inputUrl,
handleInputUrl,
}: InputCategoryUrlProps) => {
const [errorMessage, setErrorMessage] = useState<string>('');

const sizeVariantWidth = {
Expand All @@ -29,29 +39,18 @@ const InputCategoryUrl = ({ variant = 'basic', onUrlInputChange, currentUrlInfos
const defaultStyle = `subhead-med-18 h-[4.6rem] rounded-[8px] border-[1px] bg-gray-bg-02 px-[2rem] py-[1rem] text-white placeholder-gray-03 focus:outline-none ${sizeVariantWidth[variant]}`;
const borderStyle = isUrlValidated === false ? 'border-error-02' : 'border-transparent';

useEffect(() => {
if (isUrlValidated === false) {
const timer = setTimeout(() => {
setUrl('');
setIsUrlValidated(true);
}, 3000);

return () => clearTimeout(timer);
}
}, [isUrlValidated]);

const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
const isValid = isUrlValid(url);
setIsUrlValidated(isValid);
const isValid = isUrlValid(inputUrl);
handleUrlValidation(isValid);
if (isValid) {
const isExist = currentUrlInfos?.some((info) => info.url === url);
const isExist = currentUrlInfos?.some((info) => info.url === inputUrl);
if (isExist) {
setErrorMessage('이미 추가된 주소입니다.');
setIsUrlValidated(false);
handleUrlValidation(false);
} else {
onUrlInputChange(url);
setUrl('');
onUrlInputChange(inputUrl);
handleInputUrl('');
setErrorMessage('알맞은 도메인을 입력해주세요.');
}
} else {
Expand All @@ -62,8 +61,8 @@ const InputCategoryUrl = ({ variant = 'basic', onUrlInputChange, currentUrlInfos

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const userInput = e.target.value;
setUrl(userInput);
setIsUrlValidated(null);
handleInputUrl(userInput);
handleUrlValidation(null);
setErrorMessage('');
};

Expand All @@ -74,7 +73,7 @@ const InputCategoryUrl = ({ variant = 'basic', onUrlInputChange, currentUrlInfos
placeholder="허용할 웹사이트 주소를 입력해 주세요."
className={`${defaultStyle} ${borderStyle}`}
onChange={handleChange}
value={url}
value={inputUrl}
onKeyDown={handleKeyDown}
/>
<div className={`flex h-[3.2rem] ${isUrlValidated === false ? 'visible' : 'invisible'}`}>
Expand Down
2 changes: 1 addition & 1 deletion src/shared/components/TitleMoribSet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const TitleMoribSet = ({ moribSetName }: TitleMoribSetProp) => {
moribSetName
) : (
<>
<h2 className="pr-[1rem]" /> _______ <span className="pr-[0.5rem]" />
<span className="pr-[1rem]" /> _______ <span className="pr-[0.5rem]" />
</>
)}
</h2>
Expand Down