From f801bacd12440da0493a0de943a8c8f09a600a06 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Tue, 29 Apr 2025 16:56:41 +0900 Subject: [PATCH 1/3] feat: Add update functionality to Survey Sales API and enhance UI for managing survey sales details --- src/api/surveySales.ts | 4 ++ src/app/api/survey-sales/route.ts | 22 ++++++++ src/app/suitable/[slug]/page.tsx | 1 + src/components/SuitableDetails.tsx | 17 ++++--- src/components/SurveySales.tsx | 80 ++++++++++++++++++++++++++++-- 5 files changed, 114 insertions(+), 10 deletions(-) diff --git a/src/api/surveySales.ts b/src/api/surveySales.ts index 3d9d727..e54f856 100644 --- a/src/api/surveySales.ts +++ b/src/api/surveySales.ts @@ -64,4 +64,8 @@ export const surveySalesApi = { const response = await axiosInstance.get('/api/survey-sales') return response.data }, + update: async (data: SurveySalesBasicInfo): Promise => { + const response = await axiosInstance.put(`/api/survey-sales`, data) + return response.data + }, } diff --git a/src/app/api/survey-sales/route.ts b/src/app/api/survey-sales/route.ts index decd3a3..7662111 100644 --- a/src/app/api/survey-sales/route.ts +++ b/src/app/api/survey-sales/route.ts @@ -11,3 +11,25 @@ export async function POST(request: Request) { return NextResponse.json({ message: 'Survey sales created successfully' }) } + +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/SuitableDetails.tsx b/src/components/SuitableDetails.tsx index 3d698d7..795fcdc 100644 --- a/src/components/SuitableDetails.tsx +++ b/src/components/SuitableDetails.tsx @@ -1,15 +1,18 @@ 'use client' -import { suitableApi } from '@/api/suitable' -import { useQuery } from '@tanstack/react-query' +import { Suitable, suitableApi } from '@/api/suitable' +import { useQuery, useQueryClient } from '@tanstack/react-query' export default function SuitableDetails({ roofMaterial }: { roofMaterial: string }) { console.log('πŸš€ ~ SuitableDetails ~ roofMaterial:', roofMaterial) - const { data, error, isPending } = useQuery({ - queryKey: ['suitable-details'], - queryFn: () => suitableApi.getDetails(roofMaterial), - staleTime: 0, - }) + // const { data, error, isPending } = useQuery({ + // queryKey: ['suitable-details'], + // queryFn: () => suitableApi.getDetails(roofMaterial), + // staleTime: 0, + // }) + const cache = useQueryClient() + const listData = cache.getQueryData(['suitable-list']) as Suitable[] + const data = listData.filter((item) => item.roof_material === roofMaterial) return ( <> 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)}
)} +
) } From 45b244d30954fd583edad2c3de561f6862ca8020 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Wed, 30 Apr 2025 15:01:23 +0900 Subject: [PATCH 2/3] chore: Refactor next.config.ts to streamline API rewrites and remove unnecessary CORS headers --- next.config.ts | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) 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*`, }, ] }, From 4afcd7f8ebaf9f95efad6b44179230edf4b6f797 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Wed, 30 Apr 2025 16:47:44 +0900 Subject: [PATCH 3/3] chore: ready for work --- src/api/auth.ts | 21 -------- src/api/user.ts | 37 ------------- src/app/api/suitable/route.ts | 12 ----- src/app/api/user/create/route.ts | 23 -------- src/app/api/user/list/route.ts | 7 --- src/app/api/user/route.ts | 37 ------------- src/app/counter/page.tsx | 14 ----- src/app/globals.css | 26 --------- src/app/layout.tsx | 14 ----- src/app/login/page.tsx | 12 ----- src/app/page.tsx | 39 +------------- src/app/pdf-download/page.tsx | 10 ---- src/app/suitable/[slug]/page.tsx | 12 ----- src/app/suitable/page.tsx | 13 ----- src/components/Counter.tsx | 31 ----------- src/components/Login.tsx | 79 ---------------------------- src/components/PdfDownloadNew.tsx | 20 ------- src/components/SuitableCreateBtn.tsx | 29 ---------- src/components/User.tsx | 52 ------------------ src/components/UserList.tsx | 25 --------- src/components/common/Footer.tsx | 13 ----- 21 files changed, 1 insertion(+), 525 deletions(-) delete mode 100644 src/api/auth.ts delete mode 100644 src/api/user.ts delete mode 100644 src/app/api/suitable/route.ts delete mode 100644 src/app/api/user/create/route.ts delete mode 100644 src/app/api/user/list/route.ts delete mode 100644 src/app/api/user/route.ts delete mode 100644 src/app/counter/page.tsx delete mode 100644 src/app/globals.css delete mode 100644 src/app/login/page.tsx delete mode 100644 src/app/pdf-download/page.tsx delete mode 100644 src/app/suitable/[slug]/page.tsx delete mode 100644 src/app/suitable/page.tsx delete mode 100644 src/components/Counter.tsx delete mode 100644 src/components/Login.tsx delete mode 100644 src/components/PdfDownloadNew.tsx delete mode 100644 src/components/SuitableCreateBtn.tsx delete mode 100644 src/components/User.tsx delete mode 100644 src/components/UserList.tsx delete mode 100644 src/components/common/Footer.tsx diff --git a/src/api/auth.ts b/src/api/auth.ts deleted file mode 100644 index ee3fd05..0000000 --- a/src/api/auth.ts +++ /dev/null @@ -1,21 +0,0 @@ -'use server' - -import { SessionData, sessionOptions } from '@/libs/session' -import { getIronSession } from 'iron-session' -import { cookies } from 'next/headers' -import { redirect } from 'next/navigation' - -export const logout = async () => { - const cookieStore = await cookies() - const session = await getIronSession(cookieStore, sessionOptions) - - session.destroy() - return redirect('/login') -} - -export const getSession = async () => { - const cookieStore = await cookies() - const session = await getIronSession(cookieStore, sessionOptions) - - return session -} diff --git a/src/api/user.ts b/src/api/user.ts deleted file mode 100644 index fe299ba..0000000 --- a/src/api/user.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { axiosInstance } from '@/libs/axios' - -export interface UserData { - username: string - email: string - password: string -} - -export interface User { - id: number - username: string - email: string - created_at: string - updated_at: string -} - -export interface LoginData { - username: string - password: string -} - -export const userApi = { - create: async (data: UserData): Promise => { - const response = await axiosInstance.post('/api/user/create', data) - return response.data - }, - - getList: async (): Promise => { - const response = await axiosInstance.get('/api/user/list') - return response.data - }, - - getUser: async (data: LoginData): Promise => { - const response = await axiosInstance.post(`/api/user`, data) - return response.data - }, -} diff --git a/src/app/api/suitable/route.ts b/src/app/api/suitable/route.ts deleted file mode 100644 index 7f7be9c..0000000 --- a/src/app/api/suitable/route.ts +++ /dev/null @@ -1,12 +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 suitables = await prisma.MS_SUITABLE.createMany({ - data: body, - }) - - return NextResponse.json({ message: 'Suitable created successfully' }) -} diff --git a/src/app/api/user/create/route.ts b/src/app/api/user/create/route.ts deleted file mode 100644 index c4e4060..0000000 --- a/src/app/api/user/create/route.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { NextResponse } from 'next/server' -import { prisma } from '@/libs/prisma' - -export async function POST(request: Request) { - try { - const body = await request.json() - const { username, email, password } = body - - const user = await prisma.user.create({ - data: { - username, - email, - password, - updated_at: new Date(), - }, - }) - - return NextResponse.json(user) - } catch (error) { - console.error('Error creating user:', error) - return NextResponse.json({ error: 'Error creating user' }, { status: 500 }) - } -} diff --git a/src/app/api/user/list/route.ts b/src/app/api/user/list/route.ts deleted file mode 100644 index f84af78..0000000 --- a/src/app/api/user/list/route.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { NextResponse } from 'next/server' -import { prisma } from '@/libs/prisma' - -export const GET = async () => { - const users = await prisma.user.findMany() - return NextResponse.json(users) -} diff --git a/src/app/api/user/route.ts b/src/app/api/user/route.ts deleted file mode 100644 index d3cda5f..0000000 --- a/src/app/api/user/route.ts +++ /dev/null @@ -1,37 +0,0 @@ -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' - -export async function POST(request: Request) { - const { username, password } = await request.json() - - console.log('πŸš€ ~ POST ~ username:', username) - console.log('πŸš€ ~ POST ~ password:', password) - - const user = await prisma.user.findFirst({ - where: { - username: username, - password: password, - }, - }) - console.log('πŸš€ ~ POST ~ user:', user) - - if (!user) { - return NextResponse.json({ error: 'User not found' }, { status: 404 }) - } - - const cookieStore = await cookies() - const session = await getIronSession(cookieStore, sessionOptions) - console.log('start session edit!') - session.username = user.username! - session.email = user.email! - session.isLoggedIn = true - console.log('end session edit!') - await session.save() - console.log('πŸš€ ~ POST ~ session:', session) - - // return NextResponse.redirect(new URL(process.env.NEXT_PUBLIC_URL!, request.url)) - return NextResponse.json(user) -} diff --git a/src/app/counter/page.tsx b/src/app/counter/page.tsx deleted file mode 100644 index be7ed53..0000000 --- a/src/app/counter/page.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import Counter from '@/components/Counter' - -export default function page() { - return ( - <> -
-

Counter

-
- -
-
- - ) -} diff --git a/src/app/globals.css b/src/app/globals.css deleted file mode 100644 index a2dc41e..0000000 --- a/src/app/globals.css +++ /dev/null @@ -1,26 +0,0 @@ -@import "tailwindcss"; - -:root { - --background: #ffffff; - --foreground: #171717; -} - -@theme inline { - --color-background: var(--background); - --color-foreground: var(--foreground); - --font-sans: var(--font-geist-sans); - --font-mono: var(--font-geist-mono); -} - -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; - } -} - -body { - background: var(--background); - color: var(--foreground); - font-family: Arial, Helvetica, sans-serif; -} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 0e4e365..4766652 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,18 +1,5 @@ import type { Metadata } from 'next' import ReactQueryProviders from '@/providers/ReactQueryProvider' -import { Geist, Geist_Mono } from 'next/font/google' -import Footer from '@/components/common/Footer' -import './globals.css' - -const geistSans = Geist({ - variable: '--font-geist-sans', - subsets: ['latin'], -}) - -const geistMono = Geist_Mono({ - variable: '--font-geist-mono', - subsets: ['latin'], -}) export const metadata: Metadata = { title: 'Create Next App', @@ -28,7 +15,6 @@ export default function RootLayout({ {children} -