diff --git a/next.config.ts b/next.config.ts index 8304bcd..1ff5ba6 100644 --- a/next.config.ts +++ b/next.config.ts @@ -7,31 +7,10 @@ const nextConfig: NextConfig = { includePaths: [path.join(__dirname, './src/styles')], }, async rewrites() { - return [ - { - source: '/:path*', - destination: `${process.env.NEXT_PUBLIC_API_URL}/:path*`, - }, - ] - }, - async headers() { return [ { source: '/api/:path*', - headers: [ - { - key: 'Access-Control-Allow-Origin', - value: '*', - }, - { - key: 'Access-Control-Allow-Methods', - value: 'GET, POST, PUT, DELETE, OPTIONS', - }, - { - key: 'Access-Control-Allow-Headers', - value: 'Content-Type, Authorization', - }, - ], + destination: `${process.env.NEXT_PUBLIC_API_URL}/api/:path*`, }, ] }, diff --git a/src/api/suitable.ts b/src/api/suitable.ts index e8458c4..277bc7e 100644 --- a/src/api/suitable.ts +++ b/src/api/suitable.ts @@ -38,14 +38,31 @@ export interface Suitable { } export const suitableApi = { - getList: async (): Promise => { - const response = await axiosInstance.get('/api/suitable/list') + getList: async (category?: string, keyword?: string): Promise => { + let condition: any = {} + if (category) { + condition['category'] = category + } + if (keyword) { + condition['keyword'] = { + contains: keyword, + } + } + console.log('๐Ÿš€ ~ getList: ~ condition:', condition) + const response = await axiosInstance.get('/api/suitable/list', { params: condition }) console.log('๐Ÿš€ ~ getList: ~ response:', response) return response.data }, + getCategory: async (): Promise => { + const response = await axiosInstance.get('/api/suitable/category') + console.log('๐Ÿš€ ~ getCategory: ~ response:', response) + return response.data + }, + getDetails: async (roofMaterial: string): Promise => { const response = await axiosInstance.get(`/api/suitable/details?roof-material=${roofMaterial}`) + console.log('๐Ÿš€ ~ getDetails: ~ response:', response) return response.data }, diff --git a/src/api/surveySales.ts b/src/api/surveySales.ts index 4ecff63..57314da 100644 --- a/src/api/surveySales.ts +++ b/src/api/surveySales.ts @@ -120,4 +120,8 @@ export const surveySalesApi = { throw error } }, + update: async (data: SurveySalesBasicInfo): Promise => { + const response = await axiosInstance.put(`/api/survey-sales`, data) + return response.data + }, } diff --git a/src/app/api/suitable/category/route.ts b/src/app/api/suitable/category/route.ts new file mode 100644 index 0000000..288a74a --- /dev/null +++ b/src/app/api/suitable/category/route.ts @@ -0,0 +1,16 @@ +import { NextResponse } from 'next/server' +import { prisma } from '@/libs/prisma' + +export async function GET() { + // @ts-ignore + const roofMaterialCategory = await prisma.MS_SUITABLE.findMany({ + select: { + roof_material: true, + }, + distinct: ['roof_material'], + orderBy: { + roof_material: 'asc', + }, + }) + return NextResponse.json(roofMaterialCategory) +} diff --git a/src/app/api/suitable/details/route.ts b/src/app/api/suitable/details/route.ts index 2645411..d29f666 100644 --- a/src/app/api/suitable/details/route.ts +++ b/src/app/api/suitable/details/route.ts @@ -1,4 +1,5 @@ import { NextResponse } from 'next/server' +import { prisma } from '@/libs/prisma' export async function GET(request: Request) { const { searchParams } = new URL(request.url) diff --git a/src/app/api/suitable/list/route.ts b/src/app/api/suitable/list/route.ts index e1a44cb..22c3d8a 100644 --- a/src/app/api/suitable/list/route.ts +++ b/src/app/api/suitable/list/route.ts @@ -1,8 +1,35 @@ -import { NextResponse } from 'next/server' +import { NextRequest, NextResponse } from 'next/server' import { prisma } from '@/libs/prisma' -export async function GET() { - // @ts-ignore - const suitables = await prisma.MS_SUITABLE.findMany() - return NextResponse.json(suitables) + +export async function GET(request: NextRequest) { + try { + const searchParams = request.nextUrl.searchParams + const category = searchParams.get('category') + const keyword = searchParams.get('keyword') + + let whereCondition: any = {} + if (category) { + whereCondition['roof_material'] = category + } + if (keyword) { + whereCondition['product_name'] = { + contains: keyword, + } + } + console.log('๐Ÿš€ ~ /api/suitable/list: ~ prisma where condition:', whereCondition) + + // @ts-ignore + const suitables = await prisma.MS_SUITABLE.findMany({ + where: whereCondition, + orderBy: { + product_name: 'asc', + }, + }) + + return NextResponse.json(suitables) + } catch (error) { + console.error('โŒ ๋ฐ์ดํ„ฐ ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค:', error) + return NextResponse.json({ error: '๋ฐ์ดํ„ฐ ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค' }, { status: 500 }) + } } diff --git a/src/app/api/survey-sales/route.ts b/src/app/api/survey-sales/route.ts index aebff14..b460751 100644 --- a/src/app/api/survey-sales/route.ts +++ b/src/app/api/survey-sales/route.ts @@ -19,3 +19,25 @@ export async function GET() { console.error(error) } } + +export async function GET(request: Request) { + // @ts-ignore + const res = await prisma.SD_SERVEY_SALES_BASIC_INFO.findMany({ + include: { + detail_info: true, + }, + }) + return NextResponse.json(res) +} + +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/suitable/[slug]/page.tsx b/src/app/suitable/[slug]/page.tsx index 6a4f8a0..6c1959a 100644 --- a/src/app/suitable/[slug]/page.tsx +++ b/src/app/suitable/[slug]/page.tsx @@ -2,6 +2,7 @@ import SuitableDetails from '@/components/SuitableDetails' export default async function page({ params }: { params: Promise<{ slug: string }> }) { const { slug } = await params + console.log('๐Ÿš€ ~ page ~ slug:', slug) return ( <>

Suitable Details

diff --git a/src/components/Suitable.tsx b/src/components/Suitable.tsx index f5766f1..e21b4d4 100644 --- a/src/components/Suitable.tsx +++ b/src/components/Suitable.tsx @@ -1,16 +1,33 @@ 'use client' -import { suitableApi } from '@/api/suitable' -import { useQuery } from '@tanstack/react-query' +import { useSuitableStore } from '@/store/useSuitableStore' +import { useQuery, useQueryClient } from '@tanstack/react-query' import { useRouter } from 'next/navigation' +import type { Suitable as SuitableType } from '@/api/suitable' export default function Suitable() { const router = useRouter() - const { data, error, isPending } = useQuery({ - queryKey: ['suitable-list'], - queryFn: suitableApi.getList, + const queryClient = useQueryClient() + const { selectedItems, addSelectedItem, removeSelectedItem } = useSuitableStore() + + const handleItemClick = (item: SuitableType) => { + if (!item.id) return // ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ import ๋•Œ๋ฌธ์— Suitable.id๊ฐ€ optional ํƒ€์ž…์ด๋ผ์„œ ๋ฐฉ์–ด ์ฒ˜๋ฆฌ ์ถ”๊ฐ€ + selectedItems.some((selected) => selected.id === item.id) ? removeSelectedItem(item.id) : addSelectedItem(item) + } + + const { data: suitableList, isLoading } = useQuery({ + queryKey: ['suitables', 'search'], + queryFn: async () => { + const data = queryClient.getQueryData(['suitables', 'search']) as SuitableType[] + return data ?? [] + }, + enabled: false, }) + if (isLoading || !suitableList || suitableList.length === 0) { + return
Loading...
+ } + return ( <>

Suitable

@@ -22,9 +39,31 @@ export default function Suitable() { > HOME - {error &&
Error: {error.message}
} - {isPending &&
Loading...
} - {data && data.map((item) =>
{item.product_name}
)} +
+

์„ ํƒ๋œ ์•„์ดํ…œ

+ {selectedItems.length > 0 ? ( + selectedItems.map((item) => ( +
handleItemClick(item)}> + {item.product_name} +
+ )) + ) : ( +
์„ ํƒ๋œ ์•„์ดํ…œ์ด ์—†์Šต๋‹ˆ๋‹ค.
+ )} +
+
+
+

๋ฐ์ดํ„ฐ ๋ชฉ๋ก

+ {suitableList ? ( + suitableList.map((item: SuitableType) => ( +
handleItemClick(item)}> + {item.product_name} +
+ )) + ) : ( +
๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
+ )} +
) } diff --git a/src/components/SuitableDetails.tsx b/src/components/SuitableDetails.tsx index 3d698d7..748c28f 100644 --- a/src/components/SuitableDetails.tsx +++ b/src/components/SuitableDetails.tsx @@ -2,19 +2,70 @@ import { suitableApi } from '@/api/suitable' import { useQuery } from '@tanstack/react-query' +import generatePDF, { usePDF, Options } from 'react-to-pdf' +import PDFContent from './SuitablePdf' + +const pdfOptions: Options = { + filename: 'page.pdf', + method: 'save', + page: { format: 'a4', margin: 10 }, + overrides: { + pdf: { + compress: true, + }, + }, +} export default function SuitableDetails({ roofMaterial }: { roofMaterial: string }) { - console.log('๐Ÿš€ ~ SuitableDetails ~ roofMaterial:', roofMaterial) - const { data, error, isPending } = useQuery({ + const { data, isLoading } = useQuery({ queryKey: ['suitable-details'], queryFn: () => suitableApi.getDetails(roofMaterial), staleTime: 0, + enabled: !!roofMaterial, }) + const { toPDF, targetRef } = usePDF({ ...pdfOptions, method: 'open' }) + + if (isLoading) { + return
Loading...
+ } + return ( <> -

Searched Roof Material: {roofMaterial}

- {data && data.map((item) =>
{item.product_name}
)} + + + {/* */} + {/*
*/} +
+

Searched Roof Material: {decodeURIComponent(roofMaterial as string)}

+ {data && + data.map((item) => ( +
+
+
product_name: {item.product_name}
+
manufacturer: {item.manufacturer}
+
roof_material: {item.roof_material}
+
shape: {item.shape}
+
support_roof_tile: {item.support_roof_tile}
+
support_roof_bracket: {item.support_roof_bracket}
+
yg_anchor: {item.yg_anchor}
+
+ ))} +
+ {/*
*/} +
+
+

PDF ๋‚ด์šฉ ๋‚˜์™€๋ผ

+ +
+
) } diff --git a/src/components/SuitablePdf.tsx b/src/components/SuitablePdf.tsx new file mode 100644 index 0000000..f059744 --- /dev/null +++ b/src/components/SuitablePdf.tsx @@ -0,0 +1,116 @@ +import { Suitable } from '@/api/suitable' + +interface StatusInfo { + statusIcon: string + statusText: string +} + +interface FittingItem { + name: string + value: string + memo: string +} + +function getStatusInfo(value: string): StatusInfo | null { + const val = value?.trim()?.replace(/ใƒผ|๏ผ/g, '-') || '' + + if (['โ—‹', 'ใ€‡'].includes(val)) { + return { + statusIcon: 'โœ…', + statusText: '่จญ็ฝฎๅฏ', + } + } + + if (['ร—', 'โœ•'].includes(val)) { + return { + statusIcon: 'โŒ', + statusText: '่จญ็ฝฎไธๅฏ', + } + } + + if (['-', '๏ผ', 'ใƒผ'].includes(val)) { + return { + statusIcon: 'โ“', + statusText: 'ใŠๅ•ใ„ๅˆใ‚ใ›ใใ ใ•ใ„', + } + } + + if (val === '') return null + + return { + statusIcon: 'โœ…', + statusText: `${val} ใง่จญ็ฝฎๅฏ`, + } +} + +function getFittingItems(item: Suitable): FittingItem[] { + return [ + { name: 'ๅฑ‹ๆ น็“ฆ็”จๆ”ฏๆŒ้‡‘ๅ…ท', value: item.support_roof_tile, memo: item.support_roof_tile_memo }, + { name: 'ๅฑ‹ๆ นใƒ–ใƒฉใ‚ฑใƒƒใƒˆ็”จๆ”ฏๆŒ้‡‘ๅ…ท', value: item.support_roof_bracket, memo: item.support_roof_bracket_memo }, + { name: 'YGใ‚ขใƒณใ‚ซใƒผ', value: item.yg_anchor, memo: item.yg_anchor_memo }, + { name: 'RGๅฑ‹ๆ น็“ฆใƒ‘ใƒผใƒ„', value: item.rg_roof_tile_part, memo: item.rg_roof_tile_part_memo }, + { name: 'DIDOใƒใƒณใƒˆๆ”ฏๆŒ็“ฆ2', value: item.dido_hunt_support_tile_2, memo: item.dido_hunt_support_tile_2_memo }, + { name: '้ซ˜ๅณถใƒ‘ใƒฏใƒผใƒ™ใƒผใ‚น', value: item.takashima_power_base, memo: item.takashima_power_base_memo }, + { name: '้ซ˜ๅณถ็“ฆใƒ–ใƒฉใ‚ฑใƒƒใƒˆ', value: item.takashima_tile_bracket, memo: item.takashima_tile_bracket_memo }, + { name: 'ใ‚นใƒฌใƒผใƒˆใƒ–ใƒฉใ‚ฑใƒƒใƒˆ4', value: item.slate_bracket_4, memo: item.slate_bracket_4_memo }, + { name: 'ใ‚นใƒฌใƒผใƒˆใ‚ทใƒณใ‚ฐใƒซใƒกใ‚ฟใƒซใƒ–ใƒฉใ‚ฑใƒƒใƒˆ', value: item.slate_single_metal_bracket, memo: item.slate_single_metal_bracket_memo }, + { name: 'DIDOใƒใƒณใƒˆใ‚ทใƒงใƒผใƒˆใƒฉใƒƒใ‚ฏ4', value: item.dido_hunt_short_rack_4, memo: item.dido_hunt_short_rack_4_memo }, + { + name: '้ซ˜ๅณถใ‚นใƒฌใƒผใƒˆใƒ–ใƒฉใ‚ฑใƒƒใƒˆใ‚นใƒฌใƒผใƒˆใ‚ทใƒณใ‚ฐใƒซ', + value: item.takashima_slate_bracket_slate_single, + memo: item.takashima_slate_bracket_slate_single_memo, + }, + { name: 'DFใƒกใ‚ฟใƒซใƒ–ใƒฉใ‚ฑใƒƒใƒˆ', value: item.df_metal_bracket, memo: item.df_metal_bracket_memo }, + { name: 'ใ‚นใƒฌใƒผใƒˆใƒกใ‚ฟใƒซใƒ–ใƒฉใ‚ฑใƒƒใƒˆ', value: item.slate_metal_bracket, memo: item.slate_metal_bracket_memo }, + { name: '้ซ˜ๅณถใ‚นใƒฌใƒผใƒˆใƒ–ใƒฉใ‚ฑใƒƒใƒˆใƒกใ‚ฟใƒซๅฑ‹ๆ น', value: item.takashima_slate_bracket_metal_roof, memo: item.takashima_slate_bracket_metal_roof_memo }, + ] +} + +function FittingItem({ fitting }: { fitting: FittingItem }) { + const statusInfo = getStatusInfo(fitting.value) + if (!statusInfo) return null + + return ( +
  • + {statusInfo.statusIcon} + + {fitting.name}๏ผš{statusInfo.statusText} + + {fitting.memo && ( + + ๅ‚™่€ƒ๏ผš + {fitting.memo} + + )} +
  • + ) +} + +export default function PDFContent({ data }: { data: Suitable[] }) { + return ( +
    + +

    ้ฉๅˆ็ตๆžœ (์ ํ•ฉ๊ฒฐ๊ณผ)

    + {data.map((item) => ( +
    +
    +

    + {item.product_name}๏ผˆ{item.manufacturer} / {item.roof_material} / {item.shape}๏ผ‰ +

    +
      + {getFittingItems(item).map((fitting, index) => ( + + ))} +
    +
    + ))} +
    + ) +} diff --git a/src/components/SuitableSearch.tsx b/src/components/SuitableSearch.tsx index 9583ede..4e3aa13 100644 --- a/src/components/SuitableSearch.tsx +++ b/src/components/SuitableSearch.tsx @@ -1,21 +1,88 @@ 'use client' -import { useState } from 'react' +import { useEffect, useState } from 'react' import { useRouter } from 'next/navigation' +import { useQuery } from '@tanstack/react-query' +import { useSuitable } from '@/hooks/useSuitable' +import Link from 'next/link' export default function SuitableSearch() { const router = useRouter() - const [selectedValue, setSelectedValue] = useState('') + const [selectedCategory, setSelectedCategory] = useState('') + const [searchValue, setSearchValue] = useState('') + const { getCategories, getSuitables } = useSuitable() + + const { data: categories } = useQuery({ + queryKey: ['categories'], + queryFn: getCategories, + staleTime: 1000 * 60 * 60, // 60๋ถ„ + }) + + const { data: suitableList } = useQuery({ + queryKey: ['suitables', 'list'], + queryFn: async () => await getSuitables(), + staleTime: 1000 * 60 * 10, // 10๋ถ„ + gcTime: 1000 * 60 * 10, // 10๋ถ„ + }) + + const { data: suitableSearch, refetch: refetchBySearch } = useQuery({ + queryKey: ['suitables', 'search'], + queryFn: async () => { + // api๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒ€์ƒ‰ ๋ฐฉ๋ฒ• + // return await updateSearchResults(selectedCategory || undefined, searchValue || undefined) + // useQuery ์บ์‹œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒ€์ƒ‰ ๋ฐฉ๋ฒ• + return ( + suitableList?.filter((item) => { + const categoryMatch = !selectedCategory || item.roof_material === selectedCategory + const searchMatch = !searchValue || item.product_name.includes(searchValue) + return categoryMatch && searchMatch + }) ?? [] + ) + }, + staleTime: 1000 * 60 * 10, + gcTime: 1000 * 60 * 10, + enabled: false, + }) + + // ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ๋œ ํ›„ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์—†์œผ๋ฉด ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ๋กœ๋”ฉ + useEffect(() => { + if (suitableList && (!suitableSearch || suitableSearch.length === 0)) { + refetchBySearch() + } + }, [suitableList, suitableSearch]) + + // ์นดํ…Œ๊ณ ๋ฆฌ ์„ ํƒ ์‹œ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ๋กœ๋”ฉ + useEffect(() => { + refetchBySearch() + }, [selectedCategory]) + + const handleSearch = async () => { + if (!searchValue.trim()) { + alert('๊ฒ€์ƒ‰์–ด๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”.') + return + } + refetchBySearch() + } return ( <> - - +
    + + + ์ง€๋ถ•์žฌ ์ข…๋ฅ˜ ์ƒ์„ธ๋ณด๊ธฐ ํŽ˜์ด์ง€ ์ด๋™ + +
    +
    + setSearchValue(e.target.value)} /> + +
    ) } diff --git a/src/components/SurveySales.tsx b/src/components/SurveySales.tsx index 387b7cd..f0dba94 100644 --- a/src/components/SurveySales.tsx +++ b/src/components/SurveySales.tsx @@ -1,9 +1,12 @@ 'use client' -import { surveySalesApi, SurveySalesBasicInfo } from '@/api/surveySales' -import { useMutation, useQueryClient } from '@tanstack/react-query' +import { surveySalesApi, SurveySalesBasicInfo, SurveySalesDetailInfo } from '@/api/surveySales' +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' +import { useState } from 'react' export default function SurveySales() { + const [isSearch, setIsSearch] = useState(false) + const queryClient = useQueryClient() const { @@ -34,6 +37,68 @@ export default function SurveySales() { createSurveySales(data) } + const { data, error: errorList } = useQuery({ + queryKey: ['survey-sales', 'list'], + queryFn: surveySalesApi.getList, + enabled: isSearch, + }) + + const { mutate: updateSurveySales } = useMutation({ + mutationFn: surveySalesApi.update, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['survey-sales', 'list'] }) + }, + }) + + const handleUpdateSurveySales = () => { + const detailData: SurveySalesDetailInfo = { + contract_capacity: '1100', + retail_company: 'test company', + supplementary_facilities: 1, + supplementary_facilities_etc: '', + installation_system: 3, + installation_system_etc: '', + construction_year: 4, + construction_year_etc: '', + roof_material: 1, + roof_material_etc: '', + roof_shape: 2, + roof_shape_etc: '', + roof_slope: '4.5', + house_structure: 1, + house_structure_etc: '', + rafter_material: 5, + rafter_material_etc: 'test message', + rafter_size: 3, + rafter_size_etc: '', + rafter_pitch: 2, + rafter_pitch_etc: '', + rafter_direction: 3, + open_field_plate_kind: 3, + open_field_plate_kind_etc: '', + open_field_plate_thickness: '', + leak_trace: false, + waterproof_material: 2, + waterproof_material_etc: '', + insulation_presence: 3, + insulation_presence_etc: '', + structure_order: 2, + structure_order_etc: '', + installation_availability: 1, + installation_availability_etc: '', + memo: 'test memo', + } + + if (!data) return + + const surveySalesData: SurveySalesBasicInfo = { + ...data[0], + detail_info: { ...detailData }, + } + + updateSurveySales(surveySalesData) + } + return ( <>
    @@ -41,13 +106,22 @@ export default function SurveySales() { - + +
    {/*

    Be Warned

    ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ ์„ธํŒ… ๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค.

    */} +
    + {errorList &&
    Error: {errorList.message}
    } + {data && data.map((item) =>
    {JSON.stringify(item)}
    )} +
    ) } diff --git a/src/hooks/useSuitable.ts b/src/hooks/useSuitable.ts new file mode 100644 index 0000000..62f00e2 --- /dev/null +++ b/src/hooks/useSuitable.ts @@ -0,0 +1,30 @@ +import { suitableApi } from '@/api/suitable' + +export function useSuitable() { + const getCategories = async () => { + try { + return await suitableApi.getCategory() + } catch (error) { + console.error('์นดํ…Œ๊ณ ๋ฆฌ ๋ฐ์ดํ„ฐ ๋กœ๋“œ ์‹คํŒจ:', error) + return [] + } + } + + const getSuitables = async () => { + try { + return await suitableApi.getList() + } catch (error) { + console.error('์ง€๋ถ•์žฌ ๋ฐ์ดํ„ฐ ๋กœ๋“œ ์‹คํŒจ:', error) + } + } + + const updateSearchResults = async (selectedCategory: string | undefined, searchValue: string | undefined) => { + try { + return await suitableApi.getList(selectedCategory, searchValue) + } catch (error) { + console.error('์ง€๋ถ•์žฌ ๋ฐ์ดํ„ฐ ๊ฒ€์ƒ‰ ์‹คํŒจ:', error) + } + } + + return { getCategories, getSuitables, updateSearchResults } +} diff --git a/src/store/useSuitableStore.ts b/src/store/useSuitableStore.ts new file mode 100644 index 0000000..17b88c5 --- /dev/null +++ b/src/store/useSuitableStore.ts @@ -0,0 +1,68 @@ +import { create } from 'zustand' +import { Suitable, suitableApi } from '@/api/suitable' + +interface SuitableState { + // // ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ๋ฆฌ์ŠคํŠธ + // searchResults: Suitable[] + // // ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ ๋กœ๋“œ + // fetchInitializeData: () => Promise + // // ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์„ค์ • + // setSearchResults: (results: Suitable[]) => void + // // ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์ดˆ๊ธฐํ™” + // resetSearchResults: () => void + + // ์„ ํƒ๋œ ์•„์ดํ…œ ๋ฆฌ์ŠคํŠธ + selectedItems: Suitable[] + // ์„ ํƒ๋œ ์•„์ดํ…œ ์ถ”๊ฐ€ + addSelectedItem: (item: Suitable) => void + // ์„ ํƒ๋œ ์•„์ดํ…œ ์ œ๊ฑฐ + removeSelectedItem: (itemId: number) => void + // ์„ ํƒ๋œ ์•„์ดํ…œ ๋ชจ๋‘ ์ œ๊ฑฐ + clearSelectedItems: () => void +} + +export const useSuitableStore = create((set) => ({ + // // ์ดˆ๊ธฐ ์ƒํƒœ + // searchResults: [], + + // // ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ ๋กœ๋“œ + // fetchInitializeData: async () => { + // const suitables = await fetchInitialSuitablee() + // set({ searchResults: suitables }) + // }, + + // // ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์„ค์ • + // setSearchResults: (results) => set({ searchResults: results }), + + // // ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์ดˆ๊ธฐํ™” + // resetSearchResults: () => set({ searchResults: [] }), + + // ์ดˆ๊ธฐ ์ƒํƒœ + selectedItems: [], + + // ์„ ํƒ๋œ ์•„์ดํ…œ ์ถ”๊ฐ€ (์ค‘๋ณต ๋ฐฉ์ง€) + addSelectedItem: (item) => + set((state) => ({ + selectedItems: state.selectedItems.some((i) => i.id === item.id) ? state.selectedItems : [...state.selectedItems, item], + })), + + // ์„ ํƒ๋œ ์•„์ดํ…œ ์ œ๊ฑฐ + removeSelectedItem: (itemId) => + set((state) => ({ + selectedItems: state.selectedItems.filter((item) => item.id !== itemId), + })), + + // ์„ ํƒ๋œ ์•„์ดํ…œ ๋ชจ๋‘ ์ œ๊ฑฐ + clearSelectedItems: () => set({ selectedItems: [] }), +})) + +// // ์ „์ฒด ๋ฐ์ดํ„ฐ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜ +// async function fetchInitialSuitablee() { +// try { +// const suitable = await suitableApi.getList() +// return suitable +// } catch (error) { +// console.error('์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ ๋กœ๋“œ ์‹คํŒจ:', error) +// return [] +// } +// }