feat: modify inquriy create parameter

- 문의 등록 시 이메일 파라미터 추가
This commit is contained in:
Dayoung 2025-05-16 11:01:39 +09:00
parent 4d6f5c0e01
commit 7066d01060
10 changed files with 143 additions and 97 deletions

View File

@ -6,10 +6,19 @@ export async function GET(request: Request) {
const encodeFileNo = searchParams.get('encodeFileNo') const encodeFileNo = searchParams.get('encodeFileNo')
if (!encodeFileNo) { if (!encodeFileNo) {
return NextResponse.json({ error: 'fileNo is required' }, { status: 400 }) return NextResponse.json({ error: 'encodeFileNo is required' }, { status: 400 })
} }
const response = await axios.get(`${process.env.NEXT_PUBLIC_INQUIRY_API_URL}/api/file/downloadFile?encodeFileNo=${encodeFileNo}`) try {
console.log('response.data:: ', response.data) const response = await axios.get(`${process.env.NEXT_PUBLIC_INQUIRY_API_URL}/api/file/downloadFile`, {
params: {
encodeFileNo,
},
})
console.log('response.data:: ', response.data)
return NextResponse.json(response.data) return NextResponse.json(response.data)
} catch (error: any) {
console.error(error.response)
return NextResponse.json({ error: error.response.data }, { status: 500 })
}
} }

View File

