diff --git a/package-lock.json b/package-lock.json index dd35a588..52fa07ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "@swc-jotai/react-refresh": "^0.1.0", "@types/node": "^20", "@types/react": "^18", + "@types/react-datepicker": "^6.2.0", "@types/react-beautiful-dnd": "^13.1.8", "@types/react-dom": "^18", "eslint": "^8.56.0", @@ -1991,6 +1992,17 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-datepicker": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@types/react-datepicker/-/react-datepicker-6.2.0.tgz", + "integrity": "sha512-+JtO4Fm97WLkJTH8j8/v3Ldh7JCNRwjMYjRaKh4KHH0M3jJoXtwiD3JBCsdlg3tsFIw9eQSqyAPeVDN2H2oM9Q==", + "dev": true, + "dependencies": { + "@floating-ui/react": "^0.26.2", + "@types/react": "*", + "date-fns": "^3.3.1" + } + }, "node_modules/@types/react-beautiful-dnd": { "version": "13.1.8", "resolved": "https://registry.npmjs.org/@types/react-beautiful-dnd/-/react-beautiful-dnd-13.1.8.tgz", diff --git a/package.json b/package.json index 58801b7d..7e715262 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "@swc-jotai/react-refresh": "^0.1.0", "@types/node": "^20", "@types/react": "^18", + "@types/react-datepicker": "^6.2.0", "@types/react-beautiful-dnd": "^13.1.8", "@types/react-dom": "^18", "eslint": "^8.56.0", diff --git a/src/components/Selector/index.tsx b/src/components/Selector/index.tsx index 458681d9..0ca606b8 100644 --- a/src/components/Selector/index.tsx +++ b/src/components/Selector/index.tsx @@ -6,7 +6,7 @@ import { BiChevronDown } from 'react-icons/bi'; import { SelectorProps } from './types'; -const Selector = ({ selected, label, handleSelector }: SelectorProps) => { +const Selector = ({ placeholder, selected, label, handleSelector, handleClose }: SelectorProps) => { const menuRef = useRef(null); const [menuWidth, setMenuWidth] = useState('0px'); @@ -17,7 +17,7 @@ const Selector = ({ selected, label, handleSelector }: SelectorProps) => { }, []); return ( - + { _focus={{ bg: 'orange_light' }} rightIcon={} > - {selected} + {selected || placeholder} void; + handleClose?: () => void; } diff --git a/src/constants/crop.ts b/src/constants/crop.ts new file mode 100644 index 00000000..c607c716 --- /dev/null +++ b/src/constants/crop.ts @@ -0,0 +1,9 @@ +const CROP = [ + { id: 1, name: '토마토' }, + { id: 2, name: '고구마' }, + { id: 3, name: '당근' }, + { id: 4, name: '완두콩' }, + { id: 5, name: '벼' }, +]; + +export default CROP; diff --git a/src/containers/team/CreateStudyModal/index.tsx b/src/containers/team/CreateStudyModal/index.tsx new file mode 100644 index 00000000..912fd8ec --- /dev/null +++ b/src/containers/team/CreateStudyModal/index.tsx @@ -0,0 +1,148 @@ +'use client'; + +import { Box, Text, VStack } from '@chakra-ui/react'; +import { useEffect, useRef, useState } from 'react'; + +import AutoResizeTextarea from '@/components/AutoResizeTextarea'; +import ActionModal from '@/components/Modal/ActionModal'; +import Selector from '@/components/Selector'; +import StyledDatePicker from '@/components/StyledDatePicker'; +import CROP from '@/constants/crop'; + +import { CreateStudyModalProps } from './types'; + +const AlertContent = ({ message }: { message: string }) => { + return ( + + {message} + + ); +}; + +const CreateStudyModal = ({ isOpen, setIsModalOpen }: CreateStudyModalProps) => { + const [step, setStep] = useState(1); + const [name, setName] = useState(''); + const [description, setDescription] = useState(''); + const [cropName, setCropName] = useState(''); + const [cropId, setCropId] = useState(0); + const [startDate, setStartDate] = useState(null); + const [endDate, setEndDate] = useState(null); + const [alertName, setAlertName] = useState(false); + const [alertDescription, setAlertDescription] = useState(false); + const [alertSelectedCropId, setAlertSelectedCropId] = useState(false); + const [alertStartDate, setAlertStartDate] = useState(false); + + const handlePrevButtonClick = () => { + setStep(step - 1); + }; + const handleNextButtonClick = () => { + if (name === '') setAlertName(true); + if (description === '') setAlertDescription(true); + if (name !== '' && description !== '') setStep(step + 1); + }; + const handleSaveButtonClick = () => { + if (cropName === '') setAlertSelectedCropId(true); + if (startDate === null) setAlertStartDate(true); + if (cropName !== '' && startDate !== null) setIsModalOpen(false); + }; + const handleNameChange = (e: React.ChangeEvent) => { + setName(e.target.value); + }; + const handleDescriptionChange = (e: React.ChangeEvent) => { + setDescription(e.target.value); + }; + const handleStartDateChange = (date: Date | null) => { + setStartDate(date); + }; + const handleEndDateChange = (date: Date | null) => { + setEndDate(date); + }; + + const cropRef = useRef(cropName); + + useEffect(() => { + cropRef.current = cropName; + }, [cropName]); + + return ( + setIsModalOpen(false)} + title="스터디 생성" + subButtonText={step === 1 ? '취소' : '이전'} + mainButtonText={step === 1 ? '다음' : '저장'} + onSubButtonClick={step === 1 ? () => setIsModalOpen(false) : handlePrevButtonClick} + onMainButtonClick={step === 1 ? handleNextButtonClick : handleSaveButtonClick} + > + + {step === 1 && ( + <> + + 스터디 이름 * + + {alertName && } + ) => { + if (e.target.value !== '') setAlertName(false); + else setAlertName(true); + }} + /> + + 스터디 소개 * + + {alertDescription && } + ) => { + if (e.target.value !== '') setAlertDescription(false); + else setAlertDescription(true); + }} + /> + + )} + {step === 2 && ( + <> + + 작물 선택 * + + {alertSelectedCropId && } + crop.name)} + handleSelector={(value) => { + setCropName(value); + setCropId(CROP.find((crop) => crop.name === value)?.id || 0); + cropRef.current = value; + }} + handleClose={() => { + if (cropRef.current !== '') setAlertSelectedCropId(false); + else setAlertSelectedCropId(true); + }} + /> + + 날짜 선택 * + + {alertStartDate && } + + + + + + )} + + + ); +}; +export default CreateStudyModal; diff --git a/src/containers/team/CreateStudyModal/types.ts b/src/containers/team/CreateStudyModal/types.ts new file mode 100644 index 00000000..a844e831 --- /dev/null +++ b/src/containers/team/CreateStudyModal/types.ts @@ -0,0 +1,4 @@ +export interface CreateStudyModalProps { + isOpen: boolean; + setIsModalOpen: (isOpen: boolean) => void; +}