338 lines
12 KiB
TypeScript
338 lines
12 KiB
TypeScript
'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'
|
|
import { CONFIRM_MESSAGE, SUCCESS_MESSAGE, useAlertMsg, WARNING_MESSAGE } from '@/hooks/useAlertMsg'
|
|
import { useInquiryFilterStore } from '@/store/inquiryFilterStore'
|
|
|
|
export default function RegistForm() {
|
|
const { saveInquiry, isSavingInquiry, commonCodeList } = useInquiry(undefined, false)
|
|
const { showErrorAlert, showSuccessAlert, showConfirm } = useAlertMsg()
|
|
const { session } = useSessionStore()
|
|
const router = useRouter()
|
|
const { setIsMyInquiry } = useInquiryFilterStore()
|
|
const [inquiryRequest, setInquiryRequest] = useState<InquiryRequest>({
|
|
compCd: '5200',
|
|
siteTpCd: 'QC',
|
|
qnaClsLrgCd: '',
|
|
qnaClsMidCd: '',
|
|
qnaClsSmlCd: null,
|
|
title: '',
|
|
contents: '',
|
|
regId: '',
|
|
regUserNm: '',
|
|
regUserTelNo: null,
|
|
storeId: '',
|
|
qstMail: '',
|
|
})
|
|
const requiredFieldNames = [
|
|
{ id: 'qnaClsLrgCd', name: 'お問い合わせタイプ' },
|
|
{ id: 'qnaClsMidCd', name: 'お問い合わせタイプ' },
|
|
{ id: 'regUserNm', name: '名前' },
|
|
{ id: 'qstMail', name: 'E-mail' },
|
|
{ id: 'title', name: 'お問い合わせタイトル' },
|
|
{ id: 'contents', name: 'お問い合わせ内容' },
|
|
]
|
|
|
|
useEffect(() => {
|
|
if (session?.isLoggedIn) {
|
|
setInquiryRequest({
|
|
...inquiryRequest,
|
|
regId: session?.userId ?? '',
|
|
regUserNm: session?.userNm ?? '',
|
|
storeId: session?.storeId ?? '',
|
|
qstMail: session?.email ?? '',
|
|
regUserTelNo: session?.telNo ?? '',
|
|
})
|
|
}
|
|
}, [session])
|
|
|
|
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 focusOnRequiredField = (fieldId: string) => {
|
|
const element = document.getElementById(fieldId)
|
|
if (element) element.focus()
|
|
}
|
|
|
|
/** 제출 처리 */
|
|
const handleSubmit = async () => {
|
|
const emptyField = requiredFieldNames.find((field) => inquiryRequest[field.id as keyof InquiryRequest] === '')
|
|
if (emptyField) {
|
|
showErrorAlert(WARNING_MESSAGE.REQUIRED_FIELD_IS_EMPTY, emptyField?.name)
|
|
focusOnRequiredField(emptyField?.id ?? '')
|
|
return
|
|
}
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
|
if (!emailRegex.test(inquiryRequest.qstMail)) {
|
|
showErrorAlert(WARNING_MESSAGE.EMAIL_PREFIX_IS_INVALID)
|
|
focusOnRequiredField('qstMail')
|
|
return
|
|
}
|
|
if (inquiryRequest.title.length > 100) {
|
|
showErrorAlert(WARNING_MESSAGE.TITLE_MAX_LENGTH)
|
|
focusOnRequiredField('title')
|
|
return
|
|
}
|
|
if (inquiryRequest.contents.length > 2000) {
|
|
showErrorAlert(WARNING_MESSAGE.CONTENTS_MAX_LENGTH)
|
|
focusOnRequiredField('contents')
|
|
return
|
|
}
|
|
|
|
const formData = new FormData()
|
|
attachedFiles.forEach((file) => {
|
|
formData.append('files', file)
|
|
})
|
|
Object.entries(inquiryRequest).forEach(([key, value]) => {
|
|
formData.append(key, value ?? '')
|
|
})
|
|
showConfirm(
|
|
CONFIRM_MESSAGE.SAVE_INQUIRY_CONFIRM,
|
|
async () => {
|
|
const res = await saveInquiry(formData)
|
|
if (!isSavingInquiry) {
|
|
showSuccessAlert(SUCCESS_MESSAGE.SAVE_SUCCESS)
|
|
router.push(`/inquiry/${res.qnaNo}`)
|
|
}
|
|
},
|
|
() => null,
|
|
)
|
|
}
|
|
|
|
const handlePhoneNumberChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const value = e.target.value.replace(/[^\d]/g, '')
|
|
|
|
let formattedNumber = ''
|
|
if (value.length <= 3) {
|
|
formattedNumber = value
|
|
} else if (value.length <= 7) {
|
|
formattedNumber = `${value.slice(0, 3)}-${value.slice(3)}`
|
|
} else {
|
|
formattedNumber = `${value.slice(0, 3)}-${value.slice(3, 7)}-${value.slice(7, 11)}`
|
|
}
|
|
|
|
setInquiryRequest({ ...inquiryRequest, regUserTelNo: formattedNumber })
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<div className="inquiry-frame">
|
|
<div className="data-form-wrap">
|
|
<div className="data-input-form-bx">
|
|
<div className="data-input-form-tit">
|
|
お問い合わせタイプ <i className="import">*</i>
|
|
</div>
|
|
<div className="data-input">
|
|
<select
|
|
className="select-form"
|
|
name="qnaClsLrgCd"
|
|
id="qnaClsLrgCd"
|
|
value={inquiryRequest.qnaClsLrgCd}
|
|
onChange={(e) => setInquiryRequest({ ...inquiryRequest, qnaClsLrgCd: e.target.value })}
|
|
>
|
|
<option value="" hidden>
|
|
選択してください
|
|
</option>
|
|
{commonCodeList
|
|
.filter((code) => code.headId === 'QNA_CLS_LRG_CD')
|
|
.map((code) => (
|
|
<option key={code.code} value={code.code}>
|
|
{code.name}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
{commonCodeList.filter((code) => code.refChar1 === inquiryRequest.qnaClsLrgCd).length > 0 && inquiryRequest.qnaClsLrgCd && (
|
|
<div className="data-input mt5">
|
|
<select
|
|
className="select-form"
|
|
name="qnaClsMidCd"
|
|
id="qnaClsMidCd"
|
|
value={inquiryRequest.qnaClsMidCd}
|
|
onChange={(e) => setInquiryRequest({ ...inquiryRequest, qnaClsMidCd: e.target.value })}
|
|
>
|
|
<option value="" hidden>
|
|
選択してください
|
|
</option>
|
|
{commonCodeList
|
|
.filter((code) => code.refChar1 === inquiryRequest.qnaClsLrgCd)
|
|
.map((code) => (
|
|
<option key={code.code} value={code.code}>
|
|
{code.name}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
)}
|
|
{commonCodeList.filter((code) => code.refChar1 === inquiryRequest.qnaClsMidCd).length > 0 && inquiryRequest.qnaClsMidCd && (
|
|
<div className="data-input mt5">
|
|
<select
|
|
className="select-form"
|
|
name="qnaClsSmlCd"
|
|
id="qnaClsSmlCd"
|
|
value={inquiryRequest.qnaClsSmlCd ?? ''}
|
|
onChange={(e) => setInquiryRequest({ ...inquiryRequest, qnaClsSmlCd: e.target.value })}
|
|
>
|
|
<option value="" hidden>
|
|
選択してください
|
|
</option>
|
|
{commonCodeList
|
|
.filter((code) => code.refChar1 === inquiryRequest.qnaClsMidCd)
|
|
.map((code) => (
|
|
<option key={code.code} value={code.code}>
|
|
{code.name}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
)}
|
|
</div>
|
|
<div className="data-input-form-bx">
|
|
<div className="data-input-form-tit">
|
|
名前 <i className="import">*</i>
|
|
</div>
|
|
<div className="data-input">
|
|
<input
|
|
className="input-frame"
|
|
type="text"
|
|
placeholder="名前を書いてください"
|
|
onChange={(e) => setInquiryRequest({ ...inquiryRequest, regUserNm: e.target.value })}
|
|
value={inquiryRequest.regUserNm}
|
|
id="regUserNm"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="data-input-form-bx">
|
|
<div className="data-input-form-tit">電話番号</div>
|
|
<div className="data-input">
|
|
<input
|
|
className="input-frame"
|
|
type="tel"
|
|
inputMode="tel"
|
|
placeholder="電話番号を書き留めてください"
|
|
onChange={handlePhoneNumberChange}
|
|
value={inquiryRequest.regUserTelNo ?? ''}
|
|
id="regUserTelNo"
|
|
maxLength={13}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="data-input-form-bx">
|
|
<div className="data-input-form-tit">
|
|
E-mail <i className="import">*</i>
|
|
</div>
|
|
<div className="data-input">
|
|
<input
|
|
className="input-frame"
|
|
type="text"
|
|
placeholder="E-mailを書いてください"
|
|
value={inquiryRequest.qstMail}
|
|
onChange={(e) => setInquiryRequest({ ...inquiryRequest, qstMail: e.target.value })}
|
|
id="qstMail"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="data-input-form-bx">
|
|
<div className="data-input-form-tit">
|
|
お問い合わせタイトル <i className="import">*</i>
|
|
</div>
|
|
<div className="data-input">
|
|
<input
|
|
className="input-frame"
|
|
type="text"
|
|
placeholder="お問い合わせタイトルを記入してください"
|
|
onChange={(e) => {
|
|
if (e.target.value.length >= 100) {
|
|
showErrorAlert(WARNING_MESSAGE.TITLE_MAX_LENGTH)
|
|
return
|
|
}
|
|
setInquiryRequest({ ...inquiryRequest, title: e.target.value })
|
|
}}
|
|
maxLength={100}
|
|
id="title"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="data-input-form-bx">
|
|
<div className="data-input-form-tit">
|
|
お問い合わせ内容 <i className="import">*</i>
|
|
</div>
|
|
<div className="data-input">
|
|
<textarea
|
|
className="textarea-form"
|
|
rows={6}
|
|
id="contents"
|
|
placeholder="お問い合わせ内容を入力してください"
|
|
onChange={(e) => {
|
|
if (e.target.value.length >= 2000) {
|
|
showErrorAlert(WARNING_MESSAGE.CONTENTS_MAX_LENGTH)
|
|
return
|
|
}
|
|
setInquiryRequest({ ...inquiryRequest, contents: e.target.value })
|
|
}}
|
|
value={inquiryRequest.contents}
|
|
maxLength={2000}
|
|
></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="inquiry-file-wrap">
|
|
<div className="filebox">
|
|
<label className="btn-frame l-blue icon" htmlFor="file">
|
|
<i className="btn-clip"></i>添付ファイル
|
|
</label>
|
|
<input type="file" id="file" onChange={handleFileChange} multiple style={{ display: 'none' }} />
|
|
</div>
|
|
<div className="file-list-wrap">
|
|
<div className="file-list-tit">
|
|
添付ファイル<span>{attachedFiles.length}</span>個
|
|
</div>
|
|
<ul className="file-list">
|
|
{attachedFiles.map((file, index) => (
|
|
<li className="file-item" key={`${file.name}-${index}`}>
|
|
<div className="file-item-bx">
|
|
<div className="file-item-name">{file.name}</div>
|
|
<button className="file-del" onClick={() => handleRemoveFile(index)} aria-label="Remove file" />
|
|
</div>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
<div className="btn-flex-wrap">
|
|
<button
|
|
className="btn-frame n-blue icon"
|
|
onClick={() => {
|
|
setIsMyInquiry(session?.userId ?? null)
|
|
router.push('/inquiry/list')
|
|
}}
|
|
>
|
|
お問い合わせ一覧<i className="btn-arr"></i>
|
|
</button>
|
|
<button className="btn-frame n-blue icon" onClick={handleSubmit} disabled={isSavingInquiry}>
|
|
問い合わせの送信<i className="btn-arr"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</>
|
|
)
|
|
}
|