Compare commits

..

No commits in common. "19a11783d6593baa493c04fb3e75ce464c755194" and "5893cd6491724f08b7eceb9173ba58ce8ba04202" have entirely different histories.

36 changed files with 82 additions and 328 deletions

16
.env
View File

@ -0,0 +1,16 @@
# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
# DATABASE_URL="sqlserver://3team.devgrr.kr:1433;database=onsitesurvey;user=sa;password=1q2w3e4r!;encrypt=true;trustServerCertificate=true;"
DATABASE_URL="sqlserver://3team.devgrr.kr:1433;database=onsitesurvey;user=sa;password=1q2w3e4r!;encrypt=true;trustServerCertificate=true;connectionTimeout=30000;applicationName=OnSiteSurvey"
# DATABASE_URL="sqlserver://172.16.56.60:14331;database=hanwha_qcells_jp;user=qcells_jp;password=zbtpf2022!;encrypt=true;trustServerCertificate=true;applicationName=OnSiteSurvey"
# DATABASE_URL="mysql://root:root@localhost:3306/onsitesurvey"
DATABASE_CONNECTION_LIMIT=10
DATABASE_POOL_MIN=2
DATABASE_POOL_MAX=10
# SESSION_PASSWORD="QWERASDFZXCV1234567890REWQFDSAVCXZ"
SESSION_PASSWORD="This application is for mobile field research"

View File

@ -1,17 +1,8 @@
NEXT_PUBLIC_RUN_MODE=development
DATABASE_URL="sqlserver://172.16.56.60:14331;database=hanwha_qcells_jp;user=qcells_jp;password=zbtpf2022!;encrypt=true;trustServerCertificate=true;applicationName=OnSiteSurvey"
DATABASE_CONNECTION_LIMIT=10
DATABASE_POOL_MIN=2
DATABASE_POOL_MAX=10
SESSION_PASSWORD="This application is for mobile field research"
# 모바일 디바이스로 로컬 서버 확인하려면 자신 IP 주소로 변경
# 다시 로컬에서 개발할때는 localhost로 변경
#route handler
# NEXT_PUBLIC_API_URL=http://172.16.56.60:3000
NEXT_PUBLIC_API_URL=https://dev.hanasysfield.jp
NEXT_PUBLIC_API_URL=http://localhost:3000
#qsp 로그인 api
NEXT_PUBLIC_QSP_API_URL=http://121.168.9.37:8080

View File

@ -1,12 +1,4 @@
NEXT_PUBLIC_RUN_MODE=local
DATABASE_URL="sqlserver://172.16.56.60:14331;database=hanwha_qcells_jp;user=qcells_jp;password=zbtpf2022!;encrypt=true;trustServerCertificate=true;applicationName=OnSiteSurvey"
DATABASE_CONNECTION_LIMIT=10
DATABASE_POOL_MIN=2
DATABASE_POOL_MAX=10
SESSION_PASSWORD="This application is for mobile field research"
# 모바일 디바이스로 로컬 서버 확인하려면 자신 IP 주소로 변경
# 다시 로컬에서 개발할때는 localhost로 변경
#route handler

View File

@ -1,15 +1,6 @@
NEXT_PUBLIC_RUN_MODE=production
DATABASE_URL="sqlserver://172.16.56.57:14331;database=hanwha_qcells_jp;user=qcells_jp;password=zbtpf2022!;encrypt=true;trustServerCertificate=true;applicationName=OnSiteSurvey"
DATABASE_CONNECTION_LIMIT=10
DATABASE_POOL_MIN=2
DATABASE_POOL_MAX=10
SESSION_PASSWORD="This application is for mobile field research"
#route handler
# NEXT_PUBLIC_API_URL=http://localhost:3000
NEXT_PUBLIC_API_URL=https://hanasysfield.jp
NEXT_PUBLIC_API_URL=http://localhost:3000
#qsp 로그인 api
# NEXT_PUBLIC_QSP_API_URL=http://1.248.227.176:8120

6
.gitignore vendored
View File

@ -45,8 +45,4 @@ next-env.d.ts
bun.lockb
pnpm-lock.yaml
pnpm-workspace.yaml
# logs
logs/
*.log
pnpm-workspace.yaml

View File

