feat: implement Qsp Inquriy API Request, Response type

This commit is contained in:
Dayoung 2025-05-13 09:22:35 +09:00
parent 34319dadcd
commit e3940f72c8
17 changed files with 340 additions and 523 deletions

View File

@ -0,0 +1,15 @@
import { queryStringFormatter } from '@/utils/common-utils'
import axios from 'axios'
import { NextResponse } from 'next/server'
export const QSP_URL = 'http://localhost:8080'
export async function GET(request: Request) {
const body = await request.json()
const response = await axios.get(`${QSP_URL}/qna/detail?${queryStringFormatter(body)}`)
if (response.status === 200) {
return NextResponse.json(response.data)
}
return NextResponse.json({ error: 'Failed to fetch qna detail' }, { status: response.status })
}

View File

@ -0,0 +1,17 @@
import axios from 'axios'
import { NextResponse } from 'next/server'
import { queryStringFormatter } from '@/utils/common-utils'
import { QSP_URL } from '../detail/route'
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
console.log('searchParams::: ', searchParams)
const response = await axios.get(`${QSP_URL}/qna/list?${queryStringFormatter(searchParams)}`)
if (response.status === 200) {
return NextResponse.json(response.data)
}
return NextResponse.json({ error: 'Failed to fetch qna list' }, { status: response.status })
}

View File

@ -0,0 +1,15 @@
import axios from 'axios'
import { NextResponse } from 'next/server'
import { QSP_URL } from '../detail/route'
export async function POST(request: Request) {
const body = await request.json()
const response = await axios.post(`${QSP_URL}/qna/save`, body)
if (response.status === 200) {
return NextResponse.json(response.data)
}
return NextResponse.json({ error: 'Failed to save qna' }, { status: response.status })
}

View File

