diff --git a/src/components/NicknameModal.tsx b/src/components/NicknameModal.tsx index 7a45e92..adbc6f2 100644 --- a/src/components/NicknameModal.tsx +++ b/src/components/NicknameModal.tsx @@ -6,14 +6,16 @@ import nameImg from '@/assets/name.png'; import { BlurBackground } from '@/styles/modals/common.style'; import { userInfoState } from '@/stores/user'; import { useSetRecoilState } from 'recoil'; +import useCreateToast from '@/hooks/useCreateToast'; const NicknameModal = () => { - const [inputCount, setInputCount] = useState(0); - const [name, setName] = useState(""); - - const setUserInfo = useSetRecoilState(userInfoState); + const [inputCount, setInputCount] = useState(0); + const [name, setName] = useState(''); + const { createToast } = useCreateToast(); - const refreshMyInfo = async () => { + const setUserInfo = useSetRecoilState(userInfoState); + + const refreshMyInfo = async () => { try { const { result } = (await getMyInfoAPI()).data; @@ -21,100 +23,91 @@ const NicknameModal = () => { } catch (e) { console.error(e); } - } + }; - const onChangeName = (e: React.ChangeEvent) => { - const target = e.currentTarget; - if (target.value.length > 7) { - target.value = target.value.slice(0, 7); - } - setName(target.value); - setInputCount( - target.value.replace(/[\0-\x7f]|([0-\u07ff]|(.))/g, "$&$1$2").length - ); - setInputCount(target.value.length); - }; - - const onApply = () => { - if (name) { - // 서버에 데이터 전송 - onRegisterNicknameInfo(); - } else { - alert('입력값을 확인해주세요.'); - } - }; - - const onRegisterNicknameInfo = async () => { - try { - const response = (await nickNameAPI({ - nick_name : name, - })).data - refreshMyInfo(); - console.log(response); - } catch (err) { - console.log(err); - } - }; - - return ( - - - -
- signup -

어떤 이름으로 불러드릴까요?

- - vino에 오신걸 환영합니다! 원하시는 이름으로 불러드릴게요 - -
- - - - - - - {inputCount} - - /7(공백포함) - - - {name ? ( - - 등록하기 - ) : ( - ) - } -
-
+ const onChangeName = (e: React.ChangeEvent) => { + const target = e.currentTarget; + if (target.value.length > 7) { + target.value = target.value.slice(0, 7); + } + setName(target.value); + setInputCount( + target.value.replace(/[\0-\x7f]|([0-\u07ff]|(.))/g, '$&$1$2').length, ); + setInputCount(target.value.length); + }; + + const onApply = () => { + if (name) { + // 서버에 데이터 전송 + onRegisterNicknameInfo(); + } else { + createToast('입력값을 확인해주세요.'); + } + }; + + const onRegisterNicknameInfo = async () => { + try { + const response = ( + await nickNameAPI({ + nick_name: name, + }) + ).data; + refreshMyInfo(); + console.log(response); + } catch (err) { + console.log(err); + } }; - - export default NicknameModal; - const ModalDiv = styled.div` + return ( + + +
+ signup +

어떤 이름으로 불러드릴까요?

+ + vino에 오신걸 환영합니다! 원하시는 이름으로 불러드릴게요 + +
+ + + + + {inputCount} + /7(공백포함) + + + {name ? ( + + 등록하기 + + ) : ( + + )} +
+
+ ); +}; + +export default NicknameModal; + +const ModalDiv = styled.div` padding: 40px 50px; display: flex; flex-direction: column; @@ -136,52 +129,52 @@ const NicknameModal = () => { `; const InputBox = styled.input` - width: 202px; - height: 56px; - background-color: #F3F3F3; - padding: 0px 0px 0px 20px; - display: flex; - align-items: center; - justify-content: center; - gap: 20px; - flex: 1 0 0; - font-style: normal; - border: none; - border-radius: 12px; - color: var(--Main, #1E1E1E); - font-family: Pretendard; - ${theme.typography.Body1}; - &:focus { - outline: none; - } - - &::placeholder { + width: 202px; + height: 56px; + background-color: #f3f3f3; + padding: 0px 0px 0px 20px; + display: flex; + align-items: center; + justify-content: center; + gap: 20px; + flex: 1 0 0; + font-style: normal; + border: none; + border-radius: 12px; + color: var(--Main, #1e1e1e); + font-family: Pretendard; + ${theme.typography.Body1}; + &:focus { + outline: none; + } + + &::placeholder { color: #bbb; ${theme.typography.Body1}; } `; const SucButton = styled.button` - width: 100%; - height: 56px; - border: none; - border-radius: 12px; - background-color : #1E1E1E; - color: #fff; - text-align: center; - ${theme.typography.Body1}; - cursor: pointer; + width: 100%; + height: 56px; + border: none; + border-radius: 12px; + background-color: #1e1e1e; + color: #fff; + text-align: center; + ${theme.typography.Body1}; + cursor: pointer; `; const Button = styled.button` - width: 100%; - height: 56px; - border: none; - border-radius: 12px; - background-color : #F3F3F3; - color: #BBBBBB; - text-align: center; - ${theme.typography.Body1}; + width: 100%; + height: 56px; + border: none; + border-radius: 12px; + background-color: #f3f3f3; + color: #bbbbbb; + text-align: center; + ${theme.typography.Body1}; `; const InputNickNameMessage = styled.span` @@ -195,14 +188,14 @@ const InputNickNameLength = styled.span` `; const TextDiv = styled.div` - position : relative; - width : 600px; - height : 56px; - align-items: center; - justify-content: center; - background-color: #F3F3F3; - display: flex; - flex-direction: row; - border-radius: 12px; - margin-top: 48px; - ` \ No newline at end of file + position: relative; + width: 600px; + height: 56px; + align-items: center; + justify-content: center; + background-color: #f3f3f3; + display: flex; + flex-direction: row; + border-radius: 12px; + margin-top: 48px; +`; diff --git a/src/components/SummaryPage/SummaryDetailBox/CategorySelectBox/CategorySelectBox.tsx b/src/components/SummaryPage/SummaryDetailBox/CategorySelectBox/CategorySelectBox.tsx index a405333..cd9acfe 100644 --- a/src/components/SummaryPage/SummaryDetailBox/CategorySelectBox/CategorySelectBox.tsx +++ b/src/components/SummaryPage/SummaryDetailBox/CategorySelectBox/CategorySelectBox.tsx @@ -14,12 +14,16 @@ import { CategoryDropdown } from './CategoryDropdown'; type Props = { disabled?: boolean; selectedCategoryId?: number; + startSelect?: boolean; + setStartSelect?: React.Dispatch>; onSelect: (categoryId: number, categoryName?: string) => void; }; const CategorySelectBox = ({ disabled, selectedCategoryId, + startSelect, + setStartSelect, onSelect, }: Props) => { const userToken = useRecoilValue(userTokenState); @@ -55,11 +59,17 @@ const CategorySelectBox = ({ const handleSelect = (categoryId: number) => { setSelectedId(categoryId); + setStartSelect && setStartSelect(true); setIsOpen(false); }; const handleClick = () => { - if (!selectedCategory || selectedId === selectedCategoryId || disabled) + if ( + !selectedCategory || + selectedId === selectedCategoryId || + disabled || + !startSelect + ) return; onSelect(selectedCategory.categoryId, selectedCategory.name); @@ -95,9 +105,9 @@ const CategorySelectBox = ({ diff --git a/src/components/SummaryPage/SummaryDetailBox/SummaryDetailBox.tsx b/src/components/SummaryPage/SummaryDetailBox/SummaryDetailBox.tsx index 8358d15..0c9e9ed 100644 --- a/src/components/SummaryPage/SummaryDetailBox/SummaryDetailBox.tsx +++ b/src/components/SummaryPage/SummaryDetailBox/SummaryDetailBox.tsx @@ -12,7 +12,6 @@ import { summaryVideoState, summaryVideoTimeState, } from '@/stores/summary'; -import { toastListState } from '@/stores/toast'; import { DetailBox } from '@/styles/SummaryPage'; @@ -21,6 +20,7 @@ import { formatDate } from '@/utils/date'; import { CategorySelectBox } from './CategorySelectBox'; import { NoteBox } from './NoteBox'; import { DescriptionBox } from './DescriptionBox'; +import useCreateToast from '@/hooks/useCreateToast'; type Props = { onRefresh: () => void; @@ -29,6 +29,7 @@ type Props = { const SummaryDetailBox = ({ onRefresh }: Props) => { const player = useRef(); + const { createToast } = useCreateToast(); const summaryVideo = useRecoilValue(summaryVideoState) as IVideo; const summaryUpdateVideo = useRecoilValue(summaryUpdateVideoState); const setSummaryVideoTime = useSetRecoilState(summaryVideoTimeState); @@ -36,16 +37,11 @@ const SummaryDetailBox = ({ onRefresh }: Props) => { const [playSubHeadingId, setPlaySubHeadingId] = useRecoilState( summaryPlaySubHeadingIdState, ); - const [toastList, setToastList] = useRecoilState(toastListState); const subHeading = isEditingView ? summaryUpdateVideo?.subHeading || [] : summaryVideo.subHeading; - const createToast = (content: string) => { - setToastList([...toastList, { id: Date.now(), content }]); - }; - const handleSelectCategory = async (category_id: number, name?: string) => { try { await updateVideoCategoryIdAPI(category_id, { diff --git a/src/components/SummaryPage/SummaryScriptBox/ToolBox/ToolBox.tsx b/src/components/SummaryPage/SummaryScriptBox/ToolBox/ToolBox.tsx index 1967139..f219031 100644 --- a/src/components/SummaryPage/SummaryScriptBox/ToolBox/ToolBox.tsx +++ b/src/components/SummaryPage/SummaryScriptBox/ToolBox/ToolBox.tsx @@ -13,11 +13,11 @@ import { summaryUpdateVideoState, summaryVideoState, } from '@/stores/summary'; -import { toastListState } from '@/stores/toast'; import Indicator from './Indicator'; import { SearchKeyword } from './SearchKeyword'; import { ChangeKeyword } from './ChangeKeyword'; +import useCreateToast from '@/hooks/useCreateToast'; type Props = { onRefresh: () => void; @@ -33,14 +33,10 @@ const ToolBox = ({ onRefresh, onChangeKeyword }: Props) => { const [isEditingView, setIsEditingView] = useRecoilState( summaryIsEditingViewState, ); - const [toastList, setToastList] = useRecoilState(toastListState); + const { createToast } = useCreateToast(); const [originalSummary, setOriginalSummary] = useState(null); - const createToast = (content: string) => { - setToastList([...toastList, { id: Date.now(), content }]); - }; - const handleClickModifyIcon = () => { setPlaySubHeadingId(-1); setIsEditingView(true); diff --git a/src/components/category/Card.tsx b/src/components/category/Card.tsx index 3cc084f..099e02f 100644 --- a/src/components/category/Card.tsx +++ b/src/components/category/Card.tsx @@ -33,6 +33,7 @@ const Card: React.FC = ({ const [selectedCategoryId, setSelectedCategoryId] = useState( category.length ? category[0].categoryId : -1, ); + const [startSelect, setStartSelect] = useState(false); const onFileClickWithProps = (categoryId: number, categoryName?: string) => { setSelectedCategoryId(categoryId); @@ -76,6 +77,8 @@ const Card: React.FC = ({ diff --git a/src/components/category/EditCategoryName.tsx b/src/components/category/EditCategoryName.tsx index c33e9e2..f434873 100644 --- a/src/components/category/EditCategoryName.tsx +++ b/src/components/category/EditCategoryName.tsx @@ -9,7 +9,9 @@ interface IEditCategoryNameProps { categoryId: number; edit: string; setEdit: React.Dispatch>; - setIsEditing: React.Dispatch>; + setIsEditing: React.Dispatch< + React.SetStateAction<{ activated: boolean; categoryId: number }> + >; } const EditCategoryName = ({ diff --git a/src/components/layout/footer/SendEmail.tsx b/src/components/layout/footer/SendEmail.tsx index 08520a0..85522c4 100644 --- a/src/components/layout/footer/SendEmail.tsx +++ b/src/components/layout/footer/SendEmail.tsx @@ -4,10 +4,12 @@ import { useState } from 'react'; import SendEmailImage from '@/assets/mail.png'; import SuccessSendEmailImage from '@/assets/success-mail.png'; import { postFeedback } from '@/apis/feedback'; +import useCreateToast from '@/hooks/useCreateToast'; const SendEmail = () => { const [feedback, setFeedback] = useState(''); const [successSend, setSuccessSend] = useState(false); + const { createToast } = useCreateToast(); const handleInputFeedback = (e: React.ChangeEvent) => setFeedback(e.target.value); @@ -19,7 +21,7 @@ const SendEmail = () => { setSuccessSend(true); return; } - alert('피드백을 전송하는 과정에서 오류가 발생했습니다.'); + createToast('피드백을 전송하는 과정에서 오류가 발생했습니다.'); }; return ( diff --git a/src/components/layout/sideBar/SubCategory.tsx b/src/components/layout/sideBar/SubCategory.tsx index 0a1d891..dfcca2c 100644 --- a/src/components/layout/sideBar/SubCategory.tsx +++ b/src/components/layout/sideBar/SubCategory.tsx @@ -6,14 +6,18 @@ import Option from './Option'; import handleDrag from '@/utils/handleDrag'; import { ISubFolderProps } from 'types/category'; import EditCategoryName from '@/components/category/EditCategoryName'; +import useCreateToast from '@/hooks/useCreateToast'; interface ISubCategoryProps { topId: number; subId: number; - categoryId: number; - name: string; - setIsDeleteModalOpen: React.Dispatch>; + subFolder: ISubFolderProps; grabedCategory: React.MutableRefObject; + isEditing: { activated: boolean; categoryId: number }; + setIsEditing: React.Dispatch< + React.SetStateAction<{ activated: boolean; categoryId: number }> + >; + setIsDeleteModalOpen: React.Dispatch>; putCategoryFolder: () => void; setCategoryId: React.Dispatch>; } @@ -21,18 +25,19 @@ interface ISubCategoryProps { const SubCategory = ({ topId, subId, - categoryId, - name, - setIsDeleteModalOpen, + subFolder, grabedCategory, + isEditing, + setIsEditing, + setIsDeleteModalOpen, putCategoryFolder, setCategoryId, }: ISubCategoryProps) => { const [subFolderOptionModalOpen, setSubFolderOptionModalOpen] = useState(false); - const [isEditing, setIsEditing] = useState(false); - const [edit, setEdit] = useState(name); + const [edit, setEdit] = useState(subFolder.name); const [beforeEdit, setBeforeEdit] = useState(edit); + const { createToast } = useCreateToast(); const [subFolderOptionModalRef] = useOutsideClick(() => setSubFolderOptionModalOpen(false), @@ -43,15 +48,20 @@ const SubCategory = ({ const handleOptionClick = (e: React.MouseEvent, option: string) => { e.stopPropagation(); if (option === '수정') { - setIsEditing(true); + if (subFolder.name === '기타') { + createToast(`'기타' 폴더는 수정할 수 없습니다.`); + setSubFolderOptionModalOpen(false); + return; + } + setIsEditing({ activated: true, categoryId: subFolder.categoryId }); setBeforeEdit(edit); } else if (option === '삭제') { - if (name === '기타') { - alert(`'기타' 폴더는 삭제할 수 없습니다.`); + if (subFolder.name === '기타') { + createToast(`'기타' 폴더는 삭제할 수 없습니다.`); setSubFolderOptionModalOpen(false); return; } - setCategoryId(categoryId); + setCategoryId(subFolder.categoryId); setIsDeleteModalOpen(true); } setSubFolderOptionModalOpen(false); @@ -65,8 +75,8 @@ const SubCategory = ({ const handleDragStart = () => (grabedCategory.current = { - categoryId: categoryId, - name, + categoryId: subFolder.categoryId, + name: subFolder.name, topCategoryId: topId, }); @@ -79,10 +89,10 @@ const SubCategory = ({ onDragStart={handleDragStart} onDragEnd={putCategoryFolder} > - {isEditing ? ( + {isEditing.activated && isEditing.categoryId === subFolder.categoryId ? (
{edit} - - - + {!isEditing.activated && ( + + + + )} {subFolderOptionModalOpen && (