From 510317c67679a2e0156c82cbcface72f4fb2d93d Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Thu, 15 May 2025 16:30:46 +0900 Subject: [PATCH] feat: implement authentication and survey sales APIs with suitable data structure --- src/api/auth.ts | 22 +++++ src/api/suitable.ts | 107 +++++++++++++++++++++ src/api/surveySales.ts | 127 ++++++++++++++++++++++++ src/api/user.ts | 37 +++++++ src/app/api/survey-sale/[id]/route.ts | 133 +++++++++++++------------- src/app/api/user/route.ts | 7 +- src/hooks/useSuitable.ts | 6 +- 7 files changed, 367 insertions(+), 72 deletions(-) create mode 100644 src/api/auth.ts create mode 100644 src/api/suitable.ts create mode 100644 src/api/surveySales.ts create mode 100644 src/api/user.ts diff --git a/src/api/auth.ts b/src/api/auth.ts new file mode 100644 index 0000000..00a415e --- /dev/null +++ b/src/api/auth.ts @@ -0,0 +1,22 @@ +'use server' + +import { sessionOptions } from '@/libs/session' +import type { SessionData } from '@/types/Auth' +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/suitable.ts b/src/api/suitable.ts new file mode 100644 index 0000000..952f956 --- /dev/null +++ b/src/api/suitable.ts @@ -0,0 +1,107 @@ +import { database } from '@/data' +import { axiosInstance } from '@/libs/axios' + +export interface Suitable { + id?: number + product_name: string + manufacturer: string + roof_material: string + shape: string + support_roof_tile: string + support_roof_tile_memo: string + support_roof_bracket: string + support_roof_bracket_memo: string + yg_anchor: string + yg_anchor_memo: string + rg_roof_tile_part: string + rg_roof_tile_part_memo: string + dido_hunt_support_tile_2: string + dido_hunt_support_tile_2_memo: string + takashima_power_base: string + takashima_power_base_memo: string + takashima_tile_bracket: string + takashima_tile_bracket_memo: string + slate_bracket_4: string + slate_bracket_4_memo: string + slate_single_metal_bracket: string + slate_single_metal_bracket_memo: string + dido_hunt_short_rack_4: string + dido_hunt_short_rack_4_memo: string + takashima_slate_bracket_slate_single: string + takashima_slate_bracket_slate_single_memo: string + df_metal_bracket: string + df_metal_bracket_memo: string + slate_metal_bracket: string + slate_metal_bracket_memo: string + takashima_slate_bracket_metal_roof: string + takashima_slate_bracket_metal_roof_memo: string +} + +export const suitableApi = { + // 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(null).get('/api/suitable/list', { params: condition }) + // console.log('πŸš€ ~ getList: ~ response:', response) + // return response.data + // }, + // getCategory: async (): Promise => { + // const response = await axiosInstance(null).get('/api/suitable/category') + // console.log('πŸš€ ~ getCategory: ~ response:', response) + // return response.data + // }, + // getDetails: async (roofMaterial: string): Promise => { + // const response = await axiosInstance(null).get(`/api/suitable/details?roof-material=${roofMaterial}`) + // console.log('πŸš€ ~ getDetails: ~ response:', response) + // return response.data + // }, + // create: async () => { + // const suitableData: Suitable[] = [] + // database.forEach((item) => { + // suitableData.push({ + // product_name: item[0], + // manufacturer: item[1], + // roof_material: item[2], + // shape: item[3], + // support_roof_tile: item[4], + // support_roof_tile_memo: item[5], + // support_roof_bracket: item[6], + // support_roof_bracket_memo: item[7], + // yg_anchor: item[8], + // yg_anchor_memo: item[9], + // rg_roof_tile_part: item[10], + // rg_roof_tile_part_memo: item[11], + // dido_hunt_support_tile_2: item[12], + // dido_hunt_support_tile_2_memo: item[13], + // takashima_power_base: item[14], + // takashima_power_base_memo: item[15], + // takashima_tile_bracket: item[16], + // takashima_tile_bracket_memo: item[17], + // slate_bracket_4: item[18], + // slate_bracket_4_memo: item[19], + // slate_single_metal_bracket: item[20], + // slate_single_metal_bracket_memo: item[21], + // dido_hunt_short_rack_4: item[22], + // dido_hunt_short_rack_4_memo: item[23], + // takashima_slate_bracket_slate_single: item[24], + // takashima_slate_bracket_slate_single_memo: item[25], + // df_metal_bracket: item[26], + // df_metal_bracket_memo: item[27], + // slate_metal_bracket: item[28], + // slate_metal_bracket_memo: item[29], + // takashima_slate_bracket_metal_roof: item[30], + // takashima_slate_bracket_metal_roof_memo: item[31], + // }) + // }) + // const response = await axiosInstance(null).post('/api/suitable', suitableData) + // return response.data + // }, +} diff --git a/src/api/surveySales.ts b/src/api/surveySales.ts new file mode 100644 index 0000000..b17f053 --- /dev/null +++ b/src/api/surveySales.ts @@ -0,0 +1,127 @@ +import { axiosInstance } from '@/libs/axios' + +export interface SurveySalesBasicInfo { + id?: number + representative: string + store: string | null + construction_point: string | null + investigation_date: string | null + building_name: string | null + customer_name: string | null + post_code: string | null + address: string | null + address_detail: string | null + submission_status: boolean + submission_date?: string | null + detail_info?: SurveySalesDetailInfo | null +} + +export interface SurveySalesDetailInfo { + id?: number + contract_capacity: string | null + retail_company: string | null + supplementary_facilities: number | null + supplementary_facilities_etc: string | null + installation_system: number | null + installation_system_etc: string | null + construction_year: number | null + construction_year_etc: string | null + roof_material: number | null + roof_material_etc: string | null + roof_shape: number | null + roof_shape_etc: string | null + roof_slope: string | null + house_structure: number | null + house_structure_etc: string | null + rafter_material: number | null + rafter_material_etc: string | null + rafter_size: number | null + rafter_size_etc: string | null + rafter_pitch: number | null + rafter_pitch_etc: string | null + rafter_direction: number | null + open_field_plate_kind: number | null + open_field_plate_kind_etc: string | null + open_field_plate_thickness: string | null + leak_trace: boolean | null + waterproof_material: number | null + waterproof_material_etc: string | null + insulation_presence: number | null + insulation_presence_etc: string | null + structure_order: number | null + structure_order_etc: string | null + installation_availability: number | null + installation_availability_etc: string | null + memo: string | null +} + +export const surveySalesApi = { + create: async (data: SurveySalesBasicInfo): Promise => { + try { + const response = await axiosInstance(null).post('/api/survey-sales', data) + return response.data.id ?? 0 + } catch (error) { + console.error(error) + return 0 + } + }, + getList: async (): Promise => { + try { + const response = await axiosInstance(null).get('/api/survey-sales') + return response.data + } catch (error) { + console.error(error) + return [] + } + }, + getDetail: async (id: number): Promise => { + try { + const response = await axiosInstance(null).get(`/api/survey-sales/${id}`) + return response.data + } catch (error) { + console.error(error) + return null + } + }, + update: async (id: number, data: SurveySalesBasicInfo): Promise => { + try { + const response = await axiosInstance(null).put(`/api/survey-sales/${id}`, data) + return response.data + } catch (error) { + console.error(error) + return null + } + }, + delete: async (id: number, isDetail: boolean = false): Promise => { + try { + await axiosInstance(null).delete(`/api/survey-sales/${id}`, { + params: { + detail_id: isDetail ? id : undefined, + }, + }) + return true + } catch (error) { + throw error + } + }, + createDetail: async (surveyId: number, data: SurveySalesDetailInfo): Promise => { + try { + await axiosInstance(null).post(`/api/survey-sales/${surveyId}`, data) + return true + } catch (error) { + throw error + } + }, + confirm: async (id: number): Promise => { + try { + await axiosInstance(null).patch(`/api/survey-sales/${id}`) + return true + } catch (error) { + throw error + } + }, + // update: async (data: SurveySalesBasicInfo): Promise => { + // const response = await axiosInstance.put(`/api/survey-sales`, data) + // return response.data + // }, +} diff --git a/src/api/user.ts b/src/api/user.ts new file mode 100644 index 0000000..6b39cf0 --- /dev/null +++ b/src/api/user.ts @@ -0,0 +1,37 @@ +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(null).post('/api/user/create', data) + return response.data + }, + + getList: async (): Promise => { + const response = await axiosInstance(null).get('/api/user/list') + return response.data + }, + + getUser: async (data: LoginData): Promise => { + const response = await axiosInstance(null).post(`/api/user`, data) + return response.data + }, +} diff --git a/src/app/api/survey-sale/[id]/route.ts b/src/app/api/survey-sale/[id]/route.ts index bf5afe4..04ccf2d 100644 --- a/src/app/api/survey-sale/[id]/route.ts +++ b/src/app/api/survey-sale/[id]/route.ts @@ -1,72 +1,73 @@ 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 +// export async function POST(request: Request, { params }: { params: { id: string } }) { +// const body = await request.json() +// const { id } = 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) -} +// // @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 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 GET(request: Request, { params }: { params: { id: string } }) { +// const { id } = 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 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 PUT(request: Request, { params }: { params: { id: string } }) { +// const { id } = 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 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' }) -} +// export async function DELETE(request: Request, { params }: { params: { id: string; detail_id: string } }) { +// const { id, detail_id } = 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, { params }: { params: { id: string } }) { +// const { id } = 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/user/route.ts b/src/app/api/user/route.ts index d3cda5f..0249fd6 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.username = user.username! + // session.email = user.email! session.isLoggedIn = true console.log('end session edit!') await session.save() diff --git a/src/hooks/useSuitable.ts b/src/hooks/useSuitable.ts index 62f00e2..c3f0dde 100644 --- a/src/hooks/useSuitable.ts +++ b/src/hooks/useSuitable.ts @@ -3,7 +3,7 @@ import { suitableApi } from '@/api/suitable' export function useSuitable() { const getCategories = async () => { try { - return await suitableApi.getCategory() + // return await suitableApi.getCategory() } catch (error) { console.error('μΉ΄ν…Œκ³ λ¦¬ 데이터 λ‘œλ“œ μ‹€νŒ¨:', error) return [] @@ -12,7 +12,7 @@ export function useSuitable() { const getSuitables = async () => { try { - return await suitableApi.getList() + // return await suitableApi.getList() } catch (error) { console.error('μ§€λΆ•μž¬ 데이터 λ‘œλ“œ μ‹€νŒ¨:', error) } @@ -20,7 +20,7 @@ export function useSuitable() { const updateSearchResults = async (selectedCategory: string | undefined, searchValue: string | undefined) => { try { - return await suitableApi.getList(selectedCategory, searchValue) + // return await suitableApi.getList(selectedCategory, searchValue) } catch (error) { console.error('μ§€λΆ•μž¬ 데이터 검색 μ‹€νŒ¨:', error) }