@ -1,2 +0,0 @@
var exec = require('child_process').exec
exec('pnpm run start:dev', { windowsHide: true })

View File

@ -6,12 +6,7 @@ const nextConfig: NextConfig = {
sassOptions: {
includePaths: [path.join(__dirname, './src/styles')],
},
serverExternalPackages: ['@react-pdf/renderer', 'pino'],
logging: {
fetches: {
fullUrl: true,
},
},
serverExternalPackages: ['@react-pdf/renderer'],
async rewrites() {
return [
{
@ -24,22 +19,6 @@ const nextConfig: NextConfig = {
// },
]
},
webpack: (config, { dev, isServer }) => {
if (!dev && !isServer) {
config.optimization.minimizer = config.optimization.minimizer || []
config.optimization.minimizer.push(
new (require('terser-webpack-plugin'))({
terserOptions: {
format: {
comments: false,
},
},
extractComments: false,
}),
)
}
return config
},
}
export default nextConfig

View File

@ -29,7 +29,6 @@
"next": "15.2.4",
"nodemailer": "^7.0.3",
"pdf-lib": "^1.17.1",
"pino": "^9.7.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-to-pdf": "^2.0.0",
@ -46,7 +45,6 @@
"@types/react-dom": "^19",
"prisma": "^6.7.0",
"tailwindcss": "^4",
"terser-webpack-plugin": "^5.3.14",
"typescript": "^5"
}
}

View File

@ -1,2 +0,0 @@
var exec = require('child_process').exec
exec('pnpm run start:prod', { windowsHide: true })

View File

