From 115ffb8a749cbe661848feda8d6b922bbf0763f7 Mon Sep 17 00:00:00 2001 From: keyy1315 Date: Wed, 7 May 2025 18:06:10 +0900 Subject: [PATCH] feat: set SurveyList Filtering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 조사 매물 목록 페이지 필터링 구현 - 기존 survey-sales 샘플 페이지 모두 삭제 --- src/components/survey-sale/list/ListTable.tsx | 47 ++++- .../survey-sale/list/SearchForm.tsx | 6 +- src/components/survey-sales/EtcCheckbox.tsx | 68 ------- src/components/survey-sales/SurveyDetail.tsx | 61 ------- src/components/survey-sales/SurveyFilter.tsx | 22 --- .../survey-sales/SurveySaleList.tsx | 90 ---------- .../write-survey-sales/BasicWriteForm.tsx | 86 --------- .../write-survey-sales/DetailWriteForm.tsx | 157 ---------------- .../write-survey-sales/MainSurveyForm.tsx | 168 ------------------ src/store/surveyFilterStore.ts | 27 +++ 10 files changed, 70 insertions(+), 662 deletions(-) delete mode 100644 src/components/survey-sales/EtcCheckbox.tsx delete mode 100644 src/components/survey-sales/SurveyDetail.tsx delete mode 100644 src/components/survey-sales/SurveyFilter.tsx delete mode 100644 src/components/survey-sales/SurveySaleList.tsx delete mode 100644 src/components/survey-sales/write-survey-sales/BasicWriteForm.tsx delete mode 100644 src/components/survey-sales/write-survey-sales/DetailWriteForm.tsx delete mode 100644 src/components/survey-sales/write-survey-sales/MainSurveyForm.tsx create mode 100644 src/store/surveyFilterStore.ts diff --git a/src/components/survey-sale/list/ListTable.tsx b/src/components/survey-sale/list/ListTable.tsx index a9cfd34..c39b00c 100644 --- a/src/components/survey-sale/list/ListTable.tsx +++ b/src/components/survey-sale/list/ListTable.tsx @@ -2,39 +2,72 @@ import LoadMoreButton from '@/components/LoadMoreButton' import { useServey } from '@/hooks/useSurvey' -import { useState } from 'react' +import { useEffect, useMemo, useState } from 'react' import { useRouter } from 'next/navigation' +import SearchForm from './SearchForm' export default function ListTable() { const router = useRouter() const { surveyList, isLoadingSurveyList } = useServey() - const [hasMore, setHasMore] = useState(surveyList.length > 5) const [visibleItems, setVisibleItems] = useState(5) + const [search, setSearch] = useState('') + const [isMyPostsOnly, setIsMyPostsOnly] = useState(false) + const [hasMore, setHasMore] = useState(false) + + // TODO: 로그인 구현 이후 USERNAME 변경 + const username = 'test' + + const filteredSurveyList = useMemo(() => { + let filtered = surveyList + if (search.trim().length > 0) { + filtered = filtered.filter((survey) => survey.building_name?.includes(search)) + } + if (isMyPostsOnly) { + filtered = filtered.filter((survey) => survey.representative === username) + } + return filtered + }, [surveyList, search, isMyPostsOnly, username]) + + useEffect(() => { + setHasMore(filteredSurveyList.length > visibleItems) + }, [filteredSurveyList, visibleItems]) const handleLoadMore = () => { - const newVisibleItems = Math.min(visibleItems + 5, surveyList.length) + const newVisibleItems = Math.min(visibleItems + 5, filteredSurveyList.length) setVisibleItems(newVisibleItems) - setHasMore(newVisibleItems < surveyList.length) + setHasMore(newVisibleItems < filteredSurveyList.length) } const handleScrollToTop = () => { window.scrollTo({ top: 0, behavior: 'smooth' }) } - const handleDetail = (id: number) => { + const handleDetailClick = (id: number) => { router.push(`/survey-sale/${id}`) } + + const handleSearchChange = (e: React.ChangeEvent) => { + setSearch(e.target.value) + setVisibleItems(5) + } + + const handleMyPostsToggle = () => { + setIsMyPostsOnly((prev) => !prev) + setVisibleItems(5) + } + if (isLoadingSurveyList) { return
Loading...
} return ( <> +
    - {surveyList.slice(0, visibleItems).map((survey) => ( -
  • handleDetail(survey.id)}> + {filteredSurveyList.slice(0, visibleItems).map((survey) => ( +
  • handleDetailClick(survey.id)}>
    {survey.id}
    diff --git a/src/components/survey-sale/list/SearchForm.tsx b/src/components/survey-sale/list/SearchForm.tsx index 67794a2..8942836 100644 --- a/src/components/survey-sale/list/SearchForm.tsx +++ b/src/components/survey-sale/list/SearchForm.tsx @@ -2,7 +2,7 @@ import { useRouter } from 'next/navigation' -export default function SearchForm() { +export default function SearchForm({ handleSearch, handleMyPosts }: { handleSearch: (e: React.ChangeEvent) => void, handleMyPosts: () => void }) { const router = useRouter() return (
    @@ -22,13 +22,13 @@ export default function SearchForm() {
    - +
    - +
    diff --git a/src/components/survey-sales/EtcCheckbox.tsx b/src/components/survey-sales/EtcCheckbox.tsx deleted file mode 100644 index 1dd6c03..0000000 --- a/src/components/survey-sales/EtcCheckbox.tsx +++ /dev/null @@ -1,68 +0,0 @@ -'use client' -import { useState } from "react" -import { SurveyDetailRequest } from "@/types/Survey" - -interface EtcCheckboxProps { - formName: keyof SurveyDetailRequest - label: string - detailInfoForm: SurveyDetailRequest - setDetailInfoForm: (form: SurveyDetailRequest) => void -} - -export default function EtcCheckbox({ formName, label, detailInfoForm, setDetailInfoForm }: EtcCheckboxProps) { - const [showEtcInput, setShowEtcInput] = useState(false) - const etcFieldName = `${formName}_etc` as keyof SurveyDetailRequest - - return ( -
    - -
    -
    - setDetailInfoForm({ - ...detailInfoForm, - [formName]: e.target.checked ? 1 : 0 - })} - /> - -
    - -
    - { - setShowEtcInput(e.target.checked) - if (!e.target.checked) { - setDetailInfoForm({ - ...detailInfoForm, - [etcFieldName]: '' - }) - } - }} - /> - - - {showEtcInput && ( - setDetailInfoForm({ - ...detailInfoForm, - [etcFieldName]: e.target.value - })} - className="border rounded px-2 py-1 ml-2" - /> - )} -
    -
    -
    - ) -} - diff --git a/src/components/survey-sales/SurveyDetail.tsx b/src/components/survey-sales/SurveyDetail.tsx deleted file mode 100644 index bff8618..0000000 --- a/src/components/survey-sales/SurveyDetail.tsx +++ /dev/null @@ -1,61 +0,0 @@ -// 'use client' - -// import { useServey } from '@/hooks/useSurvey' -// import { useParams, useRouter } from 'next/navigation' - -// export default function SurveyDetail() { -// const params = useParams() -// const id = params.id -// const router = useRouter() - -// const { surveyDetail, deleteSurvey, isDeletingSurvey, confirmSurvey } = useServey(Number(id)) - -// console.log('surveyDetail:: ', surveyDetail) - -// const handleDelete = async () => { -// if (confirm('delete?')) { -// if (surveyDetail?.representative) { -// if (surveyDetail.detail_info?.id) { -// await deleteSurvey({ id: Number(surveyDetail.detail_info.id), isDetail: true }) -// } -// await deleteSurvey({ id: Number(id), isDetail: false }) -// } -// alert('delete success') -// router.push('/survey-sales') -// } -// } -// const handleSubmit = () => { -// if (confirm('submit?')) { -// confirmSurvey(Number(id)) -// } -// alert('submit success') -// router.push('/survey-sales') -// } - -// if (isDeletingSurvey) { -// return
    Deleting...
    -// } - -// return ( -//
    -//

    SurveyDetail

    -//

    {id}

    -//

    {surveyDetail?.representative}

    -//
    -// -// -// -// -//
    -// -//
    -// ) -// } diff --git a/src/components/survey-sales/SurveyFilter.tsx b/src/components/survey-sales/SurveyFilter.tsx deleted file mode 100644 index 2249186..0000000 --- a/src/components/survey-sales/SurveyFilter.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { Search } from 'lucide-react' -import { useRouter } from 'next/navigation' - -export default function SurveyFilter({ handleSearch, handleMyPosts }: { handleSearch: (e: React.ChangeEvent) => void, handleMyPosts: () => void }) { - const router = useRouter() - return ( -
    - -
    - - -
    -
    - -
    -
    - ) -} diff --git a/src/components/survey-sales/SurveySaleList.tsx b/src/components/survey-sales/SurveySaleList.tsx deleted file mode 100644 index 92b9ece..0000000 --- a/src/components/survey-sales/SurveySaleList.tsx +++ /dev/null @@ -1,90 +0,0 @@ -'use client' - -import { useServey } from '@/hooks/useSurvey' -import LoadMoreButton from '@/components/LoadMoreButton' -import { useState } from 'react' -import SurveyFilter from './SurveyFilter' -import { useRouter } from 'next/navigation' - -export default function SurveySaleList() { - const { surveyList, isLoadingSurveyList } = useServey() - const [search, setSearch] = useState('') - const [isMyPostsOnly, setIsMyPostsOnly] = useState(false) - const [hasMore, setHasMore] = useState(surveyList.length > 5) - const [visibleItems, setVisibleItems] = useState(5) - - const router = useRouter() - - // TEMP USERNAME - const username = 'test' - - const surveyData = () => { - if (search.trim().length > 0) { - return surveyList.filter((survey) => survey.building_name?.includes(search)) - } - if (isMyPostsOnly) { - return surveyList.filter((survey) => survey.representative === username) - } - return surveyList - } - - const handleLoadMore = () => { - const newVisibleItems = Math.min(visibleItems + 5, surveyData().length) - setVisibleItems(newVisibleItems) - setHasMore(newVisibleItems < surveyData().length) - } - - const handleScrollToTop = () => { - window.scrollTo({ top: 0, behavior: 'smooth' }) - } - - const handleSearch = (e: React.ChangeEvent) => { - setSearch(e.target.value) - } - - const handleDetail = (id: number | undefined) => { - if (id === undefined) throw new Error('id is required') - router.push(`/survey-sales/${id}`) - } - - if (isLoadingSurveyList) { - return
    Loading...
    - } - - return ( -
    - setIsMyPostsOnly(!isMyPostsOnly)} /> - -
    - {surveyData().slice(0, visibleItems).map((survey) => ( -
    handleDetail(survey.id)} - className="bg-white rounded-lg shadow p-4 hover:shadow-md transition-shadow cursor-pointer border border-gray-200" - > -
    -
    -

    {survey.id}

    -
    -

    담당자: {survey.representative || '-'}

    -

    판매점: {survey.store || '-'}

    -
    -
    - - {survey.submission_status ? '제출' : '미제출'} - -
    -
    - ))} -
    - -
    - -
    -
    - ) -} diff --git a/src/components/survey-sales/write-survey-sales/BasicWriteForm.tsx b/src/components/survey-sales/write-survey-sales/BasicWriteForm.tsx deleted file mode 100644 index 8fe0a6f..0000000 --- a/src/components/survey-sales/write-survey-sales/BasicWriteForm.tsx +++ /dev/null @@ -1,86 +0,0 @@ -'use client' - -import { SurveyBasicRequest } from '@/types/Survey' - -export default function BasicWriteForm({ - basicInfoData, - setBasicInfoData, -}: { - basicInfoData: SurveyBasicRequest - setBasicInfoData: (basicInfoData: SurveyBasicRequest) => void -}) { - const handleChange = (key: keyof SurveyBasicRequest, value: string) => { - setBasicInfoData({ ...basicInfoData, [key]: value.toString() }) - } - - return ( -
    -
    - - handleChange('representative', e.target.value)} - /> -
    -
    - - handleChange('store', e.target.value)} /> -
    -
    - - handleChange('construction_point', e.target.value)} - /> -
    -
    - - handleChange('investigation_date', e.target.value)} - /> -
    -
    - - handleChange('building_name', e.target.value)} - /> -
    -
    - - handleChange('customer_name', e.target.value)} - /> -
    -
    - - handleChange('post_code', e.target.value)} /> -
    -
    - - handleChange('address', e.target.value)} /> -
    -
    - - handleChange('address_detail', e.target.value)} - /> -
    -
    - ) -} diff --git a/src/components/survey-sales/write-survey-sales/DetailWriteForm.tsx b/src/components/survey-sales/write-survey-sales/DetailWriteForm.tsx deleted file mode 100644 index 032d6f1..0000000 --- a/src/components/survey-sales/write-survey-sales/DetailWriteForm.tsx +++ /dev/null @@ -1,157 +0,0 @@ -'use client' -import React from 'react' -import EtcCheckbox from '../EtcCheckbox' -import { SurveyDetailRequest } from '@/types/Survey' - -interface DetailWriteFormProps { - detailInfoForm: SurveyDetailRequest - setDetailInfoForm: (form: SurveyDetailRequest) => void -} - -export default function DetailWriteForm({ detailInfoForm, setDetailInfoForm }: DetailWriteFormProps) { - const handleNumberInput = (field: keyof SurveyDetailRequest, value: string) => { - const numberValue = value === '' ? null : Number(value) - setDetailInfoForm({ ...detailInfoForm, [field]: numberValue }) - } - - const handleTextInput = (field: keyof SurveyDetailRequest, value: string) => { - setDetailInfoForm({ ...detailInfoForm, [field]: value || null }) - } - - const handleBooleanInput = (field: keyof SurveyDetailRequest, checked: boolean) => { - setDetailInfoForm({ ...detailInfoForm, [field]: checked }) - } - - return ( -
    -
    - - handleTextInput('contract_capacity', e.target.value)} - /> -
    - -
    - - handleTextInput('retail_company', e.target.value)} - /> -
    - - - -
    - -
    - -
    - -
    - -
    - -
    - -
    - -
    - -
    - - handleTextInput('roof_slope', e.target.value)} - /> -
    - -
    - -
    - -
    - -
    - -
    - -
    - -
    - -
    - -
    - - handleTextInput('rafter_direction', e.target.value)} - /> -
    - -
    - -
    - -
    - - handleTextInput('open_field_plate_thickness', e.target.value)} - /> -
    - -
    - - handleBooleanInput('leak_trace', e.target.checked)} - /> -
    - -
    - -
    - -
    - -
    - -
    - -
    - -
    - -
    - -
    - -