From 95d971b19833e2ed1291eb2503bf68ec88b89e86 Mon Sep 17 00:00:00 2001 From: keyy1315 Date: Fri, 9 May 2025 15:08:55 +0900 Subject: [PATCH] feat: remove unused survey sale API routes & add address popup at Survey BasicForm --- src/app/api/survey-sale/[id]/route.ts | 72 ------------- src/app/api/survey-sale/route.ts | 33 ------ src/app/api/survey-sales/[id]/route.ts | 16 --- src/app/api/survey-sales/route.ts | 27 +++-- src/app/api/user/route.ts | 7 +- src/app/inquiry/write/page.tsx | 9 -- src/app/layout.tsx | 3 +- src/app/survey-sale/[id]/page.tsx | 2 +- src/app/survey-sale/page.tsx | 1 - src/components/LoadMoreButton.tsx | 8 +- src/components/inquiry/InquiryWriteForm.tsx | 7 +- src/components/inquiry/ListForm.tsx | 5 +- src/components/inquiry/ListTable.tsx | 101 +++++++++++------- src/components/popup/ZipCodePopup.tsx | 61 +++++++---- src/components/survey-sale/common/NavTab.tsx | 2 +- .../survey-sale/detail/DataTable.tsx | 21 +++- .../survey-sale/detail/DetailButton.tsx | 65 +++++++++++ .../survey-sale/detail/DetailForm.tsx | 86 ++------------- .../survey-sale/detail/RoofDetailForm.tsx | 26 +++++ .../survey-sale/detail/form/BasicForm.tsx | 21 +++- src/components/survey-sale/list/ListTable.tsx | 48 +++++---- src/hooks/useSurvey.ts | 21 +++- src/store/addressStore.ts | 19 ++++ src/store/inquiryFilterStore.ts | 41 +++++++ src/store/surveyFilterStore.ts | 32 +++--- 25 files changed, 398 insertions(+), 336 deletions(-) delete mode 100644 src/app/api/survey-sale/[id]/route.ts delete mode 100644 src/app/api/survey-sale/route.ts delete mode 100644 src/app/inquiry/write/page.tsx create mode 100644 src/components/survey-sale/detail/DetailButton.tsx create mode 100644 src/components/survey-sale/detail/RoofDetailForm.tsx create mode 100644 src/store/addressStore.ts create mode 100644 src/store/inquiryFilterStore.ts diff --git a/src/app/api/survey-sale/[id]/route.ts b/src/app/api/survey-sale/[id]/route.ts deleted file mode 100644 index bf5afe4..0000000 --- a/src/app/api/survey-sale/[id]/route.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { NextResponse } from 'next/server' - -export async function POST(request: Request, context: { params: { id: string } }) { - const body = await request.json() - const { id } = await context.params - - // @ts-ignore - const survey = await prisma.SD_SERVEY_SALES_BASIC_INFO.update({ - where: { id: Number(id) }, - data: { - detail_info: { - create: body, - }, - }, - }) - return NextResponse.json({ message: 'Survey detail created successfully' }) -} -export async function GET(request: Request, context: { params: { id: string } }) { - const { id } = await context.params - // @ts-ignore - const survey = await prisma.SD_SERVEY_SALES_BASIC_INFO.findUnique({ - where: { id: Number(id) }, - include: { - detail_info: true, - }, - }) - return NextResponse.json(survey) -} - -export async function PUT(request: Request, context: { params: { id: string } }) { - const { id } = await context.params - const body = await request.json() - // @ts-ignore - const survey = await prisma.SD_SERVEY_SALES_BASIC_INFO.update({ - where: { id: Number(id) }, - data: { - ...body, - detail_info: { - update: body.detail_info, - }, - }, - }) - return NextResponse.json(survey) -} - -export async function DELETE(request: Request, context: { params: { id: string; detail_id: string } }) { - const { id, detail_id } = await context.params - if (detail_id) { - // @ts-ignore - const survey = await prisma.SD_SERVEY_SALES_DETAIL_INFO.delete({ - where: { id: Number(detail_id) }, - }) - } else { - // @ts-ignore - const survey = await prisma.SD_SERVEY_SALES_BASIC_INFO.delete({ - where: { id: Number(id) }, - }) - } - return NextResponse.json({ message: 'Survey deleted successfully' }) -} - -export async function PATCH(request: Request, context: { params: { id: string } }) { - const { id } = await context.params - // @ts-ignore - const survey = await prisma.SD_SERVEY_SALES_BASIC_INFO.update({ - where: { id: Number(id) }, - data: { - submission_status: true, - }, - }) - return NextResponse.json({ message: 'Survey confirmed successfully' }) -} diff --git a/src/app/api/survey-sale/route.ts b/src/app/api/survey-sale/route.ts deleted file mode 100644 index 064c686..0000000 --- a/src/app/api/survey-sale/route.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { NextResponse } from 'next/server' -import { prisma } from '@/libs/prisma' - -export async function POST(request: Request) { - const body = await request.json() - // @ts-ignore - const res = await prisma.SD_SERVEY_SALES_BASIC_INFO.create({ - data: body, - }) - return NextResponse.json(res) -} - -export async function GET() { - try { - // @ts-ignore - const res = await prisma.SD_SERVEY_SALES_BASIC_INFO.findMany() - return NextResponse.json(res) - } catch (error) { - console.error(error) - } -} - -export async function PUT(request: Request) { - const body = await request.json() - console.log('🚀 ~ PUT ~ body:', body) - const detailInfo = { ...body.detail_info, basic_info_id: body.id } - console.log('🚀 ~ PUT ~ detailInfo:', detailInfo) - // @ts-ignore - const res = await prisma.SD_SERVEY_SALES_DETAIL_INFO.create({ - data: detailInfo, - }) - return NextResponse.json({ message: 'Survey sales updated successfully' }) -} diff --git a/src/app/api/survey-sales/[id]/route.ts b/src/app/api/survey-sales/[id]/route.ts index 025183d..5e4b83e 100644 --- a/src/app/api/survey-sales/[id]/route.ts +++ b/src/app/api/survey-sales/[id]/route.ts @@ -1,21 +1,5 @@ import { NextResponse } from 'next/server' -// export async function POST(request: Request, context: { params: { id: string } }) { -// const body = await request.json() -// const { id } = await context.params - -// // @ts-ignore -// const survey = await prisma.SD_SERVEY_SALES_BASIC_INFO.update({ -// where: { id: Number(id) }, -// data: { -// detail_info: { -// create: body, -// }, -// }, -// }) -// return NextResponse.json({ message: 'Survey detail created successfully' }) -// } - export async function GET(request: Request, context: { params: { id: string } }) { const { id } = await context.params // @ts-ignore diff --git a/src/app/api/survey-sales/route.ts b/src/app/api/survey-sales/route.ts index ee6dbe7..425c397 100644 --- a/src/app/api/survey-sales/route.ts +++ b/src/app/api/survey-sales/route.ts @@ -16,6 +16,7 @@ export async function GET(request: Request) { const searchOption = searchParams.get('searchOption') const isMySurvey = searchParams.get('isMySurvey') const sort = searchParams.get('sort') + const offset = searchParams.get('offset') const searchOptions = ['building_name', 'representative', 'store', 'construction_point', 'customer_name', 'post_code', 'address', 'address_detail'] try { @@ -27,7 +28,7 @@ export async function GET(request: Request) { if (keyword && keyword.trim() !== '' && searchOption) { if (searchOption === 'all') { - where.OR = []; + where.OR = [] if (keyword.match(/^\d+$/) || !isNaN(Number(keyword))) { where.OR.push({ id: { @@ -40,7 +41,7 @@ export async function GET(request: Request) { [field]: { contains: keyword, }, - })) + })), ) } else if (searchOptions.includes(searchOption)) { where[searchOption] = { @@ -53,12 +54,22 @@ export async function GET(request: Request) { } } - // @ts-ignore - const res = await prisma.SD_SERVEY_SALES_BASIC_INFO.findMany({ - where, - orderBy: sort === 'created' ? { created_at: 'desc' } : { updated_at: 'desc' }, - }) - return NextResponse.json(res) + if (offset) { + // @ts-ignore + const res = await prisma.SD_SERVEY_SALES_BASIC_INFO.findMany({ + where, + orderBy: sort === 'created' ? { created_at: 'desc' } : { updated_at: 'desc' }, + skip: Number(offset), + take: 10, + }) + return NextResponse.json(res) + } else { + // @ts-ignore + const count = await prisma.SD_SERVEY_SALES_BASIC_INFO.count({ + where, + }) + return NextResponse.json(count) + } } catch (error) { console.error(error) throw error diff --git a/src/app/api/user/route.ts b/src/app/api/user/route.ts index d3cda5f..e1562ac 100644 --- a/src/app/api/user/route.ts +++ b/src/app/api/user/route.ts @@ -2,7 +2,8 @@ import { NextResponse } from 'next/server' import { prisma } from '@/libs/prisma' import { getIronSession } from 'iron-session' import { cookies } from 'next/headers' -import { SessionData, sessionOptions } from '@/libs/session' +import { sessionOptions } from '@/libs/session' +import type { SessionData } from '@/types/Auth' export async function POST(request: Request) { const { username, password } = await request.json() @@ -25,8 +26,8 @@ export async function POST(request: Request) { const cookieStore = await cookies() const session = await getIronSession(cookieStore, sessionOptions) console.log('start session edit!') - session.username = user.username! - session.email = user.email! + session.userNm = user.username! + // session.email = user.email! session.isLoggedIn = true console.log('end session edit!') await session.save() diff --git a/src/app/inquiry/write/page.tsx b/src/app/inquiry/write/page.tsx deleted file mode 100644 index 2d1a122..0000000 --- a/src/app/inquiry/write/page.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import InquiryWriteForm from '@/components/inquiry/InquiryWriteForm' - -export default function InquiryWrite() { - return ( -
- -
- ) -} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 4b043a8..fd79f8c 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -22,7 +22,8 @@ interface RootLayoutProps { export default async function RootLayout({ children, header, footer, floatBtn }: RootLayoutProps): Promise { return ( - + {/* 일본어로 렌더링 */} +
{header} diff --git a/src/app/survey-sale/[id]/page.tsx b/src/app/survey-sale/[id]/page.tsx index 52202ca..cfc35d3 100644 --- a/src/app/survey-sale/[id]/page.tsx +++ b/src/app/survey-sale/[id]/page.tsx @@ -5,7 +5,7 @@ export default function page() { return ( <> - + {/* */} ) } diff --git a/src/app/survey-sale/page.tsx b/src/app/survey-sale/page.tsx index d2841f8..f7692b4 100644 --- a/src/app/survey-sale/page.tsx +++ b/src/app/survey-sale/page.tsx @@ -1,5 +1,4 @@ import ListTable from '@/components/survey-sale/list/ListTable' -import SearchForm from '@/components/survey-sale/list/SearchForm' export default function page() { return ( diff --git a/src/components/LoadMoreButton.tsx b/src/components/LoadMoreButton.tsx index 7c54f21..219b064 100644 --- a/src/components/LoadMoreButton.tsx +++ b/src/components/LoadMoreButton.tsx @@ -3,10 +3,9 @@ interface LoadMoreButtonProps { hasMore: boolean onLoadMore: () => void - onScrollToTop: () => void } -export default function LoadMoreButton({ hasMore, onLoadMore, onScrollToTop }: LoadMoreButtonProps) { +export default function LoadMoreButton({ hasMore, onLoadMore }: LoadMoreButtonProps) { return ( <> {hasMore ? ( @@ -15,10 +14,7 @@ export default function LoadMoreButton({ hasMore, onLoadMore, onScrollToTop }: L ) : ( - + <> )} ) diff --git a/src/components/inquiry/InquiryWriteForm.tsx b/src/components/inquiry/InquiryWriteForm.tsx index 047e4d0..868f3da 100644 --- a/src/components/inquiry/InquiryWriteForm.tsx +++ b/src/components/inquiry/InquiryWriteForm.tsx @@ -23,11 +23,6 @@ export default function InquiryWriteForm() { const file = Array.from(e.target.files || []) setFormData({ ...formData, file: [...formData.file, ...file] }) } - - const handleFileDelete = (fileToDelete: File) => { - setFormData({ ...formData, file: formData.file.filter((f) => f !== fileToDelete) }) - } - const handleSubmit = () => { console.log('submit: ', formData) // router.push(`/inquiry`) @@ -60,7 +55,7 @@ export default function InquiryWriteForm() {
{f.name}
- +
))} diff --git a/src/components/inquiry/ListForm.tsx b/src/components/inquiry/ListForm.tsx index 0b6ff3f..14f38bb 100644 --- a/src/components/inquiry/ListForm.tsx +++ b/src/components/inquiry/ListForm.tsx @@ -1,10 +1,13 @@ 'use client' +import { useRouter } from 'next/navigation' + export default function ListForm() { + const router = useRouter() return ( <>
-
diff --git a/src/components/inquiry/ListTable.tsx b/src/components/inquiry/ListTable.tsx index 4735ef1..a2ac091 100644 --- a/src/components/inquiry/ListTable.tsx +++ b/src/components/inquiry/ListTable.tsx @@ -1,5 +1,52 @@ 'use client' + +import { use, useEffect, useState } from 'react' +import LoadMoreButton from '../LoadMoreButton' + +const inquiryDummy = [ + { id: 1, category: '屋根', title: '屋根材適合性確認依頼', date: '2025.04.02', status: 'completed' }, + { id: 2, category: '外壁', title: '外壁仕上げ材確認', date: '2025.04.03', status: 'completed' }, + { id: 3, category: '設備', title: '換気システム図面確認', date: '2025.04.04', status: 'completed' }, + { id: 4, category: '基礎', title: '基礎配筋検査依頼', date: '2025.04.05', status: 'completed' }, + { id: 5, category: '内装', title: 'クロス仕様確認', date: '2025.04.06', status: 'waiting' }, + { id: 6, category: '構造', title: '耐震壁位置変更申請', date: '2025.04.07', status: 'completed' }, + { id: 7, category: '屋根', title: '雨樋取付方法確認', date: '2025.04.08', status: 'completed' }, + { id: 8, category: '外構', title: 'フェンス高さ変更相談', date: '2025.04.09', status: 'completed' }, + { id: 9, category: '設備', title: '給湯器設置位置確認', date: '2025.04.10', status: 'completed' }, + { id: 10, category: '外壁', title: 'タイル割付案確認依頼', date: '2025.04.11', status: 'waiting' }, + { id: 11, category: '内装', title: '照明配置図面確認', date: '2025.04.12', status: 'completed' }, + { id: 12, category: '構造', title: '梁補強案確認', date: '2025.04.13', status: 'completed' }, + { id: 13, category: '基礎', title: '杭長設計確認依頼', date: '2025.04.14', status: 'completed' }, + { id: 14, category: '屋根', title: '断熱材施工方法確認', date: '2025.04.15', status: 'completed' }, + { id: 15, category: '外構', title: '駐車場勾配図確認', date: '2025.04.16', status: 'completed' }, +] + +const badgeStyle = [ + { + id: 'completed', + label: '回答完了', + color: 'blue', + }, + { + id: 'waiting', + label: '回答待ち', + color: 'orange', + }, +] export default function ListTable() { + const [offset, setOffset] = useState(0) + const [hasMore, setHasMore] = useState(true) + + const inquiryList = inquiryDummy.slice(0, offset + 10) + + useEffect(() => { + if (inquiryDummy.length > offset + 10) { + setHasMore(true) + } else { + setHasMore(false) + } + }, [inquiryList]) + return ( <>
@@ -13,10 +60,8 @@ export default function ListTable() {
@@ -25,43 +70,21 @@ export default function ListTable() { 合計 98
    -
  • -
    -
    屋根
    -
    屋根材適合性確認依頼
    -
    2025.04.02
    -
    回答待ち
    -
    -
  • -
  • -
    -
    設計
    -
    設置可能ですか?
    -
    2025.04.02
    -
    回答完了
    -
    -
  • -
  • -
    -
    屋根
    -
    屋根材適合性確認依頼屋根材適合性確認依頼屋根材適合性確認依頼屋根材適合性確認依頼
    -
    2025.04.02
    -
    回答待ち
    -
    -
  • -
  • -
    -
    設計
    -
    設置可能ですか?
    -
    2025.04.02
    -
    回答完了
    -
    -
  • + {inquiryList.map((inquiry) => ( +
  • +
    +
    {inquiry.category}
    +
    {inquiry.title}
    +
    {inquiry.date}
    +
    badge.id === inquiry.status)?.color}`}> + {badgeStyle.find((badge) => badge.id === inquiry.status)?.label} +
    +
    +
  • + ))}
- + setOffset(offset + 10)} />
diff --git a/src/components/popup/ZipCodePopup.tsx b/src/components/popup/ZipCodePopup.tsx index 45dd486..bc7265f 100644 --- a/src/components/popup/ZipCodePopup.tsx +++ b/src/components/popup/ZipCodePopup.tsx @@ -1,18 +1,51 @@ 'use client' +import { useAddressStore } from '@/store/addressStore' import { usePopupController } from '@/store/popupController' import { useState } from 'react' +const dummyData = [ + { + post_code: '123-567', + pref: '東京都', + city: '千代田区', + detail: '永田町ハイツ101号室', + }, + { + post_code: '987-654', + pref: '大阪府', + city: '北区', + detail: '梅田スカイビル23階', + }, + { + post_code: '456-789', + pref: '福岡県', + city: '博多区', + detail: '中洲マンション305号', + }, +] + export default function ZipCodePopup() { const [searchValue, setSearchValue] = useState('') //search 데이터 유무 + const [selected, setSelected] = useState('') + + const { setAddressData } = useAddressStore() //search 데이터 value 추가 const handleChange = (e: React.ChangeEvent) => { setSearchValue(e.target.value) } - const popupController = usePopupController() + const handleApply = () => { + const addressData = dummyData.find((item) => item.post_code === selected) + setAddressData({ + post_code: addressData?.post_code || '', + address: addressData?.pref || '', + address_detail: addressData?.city + ' ' + addressData?.detail || '', + }) + popupController.setZipCodePopup(false) + } return ( <>
@@ -50,31 +83,23 @@ export default function ZipCodePopup() { - - 東京都 - 浜松 - 浜松町 - - - 東京都 - 浜松 - 浜松町 - - - 東京都 - 浜松 - 浜松町 - + {dummyData.map((item, index) => ( + setSelected(item.post_code)}> + {item.pref} + {item.city} + {item.detail} + + ))}
-
-
diff --git a/src/components/survey-sale/common/NavTab.tsx b/src/components/survey-sale/common/NavTab.tsx index 290473c..d556e00 100644 --- a/src/components/survey-sale/common/NavTab.tsx +++ b/src/components/survey-sale/common/NavTab.tsx @@ -33,7 +33,7 @@ export default function NavTab() { return } if (detailId) { - router.push(`/survey-sale/${detailId}?tab=basic-info`) + router.push(`/survey-sale/${detailId}`) return } } diff --git a/src/components/survey-sale/detail/DataTable.tsx b/src/components/survey-sale/detail/DataTable.tsx index 978c321..f4ae0b8 100644 --- a/src/components/survey-sale/detail/DataTable.tsx +++ b/src/components/survey-sale/detail/DataTable.tsx @@ -1,22 +1,34 @@ 'use client' import { useServey } from '@/hooks/useSurvey' -import { useParams } from 'next/navigation' +import { useParams, useSearchParams } from 'next/navigation' import { useEffect } from 'react' import { useState } from 'react' +import DetailForm from './DetailForm' +import { useSurveySaleTabState } from '@/store/surveySaleTabState' +import RoofDetailForm from './RoofDetailForm' export default function DataTable() { const params = useParams() const id = params.id + const searchParams = useSearchParams() + const tab = searchParams.get('tab') + const { surveyDetail, isLoadingSurveyDetail } = useServey(Number(id)) const [isTemporary, setIsTemporary] = useState(false) + const { setBasicInfoSelected, setRoofInfoSelected } = useSurveySaleTabState() useEffect(() => { if (!surveyDetail?.representative || !surveyDetail?.store || !surveyDetail?.construction_point) { setIsTemporary(true) } - }, [surveyDetail]) + if (tab === 'roof-info') { + setRoofInfoSelected() + } else { + setBasicInfoSelected() + } + }, [surveyDetail, tab, setBasicInfoSelected, setRoofInfoSelected]) if (isLoadingSurveyDetail) { return
Loading...
@@ -73,6 +85,11 @@ export default function DataTable() {
+ {tab === 'roof-info' ? ( + + ) : ( + + )} ) } diff --git a/src/components/survey-sale/detail/DetailButton.tsx b/src/components/survey-sale/detail/DetailButton.tsx new file mode 100644 index 0000000..94f34c5 --- /dev/null +++ b/src/components/survey-sale/detail/DetailButton.tsx @@ -0,0 +1,65 @@ +'use client' +import { useRouter } from 'next/navigation' +import { useServey } from '@/hooks/useSurvey' + +export default function DetailButton({ isTemporary, surveyId }: { isTemporary: boolean, surveyId: number }) { + const router = useRouter() + + const { submitSurvey, deleteSurvey } = useServey(surveyId) + + const handleSubmit = async () => { + if (isTemporary) { + alert('SAVE FIRST') + return + } + if (confirm('submit?')) { + if (surveyId) { + // TODO: 제출 페이지 추가 + alert('SUBMIT POPUP') + await submitSurvey() + } + } + } + const handleUpdate = () => { + router.push(`/survey-sale/basic-info?id=${surveyId}`) + } + const handleDelete = async () => { + if (confirm('delete?')) { + if (surveyId) { + await deleteSurvey() + router.push('/survey-sale') + } + } + } + + return ( +
+ {isTemporary ? ( + <> + ) : ( + <> +
+ +
+
+ +
+ + )} +
+ +
+
+ +
+
+ ) +} diff --git a/src/components/survey-sale/detail/DetailForm.tsx b/src/components/survey-sale/detail/DetailForm.tsx index f07b1d5..e734048 100644 --- a/src/components/survey-sale/detail/DetailForm.tsx +++ b/src/components/survey-sale/detail/DetailForm.tsx @@ -1,64 +1,27 @@ 'use client' -import { useServey } from '@/hooks/useSurvey' -import { useSurveySaleTabState } from '@/store/surveySaleTabState' import { useEffect, useState } from 'react' -import { useParams, useRouter, useSearchParams } from 'next/navigation' +import DetailButton from './DetailButton' +import { SurveyBasicInfo } from '@/types/Survey' -export default function DetailForm() { - const router = useRouter() - const params = useParams() - const id = params.id - - const searchParams = useSearchParams() - const tab = searchParams.get('tab') - - const { surveyDetail, deleteSurvey, submitSurvey, isLoadingSurveyDetail } = useServey(Number(id)) - const { setBasicInfoSelected, setRoofInfoSelected } = useSurveySaleTabState() +export default function DetailForm({ + surveyDetail, + isLoadingSurveyDetail, +}: { + surveyDetail: SurveyBasicInfo | null + isLoadingSurveyDetail: boolean +}) { const [isTemporary, setIsTemporary] = useState(true) - // TODO: 조사매물 지붕정보 퍼블 구현되면 탭 화면 변경 추가 useEffect(() => { - if (tab === 'basic-info') { - setBasicInfoSelected() - } - if (tab === 'roof-info') { - setRoofInfoSelected() - } if (surveyDetail?.representative && surveyDetail?.store && surveyDetail?.construction_point) { setIsTemporary(false) } - }, [tab, setBasicInfoSelected, setRoofInfoSelected, surveyDetail]) + }, [surveyDetail]) if (isLoadingSurveyDetail) { return
Loading...
} - - const handleSubmit = async () => { - if (isTemporary) { - alert('SAVE FIRST') - return - } - if (confirm('submit?')) { - if (surveyDetail?.id) { - // TODO: 제출 페이지 추가 - alert('SUBMIT POPUP') - await submitSurvey() - } - } - } - const handleUpdate = () => { - router.push(`/survey-sale/basic-info?id=${id}`) - } - const handleDelete = async () => { - if (confirm('delete?')) { - if (surveyDetail?.id) { - await deleteSurvey() - router.push('/survey-sale') - } - } - } - return ( <>
@@ -93,34 +56,7 @@ export default function DetailForm() {
-
- {isTemporary ? ( - <> - ) : ( - <> -
- -
-
- -
- - )} -
- -
-
- -
-
+ ) diff --git a/src/components/survey-sale/detail/RoofDetailForm.tsx b/src/components/survey-sale/detail/RoofDetailForm.tsx new file mode 100644 index 0000000..e88c938 --- /dev/null +++ b/src/components/survey-sale/detail/RoofDetailForm.tsx @@ -0,0 +1,26 @@ +import { SurveyBasicInfo } from '@/types/Survey' +import DetailButton from './DetailButton' + +export default function RoofDetailForm({ + surveyDetail, + isLoadingSurveyDetail, +}: { + surveyDetail: SurveyBasicInfo | null + isLoadingSurveyDetail: boolean +}) { + if (isLoadingSurveyDetail) { + return
Loading...
+ } + return ( + <> +
+
+
+
屋根材
+
+
+ +
+ + ) +} diff --git a/src/components/survey-sale/detail/form/BasicForm.tsx b/src/components/survey-sale/detail/form/BasicForm.tsx index 971775f..e062b65 100644 --- a/src/components/survey-sale/detail/form/BasicForm.tsx +++ b/src/components/survey-sale/detail/form/BasicForm.tsx @@ -5,6 +5,8 @@ import { SurveyBasicRequest } from '@/types/Survey' import { useRouter, useSearchParams } from 'next/navigation' import { useState, useEffect } from 'react' import { useSurveySaleTabState } from '@/store/surveySaleTabState' +import { usePopupController } from '@/store/popupController' +import { useAddressStore } from '@/store/addressStore' const defaultBasicInfoForm: SurveyBasicRequest = { representative: '', @@ -32,16 +34,25 @@ export default function BasicForm() { const [basicInfoData, setBasicInfoData] = useState(defaultBasicInfoForm) + const { addressData } = useAddressStore() + + const popupController = usePopupController() + useEffect(() => { if (surveyDetail) { const { id, updated_at, created_at, detail_info, ...rest } = surveyDetail setBasicInfoData(rest) } - }, [surveyDetail]) - - useEffect(() => { + if (addressData) { + setBasicInfoData({ + ...basicInfoData, + post_code: addressData.post_code, + address: addressData.address, + address_detail: addressData.address_detail, + }) + } setBasicInfoSelected() - }, []) + }, [surveyDetail, addressData]) const focusInput = (input: keyof SurveyBasicRequest) => { const inputElement = document.getElementById(input) @@ -192,7 +203,7 @@ export default function BasicForm() {
-
diff --git a/src/components/survey-sale/list/ListTable.tsx b/src/components/survey-sale/list/ListTable.tsx index d0f599c..89bdb09 100644 --- a/src/components/survey-sale/list/ListTable.tsx +++ b/src/components/survey-sale/list/ListTable.tsx @@ -2,46 +2,50 @@ import LoadMoreButton from '@/components/LoadMoreButton' import { useServey } from '@/hooks/useSurvey' -import { useEffect, useState } from 'react' +import { useEffect, useState, useRef } from 'react' import { useRouter } from 'next/navigation' import SearchForm from './SearchForm' +import { useSurveyFilterStore } from '@/store/surveyFilterStore' export default function ListTable() { const router = useRouter() - const { surveyList, isLoadingSurveyList } = useServey() + const { surveyList, isLoadingSurveyList, surveyListCount } = useServey() + const { offset, setOffset } = useSurveyFilterStore() - const [visibleItems, setVisibleItems] = useState(10) + const [heldSurveyList, setHeldSurveyList] = useState([]) const [hasMore, setHasMore] = useState(false) useEffect(() => { - setHasMore(surveyList.length > visibleItems) - }, [surveyList, visibleItems]) - - const handleLoadMore = () => { - const newVisibleItems = Math.min(visibleItems + 10, surveyList.length) - setVisibleItems(newVisibleItems) - setHasMore(newVisibleItems < surveyList.length) - } - - const handleScrollToTop = () => { - window.scrollTo({ top: 0, behavior: 'smooth' }) - } + if (surveyList && surveyList.length > 0) { + if (offset === 0) { + setHeldSurveyList(surveyList) + } else { + const remainingList = heldSurveyList.slice(offset, offset + 10) + if (JSON.stringify(remainingList) !== JSON.stringify(surveyList)) { + setHeldSurveyList((prev) => [...prev, ...surveyList]) + } + } + setHasMore(surveyListCount > offset + 10) + } + }, [surveyList, surveyListCount, offset]) const handleDetailClick = (id: number) => { router.push(`/survey-sale/${id}`) } - - if (isLoadingSurveyList) { - return
Loading...
+ const handleItemsInit = () => { + setHeldSurveyList([]) + setOffset(0) } + // TODO: 로딩 처리 필요 + return ( <> - setVisibleItems(10)} /> - {surveyList.length > 0 ? ( + + {heldSurveyList.length > 0 ? (
    - {surveyList.slice(0, visibleItems).map((survey) => ( + {heldSurveyList.map((survey) => (
  • handleDetailClick(survey.id)}>
    @@ -59,7 +63,7 @@ export default function ListTable() { ))}
- + setOffset(offset + 10)} />
) : ( diff --git a/src/hooks/useSurvey.ts b/src/hooks/useSurvey.ts index f4d08a7..8bc0963 100644 --- a/src/hooks/useSurvey.ts +++ b/src/hooks/useSurvey.ts @@ -6,6 +6,7 @@ import { useSurveyFilterStore } from '@/store/surveyFilterStore' export function useServey(id?: number): { surveyList: SurveyBasicInfo[] | [] surveyDetail: SurveyBasicInfo | null + surveyListCount: number isLoadingSurveyList: boolean isLoadingSurveyDetail: boolean isCreatingSurvey: boolean @@ -19,14 +20,13 @@ export function useServey(id?: number): { validateSurveyDetail: (surveyDetail: SurveyDetailRequest) => string } { const queryClient = useQueryClient() - const { keyword, searchOption, isMySurvey, sort } = useSurveyFilterStore() + const { keyword, searchOption, isMySurvey, sort, offset } = useSurveyFilterStore() const { data: surveyList, isLoading: isLoadingSurveyList } = useQuery({ - queryKey: ['survey', 'list', keyword, searchOption, isMySurvey, sort], + queryKey: ['survey', 'list', keyword, searchOption, isMySurvey, sort, offset], queryFn: async () => { - console.log('keyword, searchOption, isMySurvey, sort:: ', keyword, searchOption, isMySurvey, sort) const resp = await axiosInstance(null).get('/api/survey-sales', { - params: { keyword, searchOption, isMySurvey, sort }, + params: { keyword, searchOption, isMySurvey, sort, offset }, }) return resp.data }, @@ -43,6 +43,16 @@ export function useServey(id?: number): { enabled: id !== undefined, }) + const { data: surveyListCount } = useQuery({ + queryKey: ['survey', 'list', keyword, searchOption, isMySurvey, sort], + queryFn: async () => { + const resp = await axiosInstance(null).get('/api/survey-sales', { + params: { keyword, searchOption, isMySurvey, sort }, + }) + return resp.data + }, + }) + const { mutateAsync: createSurvey, isPending: isCreatingSurvey } = useMutation({ mutationFn: async (survey: SurveyBasicRequest) => { const resp = await axiosInstance(null).post('/api/survey-sales', survey) @@ -80,7 +90,7 @@ export function useServey(id?: number): { }, }) - const { mutateAsync: createSurveyDetail, isPending: isCreatingSurveyDetail } = useMutation({ + const { mutateAsync: createSurveyDetail } = useMutation({ mutationFn: async ({ surveyId, surveyDetail }: { surveyId: number; surveyDetail: SurveyDetailCoverRequest }) => { const resp = await axiosInstance(null).patch(`/api/survey-sales/${surveyId}`, surveyDetail) return resp.data @@ -137,6 +147,7 @@ export function useServey(id?: number): { return { surveyList: surveyList || [], surveyDetail: surveyDetail || null, + surveyListCount: surveyListCount || 0, isLoadingSurveyList, isLoadingSurveyDetail, isCreatingSurvey, diff --git a/src/store/addressStore.ts b/src/store/addressStore.ts new file mode 100644 index 0000000..2e40890 --- /dev/null +++ b/src/store/addressStore.ts @@ -0,0 +1,19 @@ +import { create } from 'zustand' + +type AddressData = { + post_code: string + address: string + address_detail: string +} + +interface AddressState { + addressData: AddressData | null + setAddressData: (address: AddressData) => void + resetAddressData: () => void +} + +export const useAddressStore = create((set) => ({ + addressData: null, + setAddressData: (address) => set({ addressData: address }), + resetAddressData: () => set({ addressData: null }), +})) diff --git a/src/store/inquiryFilterStore.ts b/src/store/inquiryFilterStore.ts new file mode 100644 index 0000000..0960c85 --- /dev/null +++ b/src/store/inquiryFilterStore.ts @@ -0,0 +1,41 @@ +import { create } from 'zustand' + +export const FILTER_OPTIONS = [ + { + id: 'all', + label: '全体', + }, + { + id: 'completed', + label: '回答完了', + }, + { + id: 'waiting', + label: '回答待ち', + }, +] +export type FILTER_OPTIONS_ENUM = (typeof FILTER_OPTIONS)[number]['id'] + +type InquiryFilterState = { + keyword: string + filter: FILTER_OPTIONS_ENUM + isMySurvey: string | null + offset: number + setKeyword: (keyword: string) => void + setFilter: (filter: FILTER_OPTIONS_ENUM) => void + setIsMySurvey: (isMySurvey: string | null) => void + setOffset: (offset: number) => void + reset: () => void +} + +export const useInquiryFilterStore = create((set) => ({ + keyword: '', + filter: 'all', + isMySurvey: null, + offset: 0, + setKeyword: (keyword) => set({ keyword }), + setFilter: (filter) => set({ filter }), + setIsMySurvey: (isMySurvey) => set({ isMySurvey }), + setOffset: (offset) => set({ offset }), + reset: () => set({ keyword: '', filter: 'all', isMySurvey: null, offset: 0 }), +})) diff --git a/src/store/surveyFilterStore.ts b/src/store/surveyFilterStore.ts index c5f0e07..56414c7 100644 --- a/src/store/surveyFilterStore.ts +++ b/src/store/surveyFilterStore.ts @@ -1,10 +1,10 @@ import { create } from 'zustand' -export type SEARCH_OPTIONS_ENUM = 'all' | 'id' | 'building_name' | 'representative' | 'store' | 'construction_point' +// export type SEARCH_OPTIONS_ENUM = 'all' | 'id' | 'building_name' | 'representative' | 'store' | 'construction_point' // | 'store_id' | 'construction_id' -export type SEARCH_OPTIONS_PARTNERS_ENUM = 'all' | 'id' | 'building_name' | 'representative' +// export type SEARCH_OPTIONS_PARTNERS_ENUM = 'all' | 'id' | 'building_name' | 'representative' -export type SORT_OPTIONS_ENUM = 'created' | 'updated' +// export type SORT_OPTIONS_ENUM = 'created' | 'updated' export const SEARCH_OPTIONS = [ { @@ -27,18 +27,18 @@ export const SEARCH_OPTIONS = [ id: 'store', label: '販売店名', }, -// { -// id: 'store_id', -// label: '販売店ID', -// }, + // { + // id: 'store_id', + // label: '販売店ID', + // }, { id: 'construction_point', label: '施工店名', }, -// { -// id: 'construction_id', -// label: '施工店ID', -// }, + // { + // id: 'construction_id', + // label: '施工店ID', + // }, ] export const SEARCH_OPTIONS_PARTNERS = [ @@ -60,15 +60,21 @@ export const SEARCH_OPTIONS_PARTNERS = [ }, ] +export type SEARCH_OPTIONS_ENUM = (typeof SEARCH_OPTIONS)[number]['id'] +export type SEARCH_OPTIONS_PARTNERS_ENUM = (typeof SEARCH_OPTIONS_PARTNERS)[number]['id'] +export type SORT_OPTIONS_ENUM = 'created' | 'updated' + type SurveyFilterState = { keyword: string searchOption: SEARCH_OPTIONS_ENUM | SEARCH_OPTIONS_PARTNERS_ENUM isMySurvey: string | null sort: SORT_OPTIONS_ENUM + offset: number setKeyword: (keyword: string) => void setSearchOption: (searchOption: SEARCH_OPTIONS_ENUM | SEARCH_OPTIONS_PARTNERS_ENUM) => void setIsMySurvey: (isMySurvey: string | null) => void setSort: (sort: SORT_OPTIONS_ENUM) => void + setOffset: (offset: number) => void reset: () => void } @@ -77,9 +83,11 @@ export const useSurveyFilterStore = create((set) => ({ searchOption: 'all', isMySurvey: null, sort: 'created', + offset: 0, setKeyword: (keyword: string) => set({ keyword }), setSearchOption: (searchOption: SEARCH_OPTIONS_ENUM | SEARCH_OPTIONS_PARTNERS_ENUM) => set({ searchOption }), setIsMySurvey: (isMySurvey: string | null) => set({ isMySurvey }), setSort: (sort: SORT_OPTIONS_ENUM) => set({ sort }), - reset: () => set({ keyword: '', searchOption: 'all', isMySurvey: null, sort: 'created' }), + setOffset: (offset: number) => set({ offset }), + reset: () => set({ keyword: '', searchOption: 'all', isMySurvey: null, sort: 'created', offset: 0 }), }))