diff --git a/src/App.jsx b/src/App.jsx index 41ccabc..42a5d4c 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,15 +1,41 @@ -import { EmptyView, Header } from '@/components'; +import { createContext, useState } from 'react'; + +import { EmptyView, Header, ListView } from '@/components'; +import useModalContext from '@/components/Context/formProvider'; import styles from './App.module.scss'; +export const modalContext = createContext(); + function App() { + const { form, updateForm, modalIndex, updateModalIndex, resetForm } = + useModalContext(); + + const users = localStorage.getItem('goormUsers') + ? JSON.parse(localStorage.getItem('goormUsers')) + : []; + return ( -
-
-
- -
-
+ +
+
+
+ {users.length > 0 ? ( + + ) : ( + + )} +
+
+
); } diff --git a/src/components/Context/formProvider.jsx b/src/components/Context/formProvider.jsx new file mode 100644 index 0000000..6c64d6e --- /dev/null +++ b/src/components/Context/formProvider.jsx @@ -0,0 +1,74 @@ +import { createContext, useEffect, useState } from 'react'; + +const intialState = { + // 1번 + name: '이름', + phone: '01012345678', + email: 'test@email.com', + permissions: { + privacyApproval: false, + marketingApproval: false, + marketingMediaApproval: { + email: false, + sms: false, + }, + + // 2번 + + swMajored: true, + groomUsed: true, + groomService: { + edu: false, + level: false, + devth: false, + ide: false, + exp: false, + }, + groomWhy: '', + + // 3번 + + expect: -1 /* 0번 ~ 3번 중 택 1 선택 */, + + // 4번 + + freeMessage: '파이팅~~', + }, +}; + +const useModalContext = () => { + const [form, setFormState] = useState(intialState); + + const [modalIndex, setModalIndex] = useState(0); + + const updateForm = (key, value) => { + setFormState((prev) => { + return { + ...prev, + [key]: value, + }; + }); + + console.log('update Form', form); + }; + + const updateModalIndex = (value) => { + setModalIndex(value); + }; + + const resetForm = () => { + setFormState(intialState); + }; + + const api = { + form, + updateForm, + modalIndex, + updateModalIndex, + resetForm, + }; + + return api; +}; + +export default useModalContext; diff --git a/src/components/EmptyView/EmptyView.jsx b/src/components/EmptyView/EmptyView.jsx index fa09372..8784aed 100644 --- a/src/components/EmptyView/EmptyView.jsx +++ b/src/components/EmptyView/EmptyView.jsx @@ -1,3 +1,4 @@ +import { useContext } from 'react'; import cn from 'classnames'; import { Card } from '@/components'; diff --git a/src/components/EmptyView/EmptyView.module.scss b/src/components/EmptyView/EmptyView.module.scss index 9f33e54..07bb50d 100644 --- a/src/components/EmptyView/EmptyView.module.scss +++ b/src/components/EmptyView/EmptyView.module.scss @@ -1,4 +1,6 @@ .emptyView { + display: flex; + flex-direction: column; padding-top: 4.5rem /* 72px -> 4.5rem */; padding-bottom: 4.5rem /* 72px -> 4.5rem */; gap: .5rem /* 8px -> .5rem */; diff --git a/src/components/Header/Header.jsx b/src/components/Header/Header.jsx index cb03179..8c82706 100644 --- a/src/components/Header/Header.jsx +++ b/src/components/Header/Header.jsx @@ -1,18 +1,46 @@ +import React, { useContext, useState } from 'react'; import cn from 'classnames'; import { Button, Typography } from '@goorm-dev/gds-challenge'; +import useModalContext from '../Context/formProvider'; +import CustomModal from '../Modal'; + import styles from './Header.module.scss'; const Header = () => { + const { form, updateForm, modalIndex, updateModalIndex, resetForm } = + useModalContext(); + const [modalOpen, setModalOpen] = useState(false); + + const toggle = () => { + setModalOpen((prevModalOpen) => { + return !prevModalOpen; + }); + }; + + const handleCloseModal = () => { + toggle(); + resetForm(); + }; + + const handleModalOpen = () => { + updateModalIndex(0); + toggle(); + }; + return (
구름톤 챌린지 참여자 정보 수집 - +
+ +
); }; diff --git a/src/components/ListView/ListView.jsx b/src/components/ListView/ListView.jsx new file mode 100644 index 0000000..6739807 --- /dev/null +++ b/src/components/ListView/ListView.jsx @@ -0,0 +1,24 @@ +import UserDetails from '../UserDetail/UserDetails'; +import { Typography } from '@goorm-dev/gds-challenge'; + +import { Card } from '@/components'; +import React from 'react'; + +const ListView = ({ users }) => { + + return ( + <> + + 응답한 참여자{" "} + {users.length} + + {users.map((user, idx) => ( + + + + ))} + + ) +}; + +export default ListView; \ No newline at end of file diff --git a/src/components/Modal/components/Modal1.jsx b/src/components/Modal/components/Modal1.jsx new file mode 100644 index 0000000..decb049 --- /dev/null +++ b/src/components/Modal/components/Modal1.jsx @@ -0,0 +1,267 @@ +import React, { useContext, useEffect, useState } from 'react'; + +import { modalContext } from '@/App'; + +import { Button, Form, Input, Label, Modal } from '@goorm-dev/gds-challenge'; + +import useModalContext from '../../Context/formProvider'; + +const Modal1 = ({ onClose, headerName }) => { + const { form, updateForm, modalIndex, updateModalIndex, resetForm } = + useContext(modalContext); + + // name + const [name, setName] = useState(''); + + // phone + const [phone, setPhone] = useState(''); + + // email + const [email, setEmail] = useState(''); + + // permissions + const [allChecked, setAllChecked] = useState(true); + const [privacyChecked, setPrivacyChecked] = useState(true); + const [marketingChecked, setMarketingChecked] = useState(true); + const [adChecked, setAdChecked] = useState(true); + const [emailChecked, setEmailChecked] = useState(true); + const [snsChecked, setSnsChecked] = useState(true); + + const handleNameChange = (e) => { + const input = e.target.value; + setName(input); + console.log(name); + updateForm('name', input); + }; + + const handlePhoneChange = (e) => { + const input = e.target.value; + setPhone(input); + console.log(phone); + }; + + const handleEmailChange = (e) => { + const input = e.target.value; + setEmail(input); + console.log(email); + }; + + useEffect(() => { + setName(name); + setPhone(phone); + setEmail(email); + }, [name, phone, email]); + + // 전체 동의 + const handleAllCheckboxChange = () => { + const newState = !allChecked; + setAllChecked(newState); + setPrivacyChecked(newState); + setMarketingChecked(newState); + setAdChecked(newState); + setEmailChecked(newState); + setSnsChecked(newState); + }; + + // 개인정보처리방침 + const handleprivacyCheckedChange = () => { + const newState = !privacyChecked; + setAllChecked(false); + setPrivacyChecked(newState); + }; + + // 마케팅 목적의 개인 정보 수집 및 이용 + const handlemarketingCheckedChange = () => { + const newState = !marketingChecked; + setAllChecked(false); + setMarketingChecked(newState); + }; + + // 광고성 정보 수신 + const handleadCheckedChange = () => { + const newState = !adChecked; + setAllChecked(false); + setAdChecked(newState); + setEmailChecked(newState); + setSnsChecked(newState); + }; + + // email 정보 수신 + const handleEmailChecked = () => { + const newState = !emailChecked; + setAllChecked(false); + setAdChecked(newState); + setEmailChecked(newState); + }; + + // SNS 정보 수신 + const handleSnsChecked = () => { + const newState = !snsChecked; + setAllChecked(false); + setAdChecked(newState); + setSnsChecked(newState); + }; + // 유효성 검사 함수 + const isEmailValid = (value) => { + return /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(value); + }; + + const isPhoneValid = (value) => { + return /^\d{10,11}$/.test(value); + }; + + const isNextButtonEnabled = () => { + return !( + name === '' || + phone === '' || + email === '' || + !privacyChecked || + (phone.length > 0 && !/^\d{10,11}$/.test(phone)) || + (email.length > 0 && + !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(email)) + ); + }; + + const handleFormSubmit = () => {}; + + return ( + <> + {headerName} + +
+ {/* title & sub title */} +
+
참여자 정보를 입력해주세요.
+
+ 오프라인 팀 챌린지 참여자의 정보를 수집하려고 해요. +
+
+ + + + 0 && !isPhoneValid(phone)} + /> + {phone.length > 0 && isPhoneValid(phone) ? ( + + 양식에 맞게 입력되었습니다. + + ) : ( + phone.length > 0 && + !isPhoneValid(phone) && ( + + 양식에 맞게 입력해주세요. + + ) + )} + + 0 && !isEmailValid(email)} + /> + {email.length > 0 && isEmailValid(email) ? ( + + 양식에 맞게 입력되었습니다. + + ) : ( + email.length > 0 && + !isEmailValid(email) && ( + + 양식에 맞게 입력해주세요. + + ) + )} + +
+ + +
+ +
+ + +
+
+ ※ 광고성 정보 수신에 동의하시면 챌린지에 꾸준히 참여하실 수 + 있도록 리마인드 알림을 보내드려요. +
+
+ + + + + ); +}; + +export default Modal1; diff --git a/src/components/Modal/components/Modal3.jsx b/src/components/Modal/components/Modal3.jsx new file mode 100644 index 0000000..1885bb6 --- /dev/null +++ b/src/components/Modal/components/Modal3.jsx @@ -0,0 +1,122 @@ +// GDS 컴포넌트 +// alias (src/* === @/*) +// import { Card } from '@/components'; +import { useState } from 'react'; + +import useModalContext from '@/components/Context/formProvider'; + +import { + Button, + CarouselIndicators, + Modal, + Typography, +} from '@goorm-dev/gds-challenge'; +// GDS 아이콘 +import { ChevronDoubleLeftIcon } from '@goorm-dev/gds-icons'; + +const Modal3 = ({ isOpen, toggle }) => { + const { form, updateForm, modalIndex, updateModalIndex, resetForm } = + useModalContext(); + + const [expect, setExpect] = useState(); + + const handleBtnClick = (e) => { + const num = e.target.value; + setExpect(num); + }; + + const moveIndex = (index) => { + updateForm('expect', expect); + updateModalIndex(index); + }; + return ( + + + + 오프라인 팀 챌린지에 가장 기대하는 점은 무엇인가요? + + + 더 좋은 챌린지가 될 수 있도록 데이터를 수집하려고 해요. + + + + + + + + + + { + return moveIndex(index); + }} + activeIndex={modalIndex} + /> + +
+ + +
+
+
+ ); +}; + +export default Modal3; diff --git a/src/components/Modal/components/Modal4.jsx b/src/components/Modal/components/Modal4.jsx new file mode 100644 index 0000000..abf3b98 --- /dev/null +++ b/src/components/Modal/components/Modal4.jsx @@ -0,0 +1,88 @@ +import React, { useContext, useState } from 'react'; + +import { + Button, + CarouselIndicators, + Modal, + TextArea, + Typography, +} from '@goorm-dev/gds-challenge'; + +import useModalContext from '../../Context/formProvider'; + +const Modal4 = ({ onClose, headerName }) => { + // const { form, setForm, modal, setModal } = useContext(FormContext); + + const { form, updateForm, modalIndex, updateModalIndex, resetForm } = + useModalContext(); + + const [freeMessage, setFreeMessage] = useState(form.freeMessage); + const handleFormSubmit = () => { + console.log(form); + localStorage.setItem('goormUsers', JSON.stringify(form)); + onClose(); + }; + + const moveIndex = (index) => { + updateForm('freeMessage', freeMessage); + updateModalIndex(index); + }; + + return ( + <> + + + {headerName} + + + 더 좋은 챌린지가 될 수 있도록 데이터를 수집하려고 해요. + + + + +