From 26425e48463154c11b19a672ced685516d40de08 Mon Sep 17 00:00:00 2001 From: JAEMOON Date: Fri, 4 Aug 2023 15:19:16 +0900 Subject: [PATCH] =?UTF-8?q?[feat]=20=20Toast=20Component=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B0=8F=20filter=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/Toast/Toast.module.scss | 3 +++ components/Toast/Toast.tsx | 25 +++++++++++++++++++++ components/index.tsx | 1 + pages/index.tsx | 1 - pages/room/filter.tsx | 27 +++++++++++++++++----- public/js/guDongList.ts | 6 ++--- public/locales/en/common.json | 3 ++- public/locales/en/filter.json | 3 ++- public/locales/ko/filter.json | 36 ++++++++++++++++++++++++++++++ 9 files changed, 94 insertions(+), 11 deletions(-) create mode 100644 components/Toast/Toast.module.scss create mode 100644 components/Toast/Toast.tsx create mode 100644 public/locales/ko/filter.json diff --git a/components/Toast/Toast.module.scss b/components/Toast/Toast.module.scss new file mode 100644 index 0000000..ce038c1 --- /dev/null +++ b/components/Toast/Toast.module.scss @@ -0,0 +1,3 @@ +.toast { + @apply fixed bottom-5 left-1/2 transform -translate-x-1/2 bg-a1 text-white font-bold rounded-lg py-2 px-4 shadow-lg z-10 w-full h-[48px] text-center; +} \ No newline at end of file diff --git a/components/Toast/Toast.tsx b/components/Toast/Toast.tsx new file mode 100644 index 0000000..2063660 --- /dev/null +++ b/components/Toast/Toast.tsx @@ -0,0 +1,25 @@ +import React, { useState, useEffect } from 'react'; +import styles from './Toast.module.scss'; + +interface ToastProps { + message: string; + duration?: number; + onVisibleChange: (visible: boolean) => void; // 새로운 콜백 함수 추가 +} + +export default function Toast({ message, duration = 3000, onVisibleChange }: ToastProps) { + const [visible, setVisible] = useState(true); + + useEffect(() => { + const timer = setTimeout(() => { + setVisible(false); + onVisibleChange(!onVisibleChange); + }, duration); + + return () => { + clearTimeout(timer); + }; + }, [duration, visible, onVisibleChange]); + + return visible ?
{message}
: null; +} diff --git a/components/index.tsx b/components/index.tsx index 9bf45e6..5a947de 100644 --- a/components/index.tsx +++ b/components/index.tsx @@ -16,3 +16,4 @@ export { default as Toggle } from '@/components/Toggle/Toggle.tsx'; export { default as Typography } from '@/components/Typography/Typography.tsx'; export { default as Space } from '@/components/Space.tsx'; export { default as LoginLayout } from '@/components/layouts/LoginLayout.tsx'; +export { default as Toast } from '@/components/Toast/Toast.tsx'; diff --git a/pages/index.tsx b/pages/index.tsx index 3ef3b8e..23ad196 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -14,7 +14,6 @@ import { Chip, Typography } from '@/components/index.tsx'; import { FilterType } from '@/public/types/filter'; import Filter from '@/pages/room/filter.tsx'; import useModal from '@/hooks/useModal.ts'; -import { ModalSetterContext } from '@/context/ModalProvider'; import { FieldValues } from 'react-hook-form'; export const getStaticProps = async ({ locale }: GetStaticPropsContext) => ({ diff --git a/pages/room/filter.tsx b/pages/room/filter.tsx index 3a107ea..d50f991 100644 --- a/pages/room/filter.tsx +++ b/pages/room/filter.tsx @@ -2,7 +2,7 @@ import React, { useState, useEffect, useCallback } from 'react'; import { useTranslation } from 'next-i18next'; import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; import { GetStaticPropsContext } from 'next'; -import { Chip, Select, Typography, Toggle, Checkbox, Space, Button, Input } from '@/components/index.tsx'; +import { Toast, Chip, Select, Typography, Toggle, Checkbox, Space, Button, Input } from '@/components/index.tsx'; import { FieldValues, SubmitHandler, useForm } from 'react-hook-form'; import { GuList, DongList } from '../../public/js/guDongList.ts'; @@ -35,12 +35,18 @@ export default function Filter({ label: '', }); const [selectedOptions, setSelectedOptions] = useState([]); + const [showToast, setShowToast] = useState(false); + const [showMessage, setMessage] = useState(''); const filteredDongList = DongList.filter((v) => v.gu === guValue.value); const onSubmit: SubmitHandler = (data) => { getChildData(data); closeModal(); }; + const handleToastVisibleChange = (visible: boolean) => { + setShowToast(visible); + }; + // 옵션 선택 시 실행될 함수, 유효성 검증 const handleOptionSelect = useCallback(() => { if (!dongValue.label) return; @@ -49,18 +55,25 @@ export default function Filter({ const option = dongValue.label; setSelectedOptions((prevSelectedOptions) => { const isExist = prevSelectedOptions.some((item) => item.includes(option)); + // Location이 5개 이상 선택 될 경우 Toast 노출 + if (prevSelectedOptions.length >= 5) { + setShowToast(true); + // TODO translation 사용해서 여기 나중에 바꿔줘야함 + setMessage('You can select up to five'); + return [...prevSelectedOptions]; + } + if (!isExist) { resultOptions = [...prevSelectedOptions, guValue?.label.concat(`, ${option}`)]; } else { + setShowToast(true); + // TODO translation 사용해서 여기 나중에 바꿔줘야함 + setMessage('Already selected'); resultOptions = prevSelectedOptions; } return [...resultOptions]; }); }, [dongValue.label, guValue?.label]); - - useEffect(() => { - handleOptionSelect(); - }, [dongValue.label, handleOptionSelect]); /** Dong Select Component 변경될 경우 -> 일반 선언형 함수로 정의할 경우 Rendering 마다 새로운 인스턴스가 생성됨 */ const handleDongChange = useCallback( (selectedValue: string, selectedLabel: string) => { @@ -78,6 +91,9 @@ export default function Filter({ const handleOptionRemove = (option: string) => { setSelectedOptions((prevSelectedOptions) => prevSelectedOptions.filter((item) => item !== option)); }; + useEffect(() => { + handleOptionSelect(); + }, [dongValue.label, handleOptionSelect]); return (
@@ -330,6 +346,7 @@ export default function Filter({
+ {showToast && } ); diff --git a/public/js/guDongList.ts b/public/js/guDongList.ts index bab0e08..9d3a6a3 100644 --- a/public/js/guDongList.ts +++ b/public/js/guDongList.ts @@ -95,13 +95,13 @@ export const DongList: DongListItem[] = [ { gu: '200', value: '570', label: 'Hangdangje 2-dong' }, { gu: '200', value: '580', label: 'Eungbong-dong' }, { gu: '200', value: '590', label: 'Kumho 1-ga-dong' }, - { gu: '200', value: '615', label: 'Kumho 2.3' }, - { gu: '200', value: '620', label: 'Kumho4 ga-dong' }, + { gu: '200', value: '615', label: 'Kumho 2.3-ga-dong' }, + { gu: '200', value: '620', label: 'Kumho4 4-ga-dong' }, { gu: '200', value: '645', label: 'Oksu-dong' }, { gu: '200', value: '650', label: 'Seongsu 1-gaje 1-dong' }, { gu: '200', value: '660', label: 'Seongsu 1-gaje 2-dong' }, { gu: '200', value: '670', label: 'Seongsu 2-gaje 1-dong' }, - { gu: '200', value: '690', label: 'Seongsu2gaje3dong' }, + { gu: '200', value: '690', label: 'Seongsu2gaje 3-dong' }, { gu: '200', value: '720', label: 'Songjeong-dong' }, { gu: '200', value: '790', label: 'Yongdap-dong' }, { gu: '215', value: '710', label: 'Hwayang-dong' }, diff --git a/public/locales/en/common.json b/public/locales/en/common.json index ab255fb..e7982be 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -9,5 +9,6 @@ "samePassword": "Please check again", "next": "Next", "complete": "Complete", - "filters" : "Filters" + "filters" : "Filters", + "uptofive" : "You can select up to five" } diff --git a/public/locales/en/filter.json b/public/locales/en/filter.json index 0f0cb87..c773e15 100644 --- a/public/locales/en/filter.json +++ b/public/locales/en/filter.json @@ -31,5 +31,6 @@ "kitchenette": "Kitchenette", "reset": "Reset", "apply": "Apply", - "mmddyyyy": "MM-DD-YYYY" + "mmddyyyy": "MM-DD-YYYY", + "uptofive" : "You can select up to five" } diff --git a/public/locales/ko/filter.json b/public/locales/ko/filter.json new file mode 100644 index 0000000..c773e15 --- /dev/null +++ b/public/locales/ko/filter.json @@ -0,0 +1,36 @@ +{ + "location": "Location", + "gu": "Gu", + "koo": "Gu", + "dong": "Dong", + "deposit": "Deposit", + "viewRoomsWithoutDeposit": "View rooms without deposit", + "minMax": "Min 0 ₩ - Max 500,000,000 ₩ ", + "min": "Min", + "max": "Max", + "monthRent": "Monthly rent", + "includeMainFee": "Include maintenance fee", + "dateAvailable": "Date available", + "viewRoomsAvailable": "View rooms available now", + "typeOfHousing": "Type of housing", + "studio": "Studio", + "bedFlats ": "1bed flats", + "shareHouse": "Share house", + "furnishing": "Furnishing", + "bed": "Bed", + "wardrobe": "Wardrobe", + "tv": "TV", + "airconditioner": "Air conditioner", + "heater": "Heater", + "doorLock": "Door lock", + "refrigerator": "Refrigerator", + "stove": "Stove", + "washingMachine": "Washing machine", + "induction": "Induction", + "gasStove": "Gas stove", + "kitchenette": "Kitchenette", + "reset": "Reset", + "apply": "Apply", + "mmddyyyy": "MM-DD-YYYY", + "uptofive" : "You can select up to five" +}