@ -1,5 +1,5 @@
import ListForm from '@/components/inquiry/ListForm'
import ListTable from '@/components/inquiry/ListTable'
import ListForm from '@/components/inquiry/list/ListForm'
import ListTable from '@/components/inquiry/list/ListTable'
export default function page() {
return (

View File

@ -1,35 +1,31 @@
'use client'
export default function Answer() {
import { Inquiry } from '@/types/Inquiry'
export default function Answer({ inquiryDetail }: { inquiryDetail: Inquiry }) {
return (
<>
<div className="inquiry-answer-wrap">
<div className="inquiry-answer-header">
<div className="inquiry-answer-tit">Hanwha Japan </div>
<div className="inquiry-answer-date">
<span></span>/ <span>2025.04.02 16:54:00</span>
<span>{inquiryDetail?.ansRegNm}</span>/ <span>{inquiryDetail?.ansRegDt}</span>
</div>
</div>
<div className="inquiry-detail-data">
<div className="inquiry-detail-category"></div>
<div className="inquiry-detail-txt">
, . ,
</div>
<div className="inquiry-detail-txt">{inquiryDetail?.ansContents}</div>
</div>
<div className="file-list-wrap">
<div className="file-list-tit"></div>
<ul className="file-list">
<li className="file-item">
{inquiryDetail?.ansListFile?.map((file) => (
<li className="file-item" key={file.fileNo}>
<button className="file-item-bx">
<div className="file-item-name">.jpg </div>
</button>
</li>
<li className="file-item">
<button className="file-item-bx">
<div className="file-item-name">.jpg </div>
<div className="file-item-name">{file.srcFileNm} </div>
</button>
</li>
))}
</ul>
</div>
</div>

View File

@ -2,19 +2,22 @@
import { useState } from 'react'
import Answer from './Answer'
import { useInquiry } from '@/hooks/useInquiry'
import { useRouter } from 'next/navigation'
export default function Detail() {
//todo: 답변 완료 표시를 위해 임시로 추가 해 놓은 state
// 추후에 api 작업 완료후 삭제
// 답변 완료 클래스 & 하단 답변내용 출력도
const [inquiry, setInquiry] = useState<Boolean>(false)
const { inquiryDetail } = useInquiry()
const router = useRouter()
return (
<>
<div className="inquiry-frame">
<div className="inquiry-detail-wrap">
<div className="inquiry-detail-badge">
<div className={`badge ${inquiry ? 'orange' : 'blue'} block`}></div>
<div className={`badge ${inquiryDetail?.answerYn === 'Y' ? 'orange' : 'blue'} block`}></div>
</div>
<div className="inquiry-detail-data-table">
<table className="sale-data-table">
@ -25,59 +28,50 @@ export default function Detail() {
<tbody>
<tr>
<th></th>
<td>2025.04.10</td>
<td>{inquiryDetail?.regDt}</td>
</tr>
<tr>
<th></th>
<td>Hong gi</td>
<td>{inquiryDetail?.regNm}</td>
</tr>
<tr>
<th></th>
<td>interplug</td>
<td>{inquiryDetail?.storeNm}</td>
</tr>
<tr>
<th></th>
<td>interplugs</td>
<td>{inquiryDetail?.compCd}</td>
</tr>
<tr>
<th>E-mail</th>
<td>Hong@interplug.co.kr</td>
<td>{inquiryDetail?.regEmail}</td>
</tr>
</tbody>
</table>
</div>
<div className="inquiry-detail-data">
<div className="inquiry-detail-category"></div>
<div className="inquiry-detail-tit"></div>
<div className="inquiry-detail-txt">
.
<br />
.
<br />
.
</div>
<div className="inquiry-detail-tit">{inquiryDetail?.qstTitle}</div>
<div className="inquiry-detail-txt">{inquiryDetail?.qstContent}</div>
</div>
<div className="file-list-wrap">
<div className="file-list-tit"></div>
<ul className="file-list">
{inquiryDetail?.listFile?.map((file) => (
<li className="file-item">
<button className="file-item-bx">
<div className="file-item-name">.jpg </div>
</button>
</li>
<li className="file-item">
<button className="file-item-bx">
<div className="file-item-name">.jpg </div>
<div className="file-item-name">{file.srcFileNm} </div>
</button>
</li>
))}
</ul>
</div>
</div>
{inquiry && <Answer />}
{inquiryDetail?.answerYn === 'Y' && <Answer inquiryDetail={inquiryDetail} />}
<div className="sale-edit-btn">
<button className="btn-frame n-blue icon">
<button className="btn-frame n-blue icon" onClick={() => router.push('/inquiry/list')}>
<i className="btn-arr"></i>
</button>
</div>

View File

@ -1,73 +0,0 @@
'use client'
import { useParams } from 'next/navigation'
const inquiryDummyData = {
writer: {
name: 'writer',
email: 'writer@example.com',
},
title: 'title',
content: 'content',
files: ['file1.jpg', 'file2.jpg', 'file3.jpg'],
createdAt: '2021-01-01',
answer: {
writer: '佐藤一貴',
content:
'一次側接続は、自動切替開閉器と住宅分電盤主幹ブレーカの間に蓄電システムブレーカを配線する方法です。\n二次側接続は、住宅分電盤主幹ブレ―カの二次側に蓄電システムブレーカを接続する',
createdAt: '2021-01-01 12:00:00',
files: ['file4.jpg', 'file5.jpg', 'file6.jpg'],
},
}
export default function InquiryDetail() {
const params = useParams()
const id = params.id
return (
<div>
<h1>InquiryDetail</h1>
<p>{id}</p>
<div className="mt-5">
<div className="grid grid-cols-2 gap-4">
<p>writer</p>
<p>{inquiryDummyData.writer.name}</p>
</div>
<div className="grid grid-cols-2 gap-4">
<p>email</p>
<p>{inquiryDummyData.writer.email}</p>
</div>
<div className="grid grid-cols-2 gap-4">
<p>title</p>
<p>{inquiryDummyData.title}</p>
</div>
<div className="grid grid-cols-2 gap-4">
<p>content</p>
<p>{inquiryDummyData.content}</p>
</div>
<div>
<p>files</p>
<div className="flex flex-col gap-2">
{inquiryDummyData.files.map((file) => (
<span key={file}>{file}</span>
))}
</div>
</div>
{inquiryDummyData.answer && (
<div className="mt-4">
<h1>Reply: Hanwha Japan</h1>
<div>
<p>{inquiryDummyData.answer.writer}</p>
<p>{inquiryDummyData.answer.createdAt}</p>
<p>{inquiryDummyData.answer.content}</p>
<div className="flex flex-col gap-2">
{inquiryDummyData.answer.files.map((file) => (
<span key={file}>{file}</span>
))}
</div>
</div>
</div>
)}
</div>
</div>
)
}

View File

@ -1,20 +0,0 @@
'use client'
import { Search } from 'lucide-react'
import { useRouter } from 'next/navigation'
export default function InquiryFilter({ handleSearch }: { handleSearch: (e: React.ChangeEvent<HTMLInputElement>) => void }) {
const router = useRouter()
return (
<div>
<button onClick={() => router.push('/inquiry/write')}>write 1:1 Inquiry {'>'}</button>
<div className="flex items-center gap-2">
<input type="text" placeholder="Search" onChange={handleSearch} />
<button>
<Search />
</button>
</div>
</div>
)
}

View File

@ -1,21 +0,0 @@
'use client'
import { useRouter } from 'next/navigation'
export default function InquiryItems({ inquiryData }: { inquiryData: any }) {
const router = useRouter()
return (
<div>
{inquiryData.map((item: any) => (
<div key={item.id} onClick={() => router.push(`/inquiry/${item.id}`)}>
<div>{item.title}</div>
<div>{item.content}</div>
<div>{item.createdAt}</div>
<div>{item.writer}</div>
<div>{item.category}</div>
{item.file && <div>{item.file}</div>}
</div>
))}
</div>
)
}

View File

@ -1,171 +0,0 @@
'use client'
import { useState } from 'react'
import InquiryItems from './InquiryItems'
import InquiryFilter from './InquiryFilter'
import LoadMoreButton from '../LoadMoreButton'
const inquiryDummyData = [
{
id: 1,
title: 'post',
content: 'content',
file: 'file.png',
createdAt: '2024-01-01',
writer: 'writer',
category: 'A',
},
{
id: 2,
title: 'post',
content: 'content',
file: 'file.png',
createdAt: '2024-01-01',
writer: 'writer1',
category: 'B',
},
{
id: 3,
title: 'post',
content: 'content',
file: null,
createdAt: '2024-01-01',
writer: 'writer1',
category: 'C',
},
{
id: 4,
title: 'post',
content: 'content',
file: null,
createdAt: '2024-01-01',
writer: 'writer1',
category: 'A',
},
{
id: 5,
title: 'post',
content: 'content',
file: null,
createdAt: '2024-01-01',
writer: 'writer1',
category: 'B',
},
{
id: 6,
title: 'post',
content: 'content',
file: null,
createdAt: '2024-01-01',
writer: 'writer1',
category: 'C',
},
{
id: 7,
title: 'post',
content: 'content',
file: 'file.png',
createdAt: '2024-01-01',
writer: 'writer',
category: 'A',
},
{
id: 8,
title: 'post',
content: 'content',
file: 'file.png',
createdAt: '2024-01-01',
writer: 'writer1',
category: 'B',
},
{
id: 9,
title: 'post',
content: 'content',
file: null,
createdAt: '2024-01-01',
writer: 'writer1',
category: 'C',
},
{
id: 10,
title: 'post',
content: 'content',
file: 'file.png',
createdAt: '2024-01-01',
writer: 'writer1',
category: 'A',
},
{
id: 11,
title: 'post',
content: 'content',
file: 'file.png',
createdAt: '2024-01-01',
writer: 'writer',
category: 'B',
},
{
id: 12,
title: 'post',
content: 'content',
file: null,
createdAt: '2024-01-01',
writer: 'writer1',
category: 'C',
},
]
export default function InquiryList() {
const [visibleItems, setVisibleItems] = useState(5)
const [isMyPostsOnly, setIsMyPostsOnly] = useState(false)
const [category, setCategory] = useState('')
const [search, setSearch] = useState('')
const [hasMore, setHasMore] = useState(inquiryDummyData.length > 5)
const inquriyData = () => {
if (isMyPostsOnly) {
return inquiryDummyData.filter((item) => item.writer === 'writer')
}
if (category.trim().length > 0) {
return inquiryDummyData.filter((item) => item.category === category)
}
if (search.trim().length > 0) {
return inquiryDummyData.filter((item) => item.title.includes(search))
}
return inquiryDummyData
}
const handleLoadMore = () => {
const newVisibleItems = Math.min(visibleItems + 5, inquriyData().length)
setVisibleItems(newVisibleItems)
setHasMore(newVisibleItems < inquriyData().length)
}
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
setSearch(e.target.value)
}
const handleScrollToTop = () => {
window.scrollTo({ top: 0, behavior: 'smooth' })
}
return (
<div className="flex flex-col gap-2">
<InquiryFilter handleSearch={handleSearch} />
<div className="flex items-center gap-2">
<input type="checkbox" id="myPosts" checked={isMyPostsOnly} onChange={(e) => setIsMyPostsOnly(e.target.checked)} />
<label htmlFor="myPosts">my posts</label>
</div>
<select onChange={(e) => setCategory(e.target.value)}>
<option value="">All</option>
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
</select>
<span>total {inquriyData().length}</span>
<InquiryItems inquiryData={inquriyData().slice(0, visibleItems)} />
<LoadMoreButton hasMore={hasMore} onLoadMore={handleLoadMore} onScrollToTop={handleScrollToTop} />
</div>
)
}

View File

@ -1,67 +0,0 @@
'use client'
import { useState } from 'react'
import { useRouter } from 'next/navigation'
export interface InquiryFormData {
category: string
title: string
content: string
file: File[]
}
export default function InquiryWriteForm() {
const router = useRouter()
const [formData, setFormData] = useState<InquiryFormData>({
category: 'A',
title: '',
content: '',
file: [],
})
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = Array.from(e.target.files || [])
setFormData({ ...formData, file: [...formData.file, ...file] })
}
const handleSubmit = () => {
console.log('submit: ', formData)
// router.push(`/inquiry`)
}
return (
<div>
<div>
<label htmlFor="category">category</label>
<select id="category" onChange={(e) => setFormData({ ...formData, category: e.target.value })}>
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
</select>
</div>
<div>
<label htmlFor="title">title</label>
<input type="text" id="title" onChange={(e) => setFormData({ ...formData, title: e.target.value })} />
</div>
<div>
<label htmlFor="content">content</label>
<textarea id="content" onChange={(e) => setFormData({ ...formData, content: e.target.value })} />
</div>
<div>
<label htmlFor="file">file</label>
<input type="file" id="file" accept="image/*" capture="environment" onChange={handleFileChange} />
<div>
<p>file count: {formData.file.length}</p>
{formData.file.map((f) => (
<div key={f.name}>
<div>{f.name}</div>
<div>
<button>delete</button>
</div>
</div>
))}
</div>
</div>
<button onClick={handleSubmit}>submit</button>
</div>
)
}

View File

@ -1,93 +0,0 @@
'use client'
import { use, useEffect, useState } from 'react'
import LoadMoreButton from '../LoadMoreButton'
const inquiryDummy = [
{ id: 1, category: '屋根', title: '屋根材適合性確認依頼', date: '2025.04.02', status: 'completed' },
{ id: 2, category: '外壁', title: '外壁仕上げ材確認', date: '2025.04.03', status: 'completed' },
{ id: 3, category: '設備', title: '換気システム図面確認', date: '2025.04.04', status: 'completed' },
{ id: 4, category: '基礎', title: '基礎配筋検査依頼', date: '2025.04.05', status: 'completed' },
{ id: 5, category: '内装', title: 'クロス仕様確認', date: '2025.04.06', status: 'waiting' },
{ id: 6, category: '構造', title: '耐震壁位置変更申請', date: '2025.04.07', status: 'completed' },
{ id: 7, category: '屋根', title: '雨樋取付方法確認', date: '2025.04.08', status: 'completed' },
{ id: 8, category: '外構', title: 'フェンス高さ変更相談', date: '2025.04.09', status: 'completed' },
{ id: 9, category: '設備', title: '給湯器設置位置確認', date: '2025.04.10', status: 'completed' },
{ id: 10, category: '外壁', title: 'タイル割付案確認依頼', date: '2025.04.11', status: 'waiting' },
{ id: 11, category: '内装', title: '照明配置図面確認', date: '2025.04.12', status: 'completed' },
{ id: 12, category: '構造', title: '梁補強案確認', date: '2025.04.13', status: 'completed' },
{ id: 13, category: '基礎', title: '杭長設計確認依頼', date: '2025.04.14', status: 'completed' },
{ id: 14, category: '屋根', title: '断熱材施工方法確認', date: '2025.04.15', status: 'completed' },
{ id: 15, category: '外構', title: '駐車場勾配図確認', date: '2025.04.16', status: 'completed' },
]
const badgeStyle = [
{
id: 'completed',
label: '回答完了',
color: 'blue',
},
{
id: 'waiting',
label: '回答待ち',
color: 'orange',
},
]
export default function ListTable() {
const [offset, setOffset] = useState(0)
const [hasMore, setHasMore] = useState(true)
const inquiryList = inquiryDummy.slice(0, offset + 10)
useEffect(() => {
if (inquiryDummy.length > offset + 10) {
setHasMore(true)
} else {
setHasMore(false)
}
}, [inquiryList])
return (
<>
<div className="sale-frame">
<div className="inquiry-table-filter">
<div className="filter-check">
<div className="check-form-box">
<input type="checkbox" id="ch01" />
<label htmlFor="ch01"></label>
</div>
</div>
<div className="filter-select">
<select className="select-form" name="" id="">
<option value=""></option>
<option value=""></option>
<option value=""></option>
</select>
</div>
</div>
<div className="inquiry-list-wrap">
<div className="inquiry-list-tit">
<span>98</span>
</div>
<ul className="inquiry-list">
{inquiryList.map((inquiry) => (
<li className="inquiry-item" key={inquiry.id}>
<div className="inquiry-item-bx">
<div className="inquiry-item-category">{inquiry.category}</div>
<div className="inquiry-item-tit">{inquiry.title}</div>
<div className="inquiry-item-date">{inquiry.date}</div>
<div className={`inquiry-badge badge ${badgeStyle.find((badge) => badge.id === inquiry.status)?.color}`}>
{badgeStyle.find((badge) => badge.id === inquiry.status)?.label}
</div>
</div>
</li>
))}
</ul>
<div className="sale-edit-btn">
<LoadMoreButton hasMore={hasMore} onLoadMore={() => setOffset(offset + 10)} />
</div>
</div>
</div>
</>
)
}

View File

@ -0,0 +1,76 @@
'use client'
import { useEffect, useState } from 'react'
import LoadMoreButton from '../../LoadMoreButton'
import { useInquiry } from '@/hooks/useInquiry'
import { InquiryList } from '@/types/Inquiry'
const badgeStyle = [
{
id: 'Y',
label: '回答完了',
color: 'blue',
},
{
id: 'N',
label: '回答待ち',
color: 'orange',
},
]
export default function ListTable() {
const [offset, setOffset] = useState(0)
const [hasMore, setHasMore] = useState(true)
const { inquiryList } = useInquiry()
useEffect(() => {
if (inquiryList.length > offset + 10) {
setHasMore(true)
} else {
setHasMore(false)
}
}, [inquiryList])
return (
<>
<div className="sale-frame">
<div className="inquiry-table-filter">
<div className="filter-check">
<div className="check-form-box">
<input type="checkbox" id="ch01" />
<label htmlFor="ch01"></label>
</div>
</div>
<div className="filter-select">
<select className="select-form" name="" id="">
<option value=""></option>
<option value="N"></option>
<option value="Y"></option>
</select>
</div>
</div>
<div className="inquiry-list-wrap">
<div className="inquiry-list-tit">
<span>{inquiryList.length}</span>
</div>
<ul className="inquiry-list">
{inquiryList.map((inquiry: InquiryList) => (
<li className="inquiry-item" key={inquiry.qnaNo}>
<div className="inquiry-item-bx">
<div className="inquiry-item-category">{inquiry.qnaTpCd}</div>
<div className="inquiry-item-tit">{inquiry.qstTitle}</div>
<div className="inquiry-item-date">{inquiry.regDt}</div>
<div className={`inquiry-badge badge ${badgeStyle.find((badge) => badge.id === inquiry.answerYn)?.color}`}>
{badgeStyle.find((badge) => badge.id === inquiry.answerYn)?.label}
</div>
</div>
</li>
))}
</ul>
<div className="sale-edit-btn">
<LoadMoreButton hasMore={hasMore} onLoadMore={() => setOffset(offset + 10)} />
</div>
</div>
</div>
</>
)
}

60
src/hooks/useInquiry.ts Normal file
View File

@ -0,0 +1,60 @@
import { InquiryList, Inquiry, InquiryRequest } from '@/types/Inquiry'
import { axiosInstance } from '@/libs/axios'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { useInquiryFilterStore } from '@/store/inquiryFilterStore'
import { useSessionStore } from '@/store/session'
export function useInquiry(
qnoNo?: number,
compCd?: string,
): {
inquiryList: InquiryList[]
isLoadingInquiryList: boolean
inquiryDetail: Inquiry | null
isLoadingInquiryDetail: boolean
isSavingInquiry: boolean
saveInquiry: (inquiryRequest: InquiryRequest) => Promise<Inquiry>
} {
const { session } = useSessionStore()
const queryClient = useQueryClient()
const { inquiryListRequest } = useInquiryFilterStore()
const { data: inquiryList, isLoading: isLoadingInquiryList } = useQuery({
queryKey: ['inquiryList', qnoNo, compCd, inquiryListRequest],
queryFn: async () => {
const resp = await axiosInstance(null).get<InquiryList[]>('/api/qna/list', {
params: { inquiryListRequest },
})
return resp.data
},
})
const { data: inquiryDetail, isLoading: isLoadingInquiryDetail } = useQuery({
queryKey: ['inquiryDetail', qnoNo, compCd],
queryFn: async () => {
const resp = await axiosInstance(null).get<Inquiry>(`/api/qna/detail`, {
params: { qnoNo, compCd, loginId: session?.userNm },
})
return resp.data
},
enabled: qnoNo !== undefined && compCd !== undefined,
})
const { mutateAsync: saveInquiry, isPending: isSavingInquiry } = useMutation({
mutationFn: async (inquiryRequest: InquiryRequest) => {
const resp = await axiosInstance(null).post<Inquiry>('/api/qna/save', inquiryRequest)
return resp.data
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['inquiryList'] })
},
})
return {
inquiryList: inquiryList ?? [],
inquiryDetail: inquiryDetail ?? null,
isLoadingInquiryList,
isLoadingInquiryDetail,
isSavingInquiry,
saveInquiry,
}
}

View File

@ -1,41 +1,41 @@
import { InquiryListRequest } from '@/types/Inquiry'
import { create } from 'zustand'
export const FILTER_OPTIONS = [
{
id: 'all',
label: '全体',
},
{
id: 'completed',
label: '回答完了',
},
{
id: 'waiting',
label: '回答待ち',
},
]
export type FILTER_OPTIONS_ENUM = (typeof FILTER_OPTIONS)[number]['id']
type InquiryFilterState = {
keyword: string
filter: FILTER_OPTIONS_ENUM
isMySurvey: string | null
offset: number
setKeyword: (keyword: string) => void
setFilter: (filter: FILTER_OPTIONS_ENUM) => void
setIsMySurvey: (isMySurvey: string | null) => void
setOffset: (offset: number) => void
inquiryListRequest: InquiryListRequest
setInquiryListRequest: (inquiryListRequest: InquiryListRequest) => void
reset: () => void
}
export const useInquiryFilterStore = create<InquiryFilterState>((set) => ({
keyword: '',
filter: 'all',
isMySurvey: null,
offset: 0,
setKeyword: (keyword) => set({ keyword }),
setFilter: (filter) => set({ filter }),
setIsMySurvey: (isMySurvey) => set({ isMySurvey }),
setOffset: (offset) => set({ offset }),
reset: () => set({ keyword: '', filter: 'all', isMySurvey: null, offset: 0 }),
inquiryListRequest: {
compCd: '',
langCd: '',
storeId: '',
siteTpCd: '',
schTitle: '',
schRegId: '',
schFromDt: '',
schToDt: '',
startRow: 0,
endRow: 0,
loginId: '',
},
setInquiryListRequest: (inquiryListRequest) => set({ inquiryListRequest }),
reset: () =>
set({
inquiryListRequest: {
compCd: '',
langCd: '',
storeId: '',
siteTpCd: '',
schTitle: '',
schRegId: '',
schFromDt: '',
schToDt: '',
startRow: 0,
endRow: 0,
loginId: '',
},
}),
}))

89
src/types/Inquiry.ts Normal file
View File

@ -0,0 +1,89 @@
export type InquiryListRequest = {
compCd: string //company code
langCd: string //language code
storeId: string //store id
siteTpCd: string //site type code (QC: QCast, QR: QRead)
schTitle: string | null //search title
schRegId: string | null //search regId
schFromDt: string | null //search start date
schToDt: string | null //search end date
startRow: number //start row
endRow: number //end row
loginId: string //login id
}
export type InquiryList = {
totCnt: number //total count
rowNumber: number //row number
compCd: string //company code
qnaNo: number //qna number
qstTitle: string //title
regDt: string //registration date
regId: string //registration Userid
regNm: string //registration User name
answerYn: string //answer yn - Y / N
attachYn: string | null //attach yn - Y / N
qnaClsLrgCd: string //qna CLS large Code
qnaClsMidCd: string //qna CLS Mid Code
qnaClsSmlCd: string | null //qna CLS Small Code
}
export type InquiryDetailRequest = {
compCd: string //company code
langCd: string //language code
qnaNo: number //qna number
loginId: string //login id
}
export type Inquiry = {
compCd: string //company code
qnaNo: number //qna number
qstTitle: string //title
qstContents: string //content
regDt: string //registration date
regId: string //registration Userid
regNm: string //registration User name
regEmail: string //registration User email
answerYn: string //answer yn - Y / N
ansContents: string | null //answer content
ansRegDt: string | null //answer registration date
ansRegNm: string | null //answer registration User name
storeId: string | null //store id
storeNm: string | null //store name
regUserNm: string //registration User name
regUserTelNo: string | null //registration User tel number
qnaClsLrgCd: string //qna CLS large Code
qnaClsMidCd: string //qna CLS Mid Code
qnaClsSmlCd: string | null //qna CLS Small Code
listFile: listFile[] | null //Question list file
ansListFile: listFile[] | null //Answer list file
}
export type listFile = {
fileNo: number //file number
encodeFileNo: string //encode file number
srcFileNm: string //source file name
fileCours: string //file course
fileSize: number //file size(Byte)
regDt: string //registration date
}
export type InquiryRequest = {
compCd: string //company code
siteTpCd: string //site type code(QC: QCast, QR: QRead)
qnaClsLrgCd: string //qna CLS large Code
qnaClsMidCd: string //qna CLS Mid Code
qnaClsSmlCd: string | null //qna CLS Small Code
title: string //title
contents: string | null //contents
regId: string //registration Userid
storeId: string | null //store id
regUserNm: string //registration User name
regUserTelNo: string | null //registration User tel number
}
export type InquirySaveResponse = {
cnt: number | null //count
qnaNo: number //qna number
mailYn: string //mail yn - Y / N
}