@ -21,7 +21,6 @@ export async function GET(request: Request) {
if (response.status === 200) { if (response.status === 200) {
return NextResponse.json(response.data) return NextResponse.json(response.data)
} }
return NextResponse.json({ error: 'Failed to fetch qna list' }, { status: response.status }) return NextResponse.json({ error: 'Failed to fetch qna list' }, { status: response.status })
} catch (error: any) { } catch (error: any) {
console.error('Error fetching qna list:', error.response.data) console.error('Error fetching qna list:', error.response.data)

View File

@ -4,12 +4,9 @@ import { NextResponse } from 'next/server'
export async function POST(request: Request) { export async function POST(request: Request) {
const formData = await request.formData() const formData = await request.formData()
console.log('formData:: ', formData) console.log('formData:: ', formData)
// const body = await request.json()
// console.log('body:: ', body)
try { try {
const response = await axios.post(`${process.env.NEXT_PUBLIC_INQUIRY_API_URL}/api/qna/save`, formData) const response = await axios.post(`${process.env.NEXT_PUBLIC_INQUIRY_API_URL}/api/qna/save`, formData)
console.log('response.data:: ', response.data)
if (response.status === 200) { if (response.status === 200) {
return NextResponse.json(response.data) return NextResponse.json(response.data)

View File

@ -1,11 +1,9 @@
import ListForm from '@/components/inquiry/list/ListForm'
import ListTable from '@/components/inquiry/list/ListTable' import ListTable from '@/components/inquiry/list/ListTable'
export default function page() { export default function page() {
return ( return (
<> <>
<div className="sale-contents"> <div className="sale-contents">
<ListForm />
<ListTable /> <ListTable />
</div> </div>
</> </>

View File

@ -3,19 +3,13 @@
import Answer from './Answer' import Answer from './Answer'
import { useInquiry } from '@/hooks/useInquiry' import { useInquiry } from '@/hooks/useInquiry'
import { useParams, useRouter } from 'next/navigation' import { useParams, useRouter } from 'next/navigation'
import { useState } from 'react'
export default function Detail() { export default function Detail() {
//todo: 답변 완료 표시를 위해 임시로 추가 해 놓은 state
// 추후에 api 작업 완료후 삭제
// 답변 완료 클래스 & 하단 답변내용 출력도
const params = useParams() const params = useParams()
const id = params.id const id = params.id
const { inquiryDetail, downloadFile } = useInquiry(Number(id), '5200') const { inquiryDetail, downloadFile } = useInquiry(Number(id), '5200')
const router = useRouter() const router = useRouter()
const [inquiry, setInquiry] = useState<Boolean>(true)
return ( return (
<> <>
@ -39,15 +33,7 @@ export default function Detail() {
</tr> </tr>
<tr> <tr>
<th></th> <th></th>
<td>Hong gi</td> <td>{inquiryDetail?.regNm}</td>
</tr>
<tr>
<th></th>
<td>Kim</td>
</tr>
<tr>
<th></th>
<td>070-1234-5678</td>
</tr> </tr>
<tr> <tr>
<th></th> <th></th>
@ -66,17 +52,9 @@ export default function Detail() {
</div> </div>
<div className="inquiry-detail-data"> <div className="inquiry-detail-data">
<div className="inquiry-detail-category"> <div className="inquiry-detail-category">
<span></span> <span>{inquiryDetail?.qnaClsLrgCd}</span>
<span></span> <span>{inquiryDetail?.qnaClsMidCd}</span>
<span></span> <span>{inquiryDetail?.qnaClsSmlCd}</span>
</div>
<div className="inquiry-detail-tit"></div>
<div className="inquiry-detail-txt">
.
<br />
.
<br />
.
</div> </div>
<div className="inquiry-detail-tit">{inquiryDetail?.qstTitle}</div> <div className="inquiry-detail-tit">{inquiryDetail?.qstTitle}</div>
<div className="inquiry-detail-txt">{inquiryDetail?.qstContents}</div> <div className="inquiry-detail-txt">{inquiryDetail?.qstContents}</div>
@ -91,6 +69,11 @@ export default function Detail() {
</button> </button>
</li> </li>
))} ))}
<li className="file-item">
<button className="file-item-bx" onClick={() => downloadFile(Number(1))}>
<div className="file-item-name">Test File</div>
</button>
</li>
</ul> </ul>
</div> </div>
</div> </div>

View File

@ -4,7 +4,7 @@ import { useInquiry } from '@/hooks/useInquiry'
import { useSessionStore } from '@/store/session' import { useSessionStore } from '@/store/session'
import { InquiryRequest } from '@/types/Inquiry' import { InquiryRequest } from '@/types/Inquiry'
import { useEffect, useState } from 'react' import { useState } from 'react'
import { useRouter } from 'next/navigation' import { useRouter } from 'next/navigation'
export default function RegistForm() { export default function RegistForm() {
const { saveInquiry, isSavingInquiry } = useInquiry() const { saveInquiry, isSavingInquiry } = useInquiry()
@ -20,14 +20,15 @@ export default function RegistForm() {
compCd: '5200', compCd: '5200',
siteTpCd: 'QC', siteTpCd: 'QC',
qnaClsLrgCd: '', qnaClsLrgCd: '',
qnaClsMidCd: 'B02', qnaClsMidCd: '',
qnaClsSmlCd: null, qnaClsSmlCd: null,
title: '', title: '',
contents: null, contents: '',
regId: 'X112', regId: 'X112',
regUserNm: 'TEST', regUserNm: 'TEST',
regUserTelNo: null, regUserTelNo: null,
storeId: null, storeId: 'X112',
qstMail: '',
}) })
const [attachedFiles, setAttachedFiles] = useState<File[]>([]) const [attachedFiles, setAttachedFiles] = useState<File[]>([])
@ -45,12 +46,30 @@ export default function RegistForm() {
} }
const handleSubmit = async () => { const handleSubmit = async () => {
if (confirm('お問い合わせを登録しますか? Hanwha Japanの担当者にお問い合わせメールが送信されます。')) { const formData = new FormData()
const res = await saveInquiry({ inquiryRequest, files: attachedFiles }) attachedFiles.forEach((file) => {
alert('保存されました。') formData.append('files', file)
router.push(`/inquiry/${res.qnaNo}`) })
} Object.entries(inquiryRequest).forEach(([key, value]) => {
return formData.append(key, value ?? '')
})
// FormData를 객체로 변환하여 확인
const formDataObj: Record<string, any> = {}
formData.forEach((value, key) => {
formDataObj[key] = value
})
console.log('formData contents:', formDataObj)
window.neoConfirm(
'お問い合わせを登録しますか? Hanwha Japanの担当者にお問い合わせメールが送信されます。',
async () => {
const res = await saveInquiry(formData)
alert('保存されました。')
router.push(`/inquiry/${res.qnaNo}`)
},
() => null,
)
} }
return ( return (
@ -62,30 +81,42 @@ export default function RegistForm() {
<i className="import">*</i> <i className="import">*</i>
</div> </div>
<div className="data-input"> <div className="data-input">
<select className="select-form" name="" id=""> <select
<option value=""></option> className="select-form"
<option value=""></option> name=""
<option value=""></option> id="qnaClsLrgCd"
<option value=""></option> value={inquiryRequest.qnaClsLrgCd}
<option value=""></option> onChange={(e) => setInquiryRequest({ ...inquiryRequest, qnaClsLrgCd: e.target.value })}
>
<option value=""></option>
<option value="A01">A01</option>
<option value="A01"></option>
</select> </select>
</div> </div>
<div className="data-input mt5"> <div className="data-input mt5">
<select className="select-form" name="" id=""> <select
<option value=""></option> className="select-form"
<option value=""></option> name=""
<option value=""></option> id="qnaClsMidCd"
<option value=""></option> value={inquiryRequest.qnaClsMidCd}
<option value=""></option> onChange={(e) => setInquiryRequest({ ...inquiryRequest, qnaClsMidCd: e.target.value })}
>
<option value=""></option>
<option value="B02">B02</option>
<option value="B02"></option>
</select> </select>
</div> </div>
<div className="data-input mt5"> <div className="data-input mt5">
<select className="select-form" name="" id=""> <select
<option value=""></option> className="select-form"
<option value=""></option> name=""
<option value=""></option> id="qnaClsSmlCd"
<option value=""></option> value={inquiryRequest.qnaClsSmlCd ?? ''}
<option value=""></option> onChange={(e) => setInquiryRequest({ ...inquiryRequest, qnaClsSmlCd: e.target.value })}
>
<option value=""></option>
<option value="C05">C05</option>
<option value="C05"></option>
</select> </select>
</div> </div>
</div> </div>
@ -94,27 +125,36 @@ export default function RegistForm() {
<i className="import">*</i> <i className="import">*</i>
</div> </div>
<div className="data-input"> <div className="data-input">
<input className="input-frame" type="text" placeholder="名前を書いてください" /> <input
className="input-frame"
type="text"
placeholder="名前を書いてください"
onChange={(e) => setInquiryRequest({ ...inquiryRequest, regUserNm: e.target.value })}
/>
</div> </div>
</div> </div>
<div className="data-input-form-bx"> <div className="data-input-form-bx">
<div className="data-input-form-tit"></div> <div className="data-input-form-tit"></div>
<div className="data-input"> <div className="data-input">
<input className="input-frame" type="text" placeholder="電話番号を書き留めてください" /> <input
className="input-frame"
type="text"
placeholder="電話番号を書き留めてください"
onChange={(e) => setInquiryRequest({ ...inquiryRequest, regUserTelNo: e.target.value })}
/>
</div> </div>
</div> </div>
<div className="data-input-form-bx"> <div className="data-input-form-bx">
<div className="data-input-form-tit"> <div className="data-input-form-tit">
<i className="import">*</i> E-mail <i className="import">*</i>
</div> </div>
<div className="data-input"> <div className="data-input">
<input className="input-frame" type="text" placeholder="名前を書いてください" /> <input
</div> className="input-frame"
</div> type="text"
<div className="data-input-form-bx"> placeholder="E-mailを書いてください"
<div className="data-input-form-tit"></div> onChange={(e) => setInquiryRequest({ ...inquiryRequest, qstMail: e.target.value })}
<div className="data-input"> />
<input className="input-frame" type="text" placeholder="電話番号を書き留めてください" />
</div> </div>
</div> </div>
<div className="data-input-form-bx"> <div className="data-input-form-bx">
@ -122,7 +162,12 @@ export default function RegistForm() {
<i className="import">*</i> <i className="import">*</i>
</div> </div>
<div className="data-input"> <div className="data-input">
<input className="input-frame" type="text" placeholder="お問い合わせタイトルを記入してください" /> <input
className="input-frame"
type="text"
placeholder="お問い合わせタイトルを記入してください"
onChange={(e) => setInquiryRequest({ ...inquiryRequest, title: e.target.value })}
/>
</div> </div>
</div> </div>
<div className="data-input-form-bx"> <div className="data-input-form-bx">

View File

@ -5,8 +5,8 @@ import { useState } from 'react'
export default function ListForm() { export default function ListForm() {
const router = useRouter() const router = useRouter()
const [searchKeyword, setSearchKeyword] = useState('')
const { inquiryListRequest, setInquiryListRequest } = useInquiryFilterStore() const { inquiryListRequest, setInquiryListRequest } = useInquiryFilterStore()
const [searchKeyword, setSearchKeyword] = useState(inquiryListRequest.schTitle ?? '')
const handleSearch = () => { const handleSearch = () => {
if (searchKeyword.length >= 2) { if (searchKeyword.length >= 2) {

View File

@ -7,6 +7,7 @@ import { InquiryList } from '@/types/Inquiry'
import { useRouter } from 'next/navigation' import { useRouter } from 'next/navigation'
import { useInquiryFilterStore } from '@/store/inquiryFilterStore' import { useInquiryFilterStore } from '@/store/inquiryFilterStore'
import { useSessionStore } from '@/store/session' import { useSessionStore } from '@/store/session'
import ListForm from './ListForm'
const badgeStyle = [ const badgeStyle = [
{ {
@ -29,14 +30,23 @@ export default function ListTable() {
const { inquiryList } = useInquiry() const { inquiryList } = useInquiry()
const { inquiryListRequest, setInquiryListRequest } = useInquiryFilterStore() const { inquiryListRequest, setInquiryListRequest } = useInquiryFilterStore()
const [heldInquiryList, setHeldInquiryList] = useState<typeof inquiryList>([])
const { session } = useSessionStore() const { session } = useSessionStore()
useEffect(() => { useEffect(() => {
if (inquiryList.length !== 0) { if (inquiryList.length > 0) {
const hasMoreItems = inquiryList[0].totCnt > offset + 10 if (offset === 0) {
setHasMore(hasMoreItems) setHeldInquiryList(inquiryList)
} else {
const remainingList = heldInquiryList.slice(offset, offset + 10)
if (JSON.stringify(remainingList) !== JSON.stringify(inquiryList)) {
setHeldInquiryList((prev) => [...prev, ...inquiryList])
}
}
setHasMore(inquiryList.length > offset + 10)
} else { } else {
setHasMore(false) setHeldInquiryList([])
} }
}, [inquiryList, offset]) }, [inquiryList, offset])
@ -49,8 +59,19 @@ export default function ListTable() {
setInquiryListRequest({ ...inquiryListRequest, startRow: offset, endRow: offset + 10 }) setInquiryListRequest({ ...inquiryListRequest, startRow: offset, endRow: offset + 10 })
} }
const handleFilter = (e: React.ChangeEvent<HTMLSelectElement>) => {
console.log(e.target.value)
setHeldInquiryList(inquiryList.filter((inquiry: InquiryList) => inquiry.answerYn === e.target.value))
if (e.target.value === '') {
setHeldInquiryList(inquiryList)
}
}
console.log('heldInquiryList:: ', heldInquiryList)
return ( return (
<> <>
<ListForm />
<div className="sale-frame"> <div className="sale-frame">
<div className="inquiry-table-filter"> <div className="inquiry-table-filter">
<div className="filter-check"> <div className="filter-check">
@ -60,7 +81,7 @@ export default function ListTable() {
</div> </div>
</div> </div>
<div className="filter-select"> <div className="filter-select">
<select className="select-form" name="" id=""> <select className="select-form" name="" id="" onChange={(e) => handleFilter(e)}>
<option value=""></option> <option value=""></option>
<option value="N"></option> <option value="N"></option>
<option value="Y"></option> <option value="Y"></option>
@ -69,11 +90,11 @@ export default function ListTable() {
</div> </div>
<div className="inquiry-list-wrap"> <div className="inquiry-list-wrap">
<div className="inquiry-list-tit"> <div className="inquiry-list-tit">
<span>{inquiryList.length}</span> <span>{heldInquiryList.length > 0 ? heldInquiryList[0].totCnt : 0}</span>
</div> </div>
<ul className="inquiry-list"> <ul className="inquiry-list">
{inquiryList.length > 0 && {heldInquiryList.length > 0 &&
inquiryList.map((inquiry: InquiryList) => ( heldInquiryList.map((inquiry: InquiryList) => (
<li className="inquiry-item" key={inquiry.qnaNo} onClick={() => router.push(`/inquiry/${inquiry.qnaNo}`)}> <li className="inquiry-item" key={inquiry.qnaNo} onClick={() => router.push(`/inquiry/${inquiry.qnaNo}`)}>
<div className="inquiry-item-bx"> <div className="inquiry-item-bx">
<div className="inquiry-item-category">{inquiry.qnaClsLrgCd}</div> <div className="inquiry-item-category">{inquiry.qnaClsLrgCd}</div>

View File

@ -12,10 +12,10 @@ export function useInquiry(
inquiryDetail: Inquiry | null inquiryDetail: Inquiry | null
isLoadingInquiryDetail: boolean isLoadingInquiryDetail: boolean
isSavingInquiry: boolean isSavingInquiry: boolean
saveInquiry: (params: { inquiryRequest: InquiryRequest; files: File[] }) => Promise<InquirySaveResponse> saveInquiry: (formData: FormData) => Promise<InquirySaveResponse>
downloadFile: (encodeFileNo: number) => Promise<File> downloadFile: (encodeFileNo: number) => Promise<File>
} { } {
const { session } = useSessionStore() // const { session } = useSessionStore()
const queryClient = useQueryClient() const queryClient = useQueryClient()
const { inquiryListRequest } = useInquiryFilterStore() const { inquiryListRequest } = useInquiryFilterStore()
@ -41,6 +41,7 @@ export function useInquiry(
const resp = await axiosInstance(null).get<{ data: Inquiry }>(`/api/qna/detail`, { const resp = await axiosInstance(null).get<{ data: Inquiry }>(`/api/qna/detail`, {
params: { qnoNo, compCd, langCd: 'JA', loginId: 'x112' }, params: { qnoNo, compCd, langCd: 'JA', loginId: 'x112' },
}) })
console.log('resp.data.data:: ', resp.data.data)
return resp.data.data return resp.data.data
} catch (error: any) { } catch (error: any) {
console.error(error.response) console.error(error.response)
@ -51,15 +52,7 @@ export function useInquiry(
}) })
const { mutateAsync: saveInquiry, isPending: isSavingInquiry } = useMutation({ const { mutateAsync: saveInquiry, isPending: isSavingInquiry } = useMutation({
mutationFn: async ({ inquiryRequest, files }: { inquiryRequest: InquiryRequest; files: File[] }) => { mutationFn: async (formData: FormData) => {
const formData = new FormData()
Object.entries(inquiryRequest).forEach(([key, value]) => {
formData.append(key, value ?? '')
})
files.forEach((file) => {
formData.append('files', file)
})
const resp = await axiosInstance(null).post<{ data: InquirySaveResponse }>('/api/qna/save', formData) const resp = await axiosInstance(null).post<{ data: InquirySaveResponse }>('/api/qna/save', formData)
return resp.data.data return resp.data.data
}, },

View File

@ -75,11 +75,12 @@ export type InquiryRequest = {
qnaClsMidCd: string //qna CLS Mid Code qnaClsMidCd: string //qna CLS Mid Code
qnaClsSmlCd: string | null //qna CLS Small Code qnaClsSmlCd: string | null //qna CLS Small Code
title: string //title title: string //title
contents: string | null //contents contents: string //contents
regId: string //registration Userid regId: string //registration Userid
storeId: string | null //store id storeId: string //store id
regUserNm: string //registration User name regUserNm: string //registration User name
regUserTelNo: string | null //registration User tel number regUserTelNo: string | null //registration User tel number
qstMail: string //mail
} }
export type InquirySaveResponse = { export type InquirySaveResponse = {