feat: implement inquiry create, read function with Qcast API
This commit is contained in:
parent
8ad1ed4bcf
commit
32a8ec72ef
@ -7,4 +7,6 @@ NEXT_PUBLIC_API_URL=http://localhost:3000
|
|||||||
NEXT_PUBLIC_QSP_API_URL=http://1.248.227.176:8120
|
NEXT_PUBLIC_QSP_API_URL=http://1.248.227.176:8120
|
||||||
|
|
||||||
#1:1문의 api
|
#1:1문의 api
|
||||||
NEXT_PUBLIC_INQUIRY_API_URL=http://1.248.227.176:38080
|
NEXT_PUBLIC_INQUIRY_API_URL=http://172.23.4.129:8110
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -5,4 +5,5 @@ NEXT_PUBLIC_API_URL=http://172.30.1.35:3000
|
|||||||
NEXT_PUBLIC_QSP_API_URL=http://1.248.227.176:8120
|
NEXT_PUBLIC_QSP_API_URL=http://1.248.227.176:8120
|
||||||
|
|
||||||
#1:1문의 api
|
#1:1문의 api
|
||||||
NEXT_PUBLIC_INQUIRY_API_URL=http://1.248.227.176:38080
|
# NEXT_PUBLIC_INQUIRY_API_URL=http://1.248.227.176:38080
|
||||||
|
NEXT_PUBLIC_INQUIRY_API_URL=http://172.23.4.129:8110
|
||||||
|
|||||||
@ -2,14 +2,23 @@ import { queryStringFormatter } from '@/utils/common-utils'
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { NextResponse } from 'next/server'
|
import { NextResponse } from 'next/server'
|
||||||
|
|
||||||
export const QSP_URL = 'http://localhost:8080'
|
|
||||||
export async function GET(request: Request) {
|
export async function GET(request: Request) {
|
||||||
const body = await request.json()
|
const { searchParams } = new URL(request.url)
|
||||||
|
const params = {
|
||||||
const response = await axios.get(`${QSP_URL}/qna/detail?${queryStringFormatter(body)}`)
|
compCd: searchParams.get('compCd'),
|
||||||
|
qnoNo: searchParams.get('qnoNo'),
|
||||||
|
langCd: searchParams.get('langCd'),
|
||||||
|
loginId: searchParams.get('loginId'),
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`${process.env.NEXT_PUBLIC_INQUIRY_API_URL}/api/qna/detail?${queryStringFormatter(params)}`)
|
||||||
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 detail' }, { status: response.status })
|
return NextResponse.json({ error: response.data.result }, { status: response.status })
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error(error.response)
|
||||||
|
return NextResponse.json({ error: 'route error' }, { status: 500 })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,17 +1,30 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { NextResponse } from 'next/server'
|
import { NextResponse } from 'next/server'
|
||||||
import { queryStringFormatter } from '@/utils/common-utils'
|
import { queryStringFormatter } from '@/utils/common-utils'
|
||||||
import { QSP_URL } from '../detail/route'
|
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
export async function GET(request: Request) {
|
||||||
const { searchParams } = new URL(request.url)
|
const { searchParams } = new URL(request.url)
|
||||||
console.log('searchParams::: ', searchParams)
|
|
||||||
|
|
||||||
const response = await axios.get(`${QSP_URL}/qna/list?${queryStringFormatter(searchParams)}`)
|
const params: Record<string, string> = {}
|
||||||
|
searchParams.forEach((value, key) => {
|
||||||
|
const match = key.match(/inquiryListRequest\[(.*)\]/)
|
||||||
|
if (match) {
|
||||||
|
params[match[1]] = value
|
||||||
|
} else {
|
||||||
|
params[key] = value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`${process.env.NEXT_PUBLIC_INQUIRY_API_URL}/api/qna/list?${queryStringFormatter(params)}`)
|
||||||
|
|
||||||
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) {
|
||||||
|
console.error('Error fetching qna list:', error.response.data)
|
||||||
|
return NextResponse.json({ error: 'route error' }, { status: 500 })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { NextResponse } from 'next/server'
|
import { NextResponse } from 'next/server'
|
||||||
import { QSP_URL } from '../detail/route'
|
|
||||||
|
|
||||||
export async function POST(request: Request) {
|
export async function POST(request: Request) {
|
||||||
const body = await request.json()
|
const body = await request.json()
|
||||||
|
|
||||||
const response = await axios.post(`${QSP_URL}/qna/save`, body)
|
const response = await axios.post(`${process.env.NEXT_PUBLIC_INQUIRY_API_URL}/api/qna/save`, body)
|
||||||
|
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
return NextResponse.json(response.data)
|
return NextResponse.json(response.data)
|
||||||
|
|||||||
@ -1,15 +1,18 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useState } from 'react'
|
|
||||||
import Answer from './Answer'
|
import Answer from './Answer'
|
||||||
import { useInquiry } from '@/hooks/useInquiry'
|
import { useInquiry } from '@/hooks/useInquiry'
|
||||||
import { useRouter } from 'next/navigation'
|
import { useParams, useRouter } from 'next/navigation'
|
||||||
|
|
||||||
export default function Detail() {
|
export default function Detail() {
|
||||||
//todo: 답변 완료 표시를 위해 임시로 추가 해 놓은 state
|
//todo: 답변 완료 표시를 위해 임시로 추가 해 놓은 state
|
||||||
// 추후에 api 작업 완료후 삭제
|
// 추후에 api 작업 완료후 삭제
|
||||||
// 답변 완료 클래스 & 하단 답변내용 출력도
|
// 답변 완료 클래스 & 하단 답변내용 출력도
|
||||||
const { inquiryDetail } = useInquiry()
|
|
||||||
|
const params = useParams()
|
||||||
|
const id = params.id
|
||||||
|
|
||||||
|
const { inquiryDetail } = useInquiry(Number(id), '5200')
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -17,7 +20,9 @@ export default function Detail() {
|
|||||||
<div className="inquiry-frame">
|
<div className="inquiry-frame">
|
||||||
<div className="inquiry-detail-wrap">
|
<div className="inquiry-detail-wrap">
|
||||||
<div className="inquiry-detail-badge">
|
<div className="inquiry-detail-badge">
|
||||||
<div className={`badge ${inquiryDetail?.answerYn === 'Y' ? 'orange' : 'blue'} block`}>回答完了</div>
|
<div className={`badge ${inquiryDetail?.answerYn === 'Y' ? 'orange' : 'blue'} block`}>
|
||||||
|
{inquiryDetail?.answerYn === 'Y' ? '回答完了' : '回答待ち'}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="inquiry-detail-data-table">
|
<div className="inquiry-detail-data-table">
|
||||||
<table className="sale-data-table">
|
<table className="sale-data-table">
|
||||||
@ -50,9 +55,11 @@ export default function Detail() {
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div className="inquiry-detail-data">
|
<div className="inquiry-detail-data">
|
||||||
<div className="inquiry-detail-category">屋根適合</div>
|
<div className="inquiry-detail-category">
|
||||||
|
{inquiryDetail?.qnaClsLrgCd} - {inquiryDetail?.qnaClsMidCd}
|
||||||
|
</div>
|
||||||
<div className="inquiry-detail-tit">{inquiryDetail?.qstTitle}</div>
|
<div className="inquiry-detail-tit">{inquiryDetail?.qstTitle}</div>
|
||||||
<div className="inquiry-detail-txt">{inquiryDetail?.qstContent}</div>
|
<div className="inquiry-detail-txt">{inquiryDetail?.qstContents}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="file-list-wrap">
|
<div className="file-list-wrap">
|
||||||
<div className="file-list-tit">ファイル添付</div>
|
<div className="file-list-tit">ファイル添付</div>
|
||||||
@ -68,7 +75,7 @@ export default function Detail() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{inquiryDetail?.answerYn === 'Y' && <Answer inquiryDetail={inquiryDetail} />}
|
{inquiryDetail?.answerYn === 'Y' && inquiryDetail && <Answer inquiryDetail={inquiryDetail} />}
|
||||||
|
|
||||||
<div className="sale-edit-btn">
|
<div className="sale-edit-btn">
|
||||||
<button className="btn-frame n-blue icon" onClick={() => router.push('/inquiry/list')}>
|
<button className="btn-frame n-blue icon" onClick={() => router.push('/inquiry/list')}>
|
||||||
|
|||||||
@ -1,5 +1,58 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
|
import { useInquiry } from '@/hooks/useInquiry'
|
||||||
|
import { useSessionStore } from '@/store/session'
|
||||||
|
import { InquiryRequest } from '@/types/Inquiry'
|
||||||
|
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { useRouter } from 'next/navigation'
|
||||||
export default function RegistForm() {
|
export default function RegistForm() {
|
||||||
|
const { saveInquiry, isSavingInquiry } = useInquiry()
|
||||||
|
const { session } = useSessionStore()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
/// TODO: 세션 정보 적용
|
||||||
|
// useEffect(() => {
|
||||||
|
// setInquiryRequest({ ...inquiryRequest, regId: session?.userId ?? '', regUserNm: session?.userNm ?? '' })
|
||||||
|
// }, [session])
|
||||||
|
|
||||||
|
const [inquiryRequest, setInquiryRequest] = useState<InquiryRequest>({
|
||||||
|
compCd: '5200',
|
||||||
|
siteTpCd: 'QC',
|
||||||
|
qnaClsLrgCd: '',
|
||||||
|
qnaClsMidCd: 'B02',
|
||||||
|
qnaClsSmlCd: null,
|
||||||
|
title: '',
|
||||||
|
contents: null,
|
||||||
|
regId: '',
|
||||||
|
regUserNm: 'TEST',
|
||||||
|
regUserTelNo: null,
|
||||||
|
storeId: null,
|
||||||
|
})
|
||||||
|
|
||||||
|
const [attachedFiles, setAttachedFiles] = useState<File[]>([])
|
||||||
|
|
||||||
|
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const files = e.target.files
|
||||||
|
if (files && files.length > 0) {
|
||||||
|
setAttachedFiles(attachedFiles.concat(Array.from(files)))
|
||||||
|
}
|
||||||
|
e.target.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRemoveFile = (index: number) => {
|
||||||
|
setAttachedFiles(attachedFiles.filter((_, i) => i !== index))
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (confirm('お問い合わせを登録しますか? Hanwha Japanの担当者にお問い合わせメールが送信されます。')) {
|
||||||
|
const res = await saveInquiry(inquiryRequest)
|
||||||
|
alert('保存されました。')
|
||||||
|
router.push(`/inquiry/${res.qnaNo}`)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="inquiry-frame">
|
<div className="inquiry-frame">
|
||||||
@ -9,12 +62,21 @@ 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="qnaClsLrgCd"
|
||||||
<option value="">屋根適合</option>
|
id="qnaClsLrgCd"
|
||||||
<option value="">屋根適合</option>
|
defaultValue=""
|
||||||
<option value="">屋根適合</option>
|
onChange={(e) => setInquiryRequest({ ...inquiryRequest, qnaClsLrgCd: e.target.value })}
|
||||||
|
>
|
||||||
|
<option value="" hidden>
|
||||||
|
選択してください
|
||||||
|
</option>
|
||||||
|
<option value="A01">A01</option>
|
||||||
|
<option value="A02">A02</option>
|
||||||
|
<option value="A03">A03</option>
|
||||||
|
<option value="A04">A04</option>
|
||||||
|
<option value="A05">A05</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -23,12 +85,19 @@ 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="title"
|
||||||
<option value="">モジュールの取り付けを確認するかどうか</option>
|
id="title"
|
||||||
<option value="">モジュールの取り付けを確認するかどうか</option>
|
onChange={(e) => setInquiryRequest({ ...inquiryRequest, title: e.target.value })}
|
||||||
<option value="">モジュールの取り付けを確認するかどうか</option>
|
>
|
||||||
|
<option value="" hidden>
|
||||||
|
選択してください
|
||||||
|
</option>
|
||||||
|
<option value="TEST">TEST</option>
|
||||||
|
<option value="TEST2">TEST2</option>
|
||||||
|
<option value="TEST3">TEST3</option>
|
||||||
|
<option value="TEST4">TEST4</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -37,7 +106,14 @@ export default function RegistForm() {
|
|||||||
お問い合わせタイプ <i className="import">*</i>
|
お問い合わせタイプ <i className="import">*</i>
|
||||||
</div>
|
</div>
|
||||||
<div className="data-input">
|
<div className="data-input">
|
||||||
<textarea className="textarea-form" rows={6} name="" id="" placeholder="TextArea Filed"></textarea>
|
<textarea
|
||||||
|
className="textarea-form"
|
||||||
|
rows={6}
|
||||||
|
name=""
|
||||||
|
id=""
|
||||||
|
placeholder="TextArea Filed"
|
||||||
|
onChange={(e) => setInquiryRequest({ ...inquiryRequest, contents: e.target.value })}
|
||||||
|
></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -46,29 +122,25 @@ export default function RegistForm() {
|
|||||||
<label className="btn-frame l-blue icon" htmlFor="file">
|
<label className="btn-frame l-blue icon" htmlFor="file">
|
||||||
<i className="btn-clip"></i>Attach ファイル
|
<i className="btn-clip"></i>Attach ファイル
|
||||||
</label>
|
</label>
|
||||||
<input type="file" id="file" />
|
<input type="file" id="file" onChange={handleFileChange} multiple style={{ display: 'none' }} />
|
||||||
</div>
|
</div>
|
||||||
<div className="file-list-wrap">
|
<div className="file-list-wrap">
|
||||||
<div className="file-list-tit">
|
<div className="file-list-tit">
|
||||||
添付ファイル<span>2</span>個
|
添付ファイル<span>{attachedFiles.length}</span>個
|
||||||
</div>
|
</div>
|
||||||
<ul className="file-list">
|
<ul className="file-list">
|
||||||
<li className="file-item">
|
{attachedFiles.map((file, index) => (
|
||||||
|
<li className="file-item" key={`${file.name}-${index}`}>
|
||||||
<div className="file-item-bx">
|
<div className="file-item-bx">
|
||||||
<div className="file-item-name">添付ファイル名.jpg </div>
|
<div className="file-item-name">{file.name}</div>
|
||||||
<button className="file-del"></button>
|
<button className="file-del" onClick={() => handleRemoveFile(index)} aria-label="Remove file" />
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li className="file-item">
|
|
||||||
<div className="file-item-bx">
|
|
||||||
<div className="file-item-name">添付ファイル名.jpg </div>
|
|
||||||
<button className="file-del"></button>
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div className="sale-edit-btn">
|
<div className="sale-edit-btn">
|
||||||
<button className="btn-frame n-blue icon">
|
<button className="btn-frame n-blue icon" onClick={handleSubmit} disabled={isSavingInquiry}>
|
||||||
登録<i className="btn-arr"></i>
|
登録<i className="btn-arr"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,8 +1,25 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
import { useInquiryFilterStore } from '@/store/inquiryFilterStore'
|
||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
|
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 handleSearch = () => {
|
||||||
|
if (searchKeyword.length >= 2) {
|
||||||
|
setInquiryListRequest({ ...inquiryListRequest, schTitle: searchKeyword })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
handleSearch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="sale-frame">
|
<div className="sale-frame">
|
||||||
@ -13,8 +30,15 @@ export default function ListForm() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="sale-form-bx">
|
<div className="sale-form-bx">
|
||||||
<div className="search-input">
|
<div className="search-input">
|
||||||
<input type="text" className="search-frame" placeholder="タイトルを入力してください. (2文字以上)" />
|
<input
|
||||||
<button className="search-icon"></button>
|
type="text"
|
||||||
|
className="search-frame"
|
||||||
|
placeholder="タイトルを入力してください. (2文字以上)"
|
||||||
|
value={searchKeyword}
|
||||||
|
onChange={(e) => setSearchKeyword(e.target.value)}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
/>
|
||||||
|
<button className="search-icon" onClick={handleSearch}></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -4,6 +4,9 @@ import { useEffect, useState } from 'react'
|
|||||||
import LoadMoreButton from '../../LoadMoreButton'
|
import LoadMoreButton from '../../LoadMoreButton'
|
||||||
import { useInquiry } from '@/hooks/useInquiry'
|
import { useInquiry } from '@/hooks/useInquiry'
|
||||||
import { InquiryList } from '@/types/Inquiry'
|
import { InquiryList } from '@/types/Inquiry'
|
||||||
|
import { useRouter } from 'next/navigation'
|
||||||
|
import { useInquiryFilterStore } from '@/store/inquiryFilterStore'
|
||||||
|
import { useSessionStore } from '@/store/session'
|
||||||
|
|
||||||
const badgeStyle = [
|
const badgeStyle = [
|
||||||
{
|
{
|
||||||
@ -21,14 +24,30 @@ export default function ListTable() {
|
|||||||
const [offset, setOffset] = useState(0)
|
const [offset, setOffset] = useState(0)
|
||||||
const [hasMore, setHasMore] = useState(true)
|
const [hasMore, setHasMore] = useState(true)
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
const { inquiryList } = useInquiry()
|
const { inquiryList } = useInquiry()
|
||||||
|
const { inquiryListRequest, setInquiryListRequest } = useInquiryFilterStore()
|
||||||
|
|
||||||
|
const { session } = useSessionStore()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (inquiryList.length > offset + 10) {
|
if (inquiryList.length !== 0) {
|
||||||
setHasMore(true)
|
const hasMoreItems = inquiryList[0].totCnt > offset + 10
|
||||||
|
setHasMore(hasMoreItems)
|
||||||
} else {
|
} else {
|
||||||
setHasMore(false)
|
setHasMore(false)
|
||||||
}
|
}
|
||||||
}, [inquiryList])
|
}, [inquiryList, offset])
|
||||||
|
|
||||||
|
const handleMyInquiry = () => {
|
||||||
|
setInquiryListRequest({ ...inquiryListRequest, schRegId: inquiryListRequest.schRegId ? null : session.userId })
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleLoadMore = () => {
|
||||||
|
setOffset(offset + 10)
|
||||||
|
setInquiryListRequest({ ...inquiryListRequest, startRow: offset, endRow: offset + 10 })
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -36,7 +55,7 @@ export default function ListTable() {
|
|||||||
<div className="inquiry-table-filter">
|
<div className="inquiry-table-filter">
|
||||||
<div className="filter-check">
|
<div className="filter-check">
|
||||||
<div className="check-form-box">
|
<div className="check-form-box">
|
||||||
<input type="checkbox" id="ch01" />
|
<input type="checkbox" id="ch01" onChange={handleMyInquiry} />
|
||||||
<label htmlFor="ch01">私が書いたお問い合わせ</label>
|
<label htmlFor="ch01">私が書いたお問い合わせ</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -53,10 +72,11 @@ export default function ListTable() {
|
|||||||
合計 <span>{inquiryList.length}</span>個
|
合計 <span>{inquiryList.length}</span>個
|
||||||
</div>
|
</div>
|
||||||
<ul className="inquiry-list">
|
<ul className="inquiry-list">
|
||||||
{inquiryList.map((inquiry: InquiryList) => (
|
{inquiryList.length > 0 &&
|
||||||
<li className="inquiry-item" key={inquiry.qnaNo}>
|
inquiryList.map((inquiry: InquiryList) => (
|
||||||
|
<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.qnaTpCd}</div>
|
<div className="inquiry-item-category">{inquiry.qnaClsLrgCd}</div>
|
||||||
<div className="inquiry-item-tit">{inquiry.qstTitle}</div>
|
<div className="inquiry-item-tit">{inquiry.qstTitle}</div>
|
||||||
<div className="inquiry-item-date">{inquiry.regDt}</div>
|
<div className="inquiry-item-date">{inquiry.regDt}</div>
|
||||||
<div className={`inquiry-badge badge ${badgeStyle.find((badge) => badge.id === inquiry.answerYn)?.color}`}>
|
<div className={`inquiry-badge badge ${badgeStyle.find((badge) => badge.id === inquiry.answerYn)?.color}`}>
|
||||||
@ -67,7 +87,7 @@ export default function ListTable() {
|
|||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
<div className="sale-edit-btn">
|
<div className="sale-edit-btn">
|
||||||
<LoadMoreButton hasMore={hasMore} onLoadMore={() => setOffset(offset + 10)} />
|
<LoadMoreButton hasMore={hasMore} onLoadMore={() => handleLoadMore()} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { InquiryList, Inquiry, InquiryRequest } from '@/types/Inquiry'
|
import { InquiryList, Inquiry, InquiryRequest, InquirySaveResponse } from '@/types/Inquiry'
|
||||||
import { axiosInstance } from '@/libs/axios'
|
import { axiosInstance } from '@/libs/axios'
|
||||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||||
import { useInquiryFilterStore } from '@/store/inquiryFilterStore'
|
import { useInquiryFilterStore } from '@/store/inquiryFilterStore'
|
||||||
@ -12,37 +12,47 @@ export function useInquiry(
|
|||||||
inquiryDetail: Inquiry | null
|
inquiryDetail: Inquiry | null
|
||||||
isLoadingInquiryDetail: boolean
|
isLoadingInquiryDetail: boolean
|
||||||
isSavingInquiry: boolean
|
isSavingInquiry: boolean
|
||||||
saveInquiry: (inquiryRequest: InquiryRequest) => Promise<Inquiry>
|
saveInquiry: (inquiryRequest: InquiryRequest) => Promise<InquirySaveResponse>
|
||||||
} {
|
} {
|
||||||
const { session } = useSessionStore()
|
const { session } = useSessionStore()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const { inquiryListRequest } = useInquiryFilterStore()
|
const { inquiryListRequest } = useInquiryFilterStore()
|
||||||
|
|
||||||
const { data: inquiryList, isLoading: isLoadingInquiryList } = useQuery({
|
const { data: inquiryList, isLoading: isLoadingInquiryList } = useQuery({
|
||||||
queryKey: ['inquiryList', qnoNo, compCd, inquiryListRequest],
|
queryKey: ['inquiryList', inquiryListRequest],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const resp = await axiosInstance(null).get<InquiryList[]>('/api/qna/list', {
|
try {
|
||||||
|
const resp = await axiosInstance(null).get<{ data: InquiryList[] }>(`/api/qna/list`, {
|
||||||
params: { inquiryListRequest },
|
params: { inquiryListRequest },
|
||||||
})
|
})
|
||||||
return resp.data
|
return resp.data.data
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error(error.response.data)
|
||||||
|
return []
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const { data: inquiryDetail, isLoading: isLoadingInquiryDetail } = useQuery({
|
const { data: inquiryDetail, isLoading: isLoadingInquiryDetail } = useQuery({
|
||||||
queryKey: ['inquiryDetail', qnoNo, compCd],
|
queryKey: ['inquiryDetail', qnoNo, compCd],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const resp = await axiosInstance(null).get<Inquiry>(`/api/qna/detail`, {
|
try {
|
||||||
params: { qnoNo, compCd, loginId: session?.userNm },
|
const resp = await axiosInstance(null).get<{ data: Inquiry }>(`/api/qna/detail`, {
|
||||||
|
params: { qnoNo, compCd, langCd: 'JA', loginId: 'x112' },
|
||||||
})
|
})
|
||||||
return resp.data
|
return resp.data.data
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error(error.response)
|
||||||
|
return null
|
||||||
|
}
|
||||||
},
|
},
|
||||||
enabled: qnoNo !== undefined && compCd !== undefined,
|
enabled: qnoNo !== undefined && compCd !== undefined,
|
||||||
})
|
})
|
||||||
|
|
||||||
const { mutateAsync: saveInquiry, isPending: isSavingInquiry } = useMutation({
|
const { mutateAsync: saveInquiry, isPending: isSavingInquiry } = useMutation({
|
||||||
mutationFn: async (inquiryRequest: InquiryRequest) => {
|
mutationFn: async (inquiryRequest: InquiryRequest) => {
|
||||||
const resp = await axiosInstance(null).post<Inquiry>('/api/qna/save', inquiryRequest)
|
const resp = await axiosInstance(null).post<{ data: InquirySaveResponse }>('/api/qna/save', inquiryRequest)
|
||||||
return resp.data
|
return resp.data.data
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
queryClient.invalidateQueries({ queryKey: ['inquiryList'] })
|
queryClient.invalidateQueries({ queryKey: ['inquiryList'] })
|
||||||
|
|||||||
@ -9,33 +9,33 @@ type InquiryFilterState = {
|
|||||||
|
|
||||||
export const useInquiryFilterStore = create<InquiryFilterState>((set) => ({
|
export const useInquiryFilterStore = create<InquiryFilterState>((set) => ({
|
||||||
inquiryListRequest: {
|
inquiryListRequest: {
|
||||||
compCd: '',
|
compCd: '5200',
|
||||||
langCd: '',
|
langCd: 'JA',
|
||||||
storeId: '',
|
storeId: 'X112',
|
||||||
siteTpCd: '',
|
siteTpCd: 'QC',
|
||||||
schTitle: '',
|
schTitle: null,
|
||||||
schRegId: '',
|
schRegId: null,
|
||||||
schFromDt: '',
|
schFromDt: null,
|
||||||
schToDt: '',
|
schToDt: null,
|
||||||
startRow: 0,
|
startRow: 0,
|
||||||
endRow: 0,
|
endRow: 10,
|
||||||
loginId: '',
|
loginId: 'x112',
|
||||||
},
|
},
|
||||||
setInquiryListRequest: (inquiryListRequest) => set({ inquiryListRequest }),
|
setInquiryListRequest: (inquiryListRequest) => set({ inquiryListRequest }),
|
||||||
reset: () =>
|
reset: () =>
|
||||||
set({
|
set({
|
||||||
inquiryListRequest: {
|
inquiryListRequest: {
|
||||||
compCd: '',
|
compCd: '5200',
|
||||||
langCd: '',
|
langCd: 'JA',
|
||||||
storeId: '',
|
storeId: 'X112',
|
||||||
siteTpCd: '',
|
siteTpCd: 'QC',
|
||||||
schTitle: '',
|
schTitle: '',
|
||||||
schRegId: '',
|
schRegId: '',
|
||||||
schFromDt: '',
|
schFromDt: '',
|
||||||
schToDt: '',
|
schToDt: '',
|
||||||
startRow: 0,
|
startRow: 0,
|
||||||
endRow: 0,
|
endRow: 50,
|
||||||
loginId: '',
|
loginId: 'x112',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
}))
|
}))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user