@ -1,8 +1,7 @@
import { NextResponse } from 'next/server'
import { loggerWrapper } from '@/libs/api-wrapper'
import { axiosInstance } from '@/libs/axios'
async function setChgPwd(req: Request): Promise<NextResponse> {
export async function POST(req: Request) {
const { loginId, email, pwd, chgPwd } = await req.json()
console.log('🚀 ~ POST ~ loginId:', loginId)
console.log('🚀 ~ POST ~ email:', email)
@ -20,5 +19,3 @@ async function setChgPwd(req: Request): Promise<NextResponse> {
return NextResponse.json({ code: 200, data: result.data })
}
export const POST = loggerWrapper(setChgPwd)

View File

@ -1,9 +1,8 @@
import { NextRequest, NextResponse } from 'next/server'
import { loggerWrapper } from '@/libs/api-wrapper'
import { prisma } from '@/libs/prisma'
import type { CommCode } from '@/types/CommCode'
async function getCommCode(request: NextRequest): Promise<NextResponse> {
export async function GET(request: NextRequest) {
try {
const searchParams = request.nextUrl.searchParams
const headCode = searchParams.get('headCode')
@ -21,26 +20,24 @@ async function getCommCode(request: NextRequest): Promise<NextResponse> {
if (!headCd) {
return NextResponse.json({ error: `${headCode}를 찾을 수 없습니다` }, { status: 404 })
}
// @ts-ignore
const roofMaterials: CommCode[] = await prisma.BC_COMM_L.findMany({
where: {
HEAD_CD: headCd.HEAD_CD,
},
select: {
HEAD_CD: true,
CODE: true,
CODE_JP: true,
},
orderBy: {
CODE: 'asc',
},
})
if (headCode === 'SALES_OFFICE_CD') {
return getSaleOffice(headCd.HEAD_CD)
} else {
// @ts-ignore
const roofMaterials: CommCode[] = await prisma.BC_COMM_L.findMany({
where: {
HEAD_CD: headCd.HEAD_CD,
},
select: {
HEAD_CD: true,
CODE: true,
CODE_JP: true,
},
orderBy: {
CODE: 'asc',
},
})
return NextResponse.json(roofMaterials)
}
return NextResponse.json(roofMaterials)
} catch (error) {
console.error('❌ 데이터 조회 중 오류가 발생했습니다:', error)
return NextResponse.json({ error: '데이터 조회 중 오류가 발생했습니다' }, { status: 500 })
@ -63,5 +60,3 @@ const getSaleOffice = async (headCode: string) => {
})
return NextResponse.json(commCodeSaleOffice)
}
export const GET = loggerWrapper(getCommCode)

View File

@ -1,9 +1,8 @@
import { queryStringFormatter } from '@/utils/common-utils'
import axios from 'axios'
import { NextResponse } from 'next/server'
import { loggerWrapper } from '@/libs/api-wrapper'
async function getQnaDetail(request: Request): Promise<NextResponse> {
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const params = {
compCd: searchParams.get('compCd'),
@ -23,5 +22,3 @@ async function getQnaDetail(request: Request): Promise<NextResponse> {
return NextResponse.json({ error: 'route error' }, { status: 500 })
}
}
export const GET = loggerWrapper(getQnaDetail)

View File

@ -1,6 +1,5 @@
import axios from 'axios'
import { NextResponse } from 'next/server'
import { loggerWrapper } from '@/libs/api-wrapper'
// export async function GET(request: Request) {
// const { searchParams } = new URL(request.url)
@ -39,7 +38,7 @@ import { loggerWrapper } from '@/libs/api-wrapper'
// }
// }
async function downloadFile(request: Request): Promise<NextResponse> {
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const encodeFileNo = searchParams.get('encodeFileNo')
const srcFileNm = searchParams.get('srcFileNm') || 'downloaded-file'
@ -72,5 +71,3 @@ async function downloadFile(request: Request): Promise<NextResponse> {
return NextResponse.json({ error: error.response?.data || 'Failed to download file' }, { status: 500 })
}
}
export const GET = loggerWrapper(downloadFile)

View File

@ -3,11 +3,10 @@ import { NextResponse } from 'next/server'
import { queryStringFormatter } from '@/utils/common-utils'
import { getIronSession } from 'iron-session'
import { cookies } from 'next/headers'
import { loggerWrapper } from '@/libs/api-wrapper'
import { sessionOptions } from '@/libs/session'
import { SessionData } from '@/types/Auth'
async function getQnaList(request: Request): Promise<NextResponse> {
export async function GET(request: Request) {
const cookieStore = await cookies()
const session = await getIronSession<SessionData>(cookieStore, sessionOptions)
@ -38,5 +37,3 @@ async function getQnaList(request: Request): Promise<NextResponse> {
return NextResponse.json({ error: 'route error' }, { status: 500 })
}
}
export const GET = loggerWrapper(getQnaList)

View File

@ -1,9 +1,8 @@
import { NextResponse } from 'next/server'
import axios from 'axios'
import { CommonCode } from '@/types/Inquiry'
import { loggerWrapper } from '@/libs/api-wrapper'
async function getCommonCodeListData(request: Request): Promise<NextResponse> {
export async function GET() {
const response = await axios.get(`${process.env.NEXT_PUBLIC_INQUIRY_API_URL}/api/system/commonCodeListData`)
const codeList: CommonCode[] = []
response.data.data.apiCommCdList.forEach((item: any) => {
@ -18,5 +17,3 @@ async function getCommonCodeListData(request: Request): Promise<NextResponse> {
})
return NextResponse.json({ data: codeList })
}
export const GET = loggerWrapper(getCommonCodeListData)

View File

@ -1,8 +1,7 @@
import axios from 'axios'
import { NextResponse } from 'next/server'
import { loggerWrapper } from '@/libs/api-wrapper'
async function setQna(request: Request): Promise<NextResponse> {
export async function POST(request: Request) {
const formData = await request.formData()
console.log(formData)
try {
@ -20,5 +19,3 @@ async function setQna(request: Request): Promise<NextResponse> {
return NextResponse.json({ error: 'Failed to save qna' }, { status: 500 })
}
}
export const POST = loggerWrapper(setQna)

View File

@ -1,6 +1,5 @@
import { prisma } from '@/libs/prisma'
import { NextRequest, NextResponse } from 'next/server'
import { loggerWrapper } from '@/libs/api-wrapper'
type AdminSubPerson = {
storeId: string
@ -8,8 +7,8 @@ type AdminSubPerson = {
eMail: string
authority: string
}
// 2차점이 자신에게 매핑 된 1차 판매점과 관리자 정보 조회
async function getSubMissionAdminSub(request: NextRequest): Promise<NextResponse> {
// 2차점이 자신에게 매핑 된 1차 판매점과 관리자 정보 조회
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url)
const id = searchParams.get('id')
@ -41,5 +40,3 @@ async function getSubMissionAdminSub(request: NextRequest): Promise<NextResponse
return NextResponse.json({ error: '데이터 조회 중 오류가 발생했습니다' }, { status: 500 })
}
}
export const GET = loggerWrapper(getSubMissionAdminSub)

View File

@ -1,6 +1,5 @@
import { prisma } from '@/libs/prisma'
import { NextRequest, NextResponse } from 'next/server'
import { loggerWrapper } from '@/libs/api-wrapper'
type SuperPerson = {
storeId: string
@ -9,7 +8,7 @@ type SuperPerson = {
toEmail: string
}
async function getSubmissionAdmin(request: NextRequest): Promise<NextResponse> {
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url)
const id = searchParams.get('id')
@ -45,5 +44,3 @@ async function getSubmissionAdmin(request: NextRequest): Promise<NextResponse> {
return NextResponse.json({ error: '데이터 조회 중 오류가 발생했습니다' }, { status: 500 })
}
}
export const GET = loggerWrapper(getSubmissionAdmin)

View File

@ -1,7 +1,6 @@
import { prisma } from '@/libs/prisma'
import { SubmitTargetResponse } from '@/types/Survey'
import { NextRequest, NextResponse } from 'next/server'
import { loggerWrapper } from '@/libs/api-wrapper'
type BuilderPerson = {
agencyStoreId: string
@ -12,7 +11,7 @@ type BuilderPerson = {
// 2차점의 시공권한 user가 해당 판매점의 관리자 정보 조회
// N == 일반유저, S == 수퍼유저, B == 시공권한유저
async function getSubmissionBuilder(request: NextRequest): Promise<NextResponse> {
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url)
const id = searchParams.get('id')
@ -47,5 +46,3 @@ async function getSubmissionBuilder(request: NextRequest): Promise<NextResponse>
return NextResponse.json({ error: '데이터 조회 중 오류가 발생했습니다' }, { status: 500 })
}
}
export const GET = loggerWrapper(getSubmissionBuilder)

View File

@ -1,6 +1,5 @@
import { prisma } from '@/libs/prisma'
import { NextRequest, NextResponse } from 'next/server'
import { loggerWrapper } from '@/libs/api-wrapper'
type SuperPerson = {
storeId: string
@ -8,7 +7,7 @@ type SuperPerson = {
eMail: string
}
async function getSubmissionSuper(request: NextRequest): Promise<NextResponse> {
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url)
const id = searchParams.get('id')
@ -38,5 +37,3 @@ async function getSubmissionSuper(request: NextRequest): Promise<NextResponse> {
return NextResponse.json({ error: '데이터 조회 중 오류가 발생했습니다' }, { status: 500 })
}
}
export const GET = loggerWrapper(getSubmissionSuper)

View File

@ -1,6 +1,4 @@
import { NextRequest, NextResponse } from 'next/server'
import { HttpStatusCode } from 'axios'
import { loggerWrapper } from '@/libs/api-wrapper'
import { prisma } from '@/libs/prisma'
import { type Suitable } from '@/types/Suitable'
@ -43,7 +41,7 @@ import { type Suitable } from '@/types/Suitable'
* }
* ]
*/
async function getSuitableList(request: NextRequest): Promise<NextResponse> {
export async function GET(request: NextRequest) {
try {
const searchParams = request.nextUrl.searchParams
const pageNumber = parseInt(searchParams.get('pageNumber') || '0')
@ -53,7 +51,7 @@ async function getSuitableList(request: NextRequest): Promise<NextResponse> {
/* 파라미터 체크 */
if (pageNumber === 0 || itemPerPage === 0) {
return NextResponse.json({ error: '페이지 번호와 페이지당 아이템 수가 필요합니다' }, { status: HttpStatusCode.BadRequest })
return NextResponse.json({ error: '페이지 번호와 페이지당 아이템 수가 필요합니다' }, { status: 400 })
}
let query = `
@ -110,12 +108,9 @@ async function getSuitableList(request: NextRequest): Promise<NextResponse> {
headers: {
'spinner-state': 'true',
},
status: HttpStatusCode.Ok,
})
} catch (error) {
console.error(`데이터 조회 중 오류가 발생했습니다: ${error}`)
return NextResponse.json({ error: `데이터 조회 중 오류가 발생했습니다: ${error}` }, { status: HttpStatusCode.InternalServerError })
return NextResponse.json({ error: `데이터 조회 중 오류가 발생했습니다: ${error}` }, { status: 500 })
}
}
export const GET = loggerWrapper(getSuitableList)

View File

@ -1,9 +1,7 @@
import React from 'react'
import { NextRequest, NextResponse } from 'next/server'
import { HttpStatusCode } from 'axios'
import { pdf, Document } from '@react-pdf/renderer'
import { PDFDocument } from 'pdf-lib'
import { loggerWrapper } from '@/libs/api-wrapper'
import { prisma } from '@/libs/prisma'
import { type Suitable } from '@/types/Suitable'
import SuitablePdf from '@/components/pdf/SuitablePdf'
@ -30,7 +28,7 @@ import SuitablePdf from '@/components/pdf/SuitablePdf'
*
* @apiSuccess {File} PDF
*/
async function createSuitablePdf(request: NextRequest): Promise<NextResponse> {
export async function POST(request: NextRequest) {
const formData = await request.formData()
const ids = formData.get('ids') as string
const detailIds = formData.get('detailIds') as string
@ -38,7 +36,7 @@ async function createSuitablePdf(request: NextRequest): Promise<NextResponse> {
/* 파라미터 체크 */
if (ids === '' || detailIds === '' || fileTitle === '') {
return NextResponse.json({ error: '필수 파라미터가 누락되었습니다' }, { status: HttpStatusCode.BadRequest })
return NextResponse.json({ error: '필수 파라미터가 누락되었습니다' }, { status: 400 })
}
try {
@ -123,7 +121,7 @@ async function createSuitablePdf(request: NextRequest): Promise<NextResponse> {
})
} catch (error) {
console.error(`데이터 조회 중 오류가 발생했습니다: ${error}`)
return NextResponse.json({ error: `데이터 조회 중 오류가 발생했습니다: ${error}` }, { status: HttpStatusCode.InternalServerError })
return NextResponse.json({ error: `데이터 조회 중 오류가 발생했습니다: ${error}` }, { status: 500 })
}
}
@ -144,5 +142,3 @@ async function mergePdfBuffers(buffers: Uint8Array[]) {
const mergedPdfBytes = await mergedPdf.save()
return mergedPdfBytes
}
export const POST = loggerWrapper(createSuitablePdf)

View File

@ -1,25 +1,23 @@
import { NextRequest, NextResponse } from 'next/server'
import { HttpStatusCode } from 'axios'
import { loggerWrapper } from '@/libs/api-wrapper'
import { prisma } from '@/libs/prisma'
/**
* @api {get} /api/suitable/pick API
* @apiName GetSuitablePick
* @apiGroup Suitable
*
*
* @apiDescription
* main_id와 detail_id를
*
*
* @apiParam {String} [category] (: RMG001)
* @apiParam {String} [keyword]
*
*
* @apiExample {curl} Example usage:
* curl -X GET \
* -G "category=RMG001" \
* -G "keyword=검색키워드" \
* http://localhost:3000/api/suitable/pick
*
*
* @apiSuccess {Array} suitableIdSet
* @apiSuccessExample {json} Success-Response:
* [
@ -29,7 +27,7 @@ import { prisma } from '@/libs/prisma'
* }
* ]
*/
async function getSuitablePick(request: NextRequest): Promise<NextResponse> {
export async function GET(request: NextRequest) {
try {
const searchParams = request.nextUrl.searchParams
const category = searchParams.get('category')
@ -74,8 +72,6 @@ async function getSuitablePick(request: NextRequest): Promise<NextResponse> {
return NextResponse.json(suitableIdSet)
} catch (error) {
console.error(`데이터 조회 중 오류가 발생했습니다: ${error}`)
return NextResponse.json({ error: `데이터 조회 중 오류가 발생했습니다: ${error}` }, { status: HttpStatusCode.InternalServerError })
return NextResponse.json({ error: `데이터 조회 중 오류가 발생했습니다: ${error}` }, { status: 500 })
}
}
export const GET = loggerWrapper(getSuitablePick)

View File

@ -1,6 +1,4 @@
import { NextRequest, NextResponse } from 'next/server'
import { HttpStatusCode } from 'axios'
import { loggerWrapper } from '@/libs/api-wrapper'
import { prisma } from '@/libs/prisma'
import { Suitable } from '@/types/Suitable'
@ -42,7 +40,7 @@ import { Suitable } from '@/types/Suitable'
* }
* ]
*/
async function getSuitable(request: NextRequest): Promise<NextResponse> {
export async function POST(request: NextRequest) {
try {
const body: Record<string, string> = await request.json()
const ids = body.ids
@ -50,7 +48,7 @@ async function getSuitable(request: NextRequest): Promise<NextResponse> {
/* 파라미터 체크 */
if (ids === '') {
return NextResponse.json({ error: '필수 파라미터가 누락되었습니다' }, { status: HttpStatusCode.BadRequest })
return NextResponse.json({ error: '필수 파라미터가 누락되었습니다' }, { status: 400 })
}
let query = `
@ -98,8 +96,6 @@ async function getSuitable(request: NextRequest): Promise<NextResponse> {
return NextResponse.json(suitable)
} catch (error) {
console.error(`데이터 조회 중 오류가 발생했습니다: ${error}`)
return NextResponse.json({ error: `데이터 조회 중 오류가 발생했습니다: ${error}` }, { status: HttpStatusCode.InternalServerError })
return NextResponse.json({ error: `데이터 조회 중 오류가 발생했습니다: ${error}` }, { status: 500 })
}
}
export const POST = loggerWrapper(getSuitable)

View File

@ -6,7 +6,6 @@ import { sessionOptions } from '@/libs/session'
import { cookies } from 'next/headers'
import type { SessionData } from '@/types/Auth'
import { Prisma } from '@prisma/client'
import { loggerWrapper } from '@/libs/api-wrapper'
/**
* @description
@ -129,11 +128,11 @@ const fetchSurvey = async (id: number) => {
* ...
* }
*/
async function getSurveySaleDetail(request: NextRequest): Promise<NextResponse> {
export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
try {
const cookieStore = await cookies()
const session = await getIronSession<SessionData>(cookieStore, sessionOptions)
const id = request.nextUrl.pathname.split('/').pop() ?? ''
const { id } = await params
const { searchParams } = new URL(request.url)
const isPdf = searchParams.get('isPdf') === 'true'
@ -229,9 +228,9 @@ const getNewSrlNo = async (srlNo: string, storeId: string, role: string) => {
* ...
* }
* */
async function updateSurveySaleDetail(request: NextRequest): Promise<NextResponse> {
export async function PUT(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
try {
const id = request.nextUrl.pathname.split('/').pop() ?? ''
const { id } = await params
const body = await request.json()
const { detailInfo, ...basicInfo } = body.survey
@ -258,7 +257,6 @@ async function updateSurveySaleDetail(request: NextRequest): Promise<NextRespons
return NextResponse.json({ error: 'データ保存に失敗しました。' }, { status: 500 })
}
}
/**
* @api {DELETE} /api/survey-sales/:id API
* @apiName DELETE /api/survey-sales/:id
@ -277,9 +275,9 @@ async function updateSurveySaleDetail(request: NextRequest): Promise<NextRespons
* {
* "message": "success"
*/
async function deleteSurveySaleDetail(request: NextRequest): Promise<NextResponse> {
export async function DELETE(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
try {
const id = request.nextUrl.pathname.split('/').pop() ?? ''
const { id } = await params
await prisma.$transaction(async (tx: Prisma.TransactionClient) => {
// @ts-ignore
@ -345,9 +343,9 @@ async function deleteSurveySaleDetail(request: NextRequest): Promise<NextRespons
* }
* }
*/
async function submitSurveySaleDetail(request: NextRequest): Promise<NextResponse> {
export async function PATCH(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
try {
const id = request.nextUrl.pathname.split('/').pop() ?? ''
const { id } = await params
const body = await request.json()
// @ts-ignore
const survey = await prisma.SD_SURVEY_SALES_BASIC_INFO.update({
@ -366,8 +364,3 @@ async function submitSurveySaleDetail(request: NextRequest): Promise<NextRespons
return NextResponse.json({ error: 'データ保存に失敗しました。' }, { status: 500 })
}
}
export const GET = loggerWrapper(getSurveySaleDetail)
export const PUT = loggerWrapper(updateSurveySaleDetail)
export const DELETE = loggerWrapper(deleteSurveySaleDetail)
export const PATCH = loggerWrapper(submitSurveySaleDetail)

View File

@ -1,7 +1,6 @@
import { NextResponse } from 'next/server'
import { prisma } from '@/libs/prisma'
import { convertToSnakeCase } from '@/utils/common-utils'
import { loggerWrapper } from '@/libs/api-wrapper'
/**
* @description
*/
@ -193,7 +192,7 @@ const checkSession = (params: SearchParams) => {
* }
*
*/
async function getSurveySales(request: Request) {
export async function GET(request: Request) {
try {
/** URL 파라미터 파싱 */
const { searchParams } = new URL(request.url)
@ -274,7 +273,7 @@ async function getSurveySales(request: Request) {
*
* @apiError {Number} 500
*/
async function updateSurveySales(request: Request) {
export async function PUT(request: Request) {
try {
/** 요청 바디 파싱 */
const body = await request.json()
@ -336,7 +335,7 @@ async function updateSurveySales(request: Request) {
*
* @apiError {Number} 500
*/
async function createSurveySales(request: Request) {
export async function POST(request: Request) {
try {
const body = await request.json()
@ -394,7 +393,3 @@ async function createSurveySales(request: Request) {
return NextResponse.json({ error: 'データ保存に失敗しました。' }, { status: 500 })
}
}
export const GET = loggerWrapper(getSurveySales)
export const PUT = loggerWrapper(updateSurveySales)
export const POST = loggerWrapper(createSurveySales)

View File

@ -1,11 +1,5 @@
import { Metadata } from 'next'
import type { ReactNode } from 'react'
export const metadata: Metadata = {
title: 'HANASYS現地調査:お問い合わせ',
description: 'HANASYS現地調査:お問い合わせ',
}
export default function layout({ children }: { children: ReactNode }) {
return <div className="container">{children}</div>
}

View File

@ -13,8 +13,8 @@ import { sessionOptions } from '@/libs/session'
import '@/styles/style.scss'
export const metadata: Metadata = {
title: 'HANASYS現地調査',
description: 'HANASYS現地調査',
title: 'Create Next App',
description: 'Generated by create next app',
}
interface RootLayoutProps {

View File

@ -1,15 +1,9 @@
import { Metadata } from 'next'
import type { ReactNode } from 'react'
interface SuitableLayoutProps {
children: ReactNode
}
export const metadata: Metadata = {
title: 'HANASYS現地調査:屋根材積合成',
description: 'HANASYS現地調査:屋根材積合成',
}
export default function layout({ children }: SuitableLayoutProps) {
return (
<>

View File

@ -1,15 +1,9 @@
import { Metadata } from 'next'
import type { ReactNode } from 'react'
interface SurveySaleLayoutProps {
children: ReactNode
}
export const metadata: Metadata = {
title: 'HANASYS現地調査:調査物件',
description: 'HANASYS現地調査:調査物件',
}
export default function layout({ children }: SurveySaleLayoutProps) {
return (
<>

View File

@ -1,8 +1,7 @@
import getConfigs from '@/config/config.common'
// 환경마다 달라져야 할 변수, 값들을 정의합니다. (여기는 development 환경에 맞는 값을 지정합니다.)
// const baseUrl = 'http://172.16.56.60:3000'
const baseUrl = 'https://dev.hanasysfield.jp'
const baseUrl = 'http://1.248.227.176:3000'
const mode = 'development'
// 환경마다 달라져야 할 값들을 getConfig 함수에 전달합니다.

View File

@ -1,8 +1,7 @@
import getConfigs from '@/config/config.common'
// 환경마다 달라져야 할 변수, 값들을 정의합니다. (여기는 production 환경에 맞는 값을 지정합니다.)
const baseUrl = 'https://hanasysfield.jp'
// const baseUrl = 'http://172.16.56.55:3000'
const baseUrl = 'http://localhost.prod:3000'
const mode = 'production'
// 환경마다 달라져야 할 값들을 getConfig 함수에 전달합니다.

View File

@ -48,9 +48,7 @@ export function useInquiry(
*/
const errorRouter = (error: any) => {
const status = error.response?.status
if (error.response?.data.error) {
alert(error.response?.data.error)
}
alert(error.response?.data.error)
switch (status) {
// session 없는 경우
case 401:

View File

@ -108,9 +108,7 @@ export function useSurvey(
*/
const errorRouter = (error: any) => {
const status = error.response?.status
if (error.response?.data.error) {
alert(error.response?.data.error)
}
alert(error.response?.data.error)
switch (status) {
/** session 없는 경우 */
case 401:
@ -261,9 +259,6 @@ export function useSurvey(
queryClient.invalidateQueries({ queryKey: ['survey', id] })
queryClient.invalidateQueries({ queryKey: ['survey', 'list'] })
},
onError: (error: any) => {
alert(error.response?.data.error)
},
})
/**
@ -274,7 +269,7 @@ export function useSurvey(
*
* @example
*
*
*
*/
const { mutateAsync: deleteSurvey, isPending: isDeletingSurvey } = useMutation({
mutationFn: async () => {
@ -375,9 +370,8 @@ export function useSurvey(
`https://zipcloud.ibsnet.co.jp/api/search?${queryStringFormatter({ zipcode: zipCode.trim() })}`,
)
return data.results
} catch (error: any) {
console.error('Failed to fetch zipcode data:', error)
alert(error.response?.data.error)
} catch (e) {
console.error('Failed to fetch zipcode data:', e)
throw new Error('Failed to fetch zipcode data')
}
}

View File

@ -1,21 +0,0 @@
import { NextRequest, NextResponse } from 'next/server'
import { writeApiLog } from './logger'
export function loggerWrapper(handler: (req: NextRequest) => Promise<NextResponse>): (req: NextRequest) => Promise<NextResponse> {
return async function (req: NextRequest) {
const reqClone = req.clone()
const response = await handler(req)
await writeApiLog(
new NextRequest(req.url, {
method: req.method,
headers: req.headers,
body: reqClone.body ? await reqClone.text() : undefined,
}),
response.status,
)
return response
}
}

View File

@ -1,92 +0,0 @@
import { NextRequest } from 'next/server'
import { join } from 'path'
import pino from 'pino'
/* 로그 데이터 인터페이스 */
interface ApiLogData {
responseStatus: number
method: string
url: string
// headers: { [k: string]: string }
query: { [k: string]: string }
body: string | undefined
}
/* 날짜별 로그 파일 경로 생성 함수 */
const getLogFilePath = (): string => {
const today = new Date().toISOString().split('T')[0] // YYYY-MM-DD 형식
return join(process.cwd(), 'logs', `onsite-survey-${today}.log`)
}
/* 날짜별 로거 생성 클래스 */
class DailyLogger {
private currentDate: string
private logger: pino.Logger
private destination: ReturnType<typeof pino.destination>
constructor() {
this.currentDate = new Date().toISOString().split('T')[0]
this.destination = pino.destination({
dest: getLogFilePath(),
mkdir: true,
sync: false,
})
this.logger = this.createLogger()
/* kill signal 핸들러 등록 */
process.on('SIGTERM', this.handleShutdown.bind(this))
process.on('SIGINT', this.handleShutdown.bind(this))
}
private async handleShutdown(): Promise<void> {
this.destination.flushSync()
this.destination.end()
}
private createLogger(): pino.Logger {
return pino(
{
level: 'info',
timestamp: pino.stdTimeFunctions.isoTime,
},
this.destination,
)
}
public info(obj: any, msg?: string): void {
const today = new Date().toISOString().split('T')[0]
if (today !== this.currentDate) {
/* 기존 destination 종료 */
this.destination.flushSync()
this.destination.end()
/* 새로운 destination 생성 */
this.destination = pino.destination({
dest: getLogFilePath(),
mkdir: true,
sync: false,
})
this.currentDate = today
this.logger = this.createLogger()
}
this.logger.info(obj, msg)
}
}
/* 로거 인스턴스 */
const dailyLogger = new DailyLogger()
/* API 로그 기록 함수 */
export const writeApiLog = async (request: NextRequest, responseStatus: number): Promise<void> => {
const logData: ApiLogData = {
responseStatus: responseStatus,
method: request.method,
url: request.url,
// headers: Object.fromEntries(request.headers),
query: Object.fromEntries(new URL(request.url).searchParams),
body: request.body ? await request.text() : undefined,
}
dailyLogger.info(logData, 'API Request')
}