diff --git a/components/Filter/Filter.tsx b/components/Filter/Filter.tsx index beae97c..a0aedf6 100644 --- a/components/Filter/Filter.tsx +++ b/components/Filter/Filter.tsx @@ -30,9 +30,10 @@ export default function Filter({ const { register, handleSubmit, watch, reset } = useForm({ mode: 'onChange' }); const [selectedLocations, setSelectedLocations] = useState([]); const [count, setCount] = useState(0); + const [searchParams, setSearchParams] = useState({}); - const onSubmit: SubmitHandler = (data) => { - getChildData(data); + const onSubmit: SubmitHandler = () => { + getChildData(searchParams); closeModal(); }; @@ -123,6 +124,24 @@ export default function Filter({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [dong]); + const [housingChecked, setHousingChecked] = useState([]); + const handleHousingCheck = (value: string, isChecked: boolean) => { + if (isChecked) { + setHousingChecked((prev) => [...prev, value]); + } else { + setHousingChecked((prev) => prev.filter((item) => item !== value)); + } + }; + + const [furnishingChecked, setFurnishingChecked] = useState<(string | number)[]>([]); + const handleFurnishingCheck = (value: string | number, isChecked: boolean) => { + if (isChecked) { + setFurnishingChecked((prev) => [...prev, value]); + } else { + setFurnishingChecked((prev) => prev.filter((item) => item !== value)); + } + }; + const minDeposit = watch('depositMin'); const maxDeposit = watch('depositMax'); const minMonthlyRent = watch('monthMin'); @@ -138,18 +157,32 @@ export default function Filter({ !maxDeposit && !minMonthlyRent && !maxMonthlyRent && - !dateAvailable + !dateAvailable && + !housingChecked.length && + !furnishingChecked.length ) { return; } const fetchData = async () => { + setSearchParams({ + locationIds: formattedSelectedLocation.join(', '), + minDeposit, + maxDeposit, + minMonthlyRent, + maxMonthlyRent, + types: housingChecked.join(', '), + furnishingTypes: furnishingChecked.join(', '), + ...(dateAvailable ? { availableDate: formatDateForAPI(dateAvailable) } : {}), + }); const data = await getRooms({ locationIds: formattedSelectedLocation.join(', '), minDeposit, maxDeposit, minMonthlyRent, maxMonthlyRent, + types: housingChecked.join(', '), + furnishingTypes: furnishingChecked.join(', '), ...(dateAvailable ? { availableDate: formatDateForAPI(dateAvailable) } : {}), }); if (data) { @@ -158,7 +191,16 @@ export default function Filter({ }; fetchData(); - }, [selectedLocations, minDeposit, maxDeposit, minMonthlyRent, maxMonthlyRent, dateAvailable]); + }, [ + selectedLocations, + minDeposit, + maxDeposit, + minMonthlyRent, + maxMonthlyRent, + dateAvailable, + housingChecked, + furnishingChecked, + ]); return (
@@ -269,6 +311,7 @@ export default function Filter({ label={item.label} register={register(item.value)} checked={watch(item.value)} + onChange={(e) => handleHousingCheck(item.value, e)} key={item.value} /> ); @@ -289,6 +332,7 @@ export default function Filter({ type="outlined" label={item.label} register={register(`furnishing-${item.value}`)} + onChange={(e) => handleFurnishingCheck(item.value, e)} key={item.value} /> ); diff --git a/components/Input/Input.module.scss b/components/Input/Input.module.scss index a1b821f..2f59b89 100644 --- a/components/Input/Input.module.scss +++ b/components/Input/Input.module.scss @@ -9,6 +9,14 @@ } } +.input::before { + content: '$'; + position: absolute; + left: 10px; /* 원하는 위치로 조절 */ + top: 50%; /* 수직 가운데 정렬 */ + transform: translateY(-50%); +} + .eye { @apply w-[24px] h-[24px]; } diff --git a/components/Input/Input.tsx b/components/Input/Input.tsx index ef911b0..9438862 100644 --- a/components/Input/Input.tsx +++ b/components/Input/Input.tsx @@ -9,9 +9,10 @@ interface InputProps { error?: FieldError; maxLength?: number; disabled?: boolean; + fixedWord?: string; } -function Input({ placeholder, register, type, error, maxLength, disabled }: InputProps) { +function Input({ placeholder, register, type, error, maxLength, disabled, fixedWord }: InputProps) { const hasError = error && error.message; const [isPasswordShow, setIsPasswordShow] = useState(false); const inputType = useMemo(() => { diff --git a/package.json b/package.json index b3bc675..62f2cb0 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "@storybook/testing-library": "^0.1.0", "@svgr/webpack": "5.5.0", "@types/date-fns": "^2.6.0", + "@types/lodash-es": "^4.17.10", "@types/next-auth": "^3.15.0", "@types/node": "20.2.5", "@types/react": "18.2.7", diff --git a/pages/index.tsx b/pages/index.tsx index 646d1e2..4a59dec 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -11,29 +11,40 @@ import { FilterType } from '@/public/types/filter'; import useModal from '@/hooks/useModal.ts'; import { FieldValues } from 'react-hook-form'; import Filter from '@/components/Filter/Filter.tsx'; -import { useTranslation } from 'next-i18next'; import { getRooms } from '@/api/room'; +import isEmpty from 'lodash-es/isEmpty'; type HomeProps = NextPage & { getLayout: (page: React.ReactElement, ctx: NextPageContext) => React.ReactNode; }; +const FILTER_LABEL: Record = { + locationIds: 'Location', + maxDeposit: 'Deposit', + maxMonthlyRent: 'Monthly rent', + availableDate: 'Date available', + types: 'Type of housing', + furnishingTypes: 'Furnishing', +}; + function Home() { - const commonTranslation = useTranslation('common'); const [rooms, setRooms] = useState([]); const [filters, setFilters] = useState([]); - // const [selectedOptions, setSelectedOptions] = useState([]); const [clickedChip, setClickedChip] = useState(''); const router = useRouter(); const { openModal, closeModal } = useModal(); const [page, setPage] = useState(0); const [totalElements, setTotalElements] = useState(0); + const [searchParams, setSearchParams] = useState>({}); // TODO: 전체 페이지보다 크면 페이징 처리 안되도록 수정 const selectRooms = async () => { try { - const data = await getRooms({ page }); + const data = await getRooms({ + ...searchParams, + page, + }); setRooms(data?.content || []); setTotalElements(data?.totalElements || 0); } catch (error) { @@ -41,78 +52,23 @@ function Home() { } }; - const makeFilters = (filterParams: FilterType) => { + const makeFilters = (filterParams: Record) => { const resultFilter: string[] = []; Object.keys(filterParams).forEach((key) => { - // eslint-disable-next-line no-unused-expressions - filterParams[`${key}`] && resultFilter.push(commonTranslation.t(`${key}`)); + if (!isEmpty(filterParams[key])) { + resultFilter.push(FILTER_LABEL[key]); + } }); setFilters(() => [...resultFilter]); }; const target = useRef(null); - const makeSubmitParam = (data: FieldValues): FilterType => { - const typeOfHousings = ['studioChecked', 'bedFlatsChecked', 'shareHouseChecked']; - const furnishings = [ - 'bedChecked', - 'inductionChecked', - 'airconditionerChecked', - 'stoveChecked', - 'refregeratorChecked', - 'wardrobeChecked', - 'washingMachineChecked', - 'doorLockChecked', - 'tvChecked', - 'kitchenetteChecked', - 'heaterChecked', - ]; - - let typeOfHousing = false; - let furnishing = false; - let monthRent = false; - let deposit = false; - let location = false; - let dateAvailable = false; - - // typeOfHousing 중 하나라도 체크되면 true - typeOfHousings.forEach((key) => { - if (data[`${key}`]) { - typeOfHousing = true; - } - }); - - // furnishing 중 하나라도 체크되면 true - furnishings.forEach((key) => { - if (data[`${key}`]) { - furnishing = true; - } - }); - - // monthRent 비용 체크 - if ((data[`${'monthMax'}`] || '') !== '' || (data[`${'monthMin'}`] || '') !== '') { - monthRent = true; - } - - // deposit 비용 체크 - if ((data[`${'depositMax'}`] || '') !== '' || (data[`${'depositMin'}`] || '') !== '') { - deposit = true; - } - - if ((data.gu || '') !== '') { - location = true; - } - - if ((data.dateAvailable || '') !== '') { - dateAvailable = true; - } - return { typeOfHousing, furnishing, monthRent, deposit, location, dateAvailable }; - }; - - const getChildData = async (childData: any) => { - const filteredChips = makeSubmitParam(childData); - makeFilters(filteredChips); - await selectRooms(); + const getChildData = async (childData: Record) => { + makeFilters(childData); + setPage(0); + setSearchParams(childData); + setRooms([]); }; const openFilterPopup = () => { @@ -133,7 +89,6 @@ function Home() { const callback = async (entries: IntersectionObserverEntry[]) => { const [{ isIntersecting }] = entries; - // target?.current?.innerText += '관측되었습니다'; if (isIntersecting) { setPage((prev) => prev + 1); } @@ -145,12 +100,13 @@ function Home() { } const fetchData = async () => { - const data = await getRooms({ page }); + const data = await getRooms({ ...searchParams, page }); setRooms((prevRooms) => [...prevRooms, ...(data?.content || [])]); + setTotalElements(data?.totalElements || 0); }; fetchData(); - }, [page]); + }, [page, searchParams]); // 최초 접근 시 Room 정보 조회 useEffect(() => { @@ -188,8 +144,19 @@ function Home() { const resultFilters = filters.filter((item) => item !== option); setFilters(() => [...resultFilters]); + const selectedOption = Object.keys(FILTER_LABEL).find((key) => { + return FILTER_LABEL[key] === option; + }); + setPage(0); + setRooms([]); + setSearchParams((prev) => { + return { + ...prev, + [selectedOption as string]: '', + }; + }); + // 선택된 칩이 없거나 클릭된 칩이 삭제된 칩인 경우에 맨 처음 칩을 clickedChip으로 설정 - // if ((clickedChip || '' ) === '' || selectedOptions.length !== filters.length) { if ((clickedChip || '') === '') { setClickedChip(filters?.[0]); } @@ -204,9 +171,8 @@ function Home() { style={{ alignSelf: 'flex-start' }} /> {filters.map((label, index) => { - console.log('label >>', label); return ( -
+