|
@@ -1,11 +1,9 @@
|
|
|
-import { useEffect, useState, type FormEvent } from 'react'
|
|
|
|
|
-import { Link, useParams } from 'react-router-dom'
|
|
|
|
|
|
|
+import { useState, type FormEvent } from 'react'
|
|
|
|
|
+import { Link } from 'react-router-dom'
|
|
|
import { Helmet } from 'react-helmet-async'
|
|
import { Helmet } from 'react-helmet-async'
|
|
|
-import { createCustomer, getCustomerById, updateCustomer } from '../../../services/api/customers'
|
|
|
|
|
|
|
+import { createCustomer } from '../../../services/api/customers'
|
|
|
import { uploadMedia } from '../../../services/api/media'
|
|
import { uploadMedia } from '../../../services/api/media'
|
|
|
-import type { CustomerEntity } from '../../../services/api/customers'
|
|
|
|
|
import {
|
|
import {
|
|
|
- customerToFormValues,
|
|
|
|
|
emptyCustomerForm,
|
|
emptyCustomerForm,
|
|
|
formValuesToPayload,
|
|
formValuesToPayload,
|
|
|
type CustomerFormValues,
|
|
type CustomerFormValues,
|
|
@@ -13,36 +11,33 @@ import {
|
|
|
import { usePageContext, usePreviewUrl } from '../../../shared/pageContext'
|
|
import { usePageContext, usePreviewUrl } from '../../../shared/pageContext'
|
|
|
import { DashboardLayout } from '../../../layouts/DashboardLayout'
|
|
import { DashboardLayout } from '../../../layouts/DashboardLayout'
|
|
|
|
|
|
|
|
-export function CustomerFormPage({ mode }: { mode: 'new' | 'edit' }) {
|
|
|
|
|
|
|
+function getSubmitErrorMessage(error: unknown, locale: 'zh' | 'ja') {
|
|
|
|
|
+ const fallback = locale === 'ja' ? '保存に失敗しました' : '保存失败'
|
|
|
|
|
+
|
|
|
|
|
+ if (!(error instanceof Error)) {
|
|
|
|
|
+ return fallback
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (error.message === 'Internal server error') {
|
|
|
|
|
+ return locale === 'ja'
|
|
|
|
|
+ ? '保存に失敗しました。しばらくしてから再試行してください'
|
|
|
|
|
+ : '保存失败,请稍后重试'
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return error.message || fallback
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export function CustomerFormPage() {
|
|
|
const { locale, navigate, path, copy } = usePageContext()
|
|
const { locale, navigate, path, copy } = usePageContext()
|
|
|
- const params = useParams()
|
|
|
|
|
- const [existing, setExisting] = useState<CustomerEntity | null>(null)
|
|
|
|
|
const [form, setForm] = useState<CustomerFormValues>(emptyCustomerForm)
|
|
const [form, setForm] = useState<CustomerFormValues>(emptyCustomerForm)
|
|
|
const [submitting, setSubmitting] = useState(false)
|
|
const [submitting, setSubmitting] = useState(false)
|
|
|
const [error, setError] = useState('')
|
|
const [error, setError] = useState('')
|
|
|
const [photoFile, setPhotoFile] = useState<File | null>(null)
|
|
const [photoFile, setPhotoFile] = useState<File | null>(null)
|
|
|
- const photoPreview = usePreviewUrl(photoFile, existing?.image || '/images/aitori-before-photo.png')
|
|
|
|
|
|
|
+ const photoPreview = usePreviewUrl(photoFile, '/images/aitori-before-photo.png')
|
|
|
|
|
|
|
|
const patch = (part: Partial<CustomerFormValues>) => setForm((current) => ({ ...current, ...part }))
|
|
const patch = (part: Partial<CustomerFormValues>) => setForm((current) => ({ ...current, ...part }))
|
|
|
-
|
|
|
|
|
- useEffect(() => {
|
|
|
|
|
- if (mode !== 'edit') return
|
|
|
|
|
-
|
|
|
|
|
- getCustomerById({ customerId: params.customerId })
|
|
|
|
|
- .then((item) => {
|
|
|
|
|
- setExisting(item)
|
|
|
|
|
- if (item) setForm(customerToFormValues(item))
|
|
|
|
|
- })
|
|
|
|
|
- .catch(() => setExisting(null))
|
|
|
|
|
- }, [mode, params.customerId])
|
|
|
|
|
-
|
|
|
|
|
- if (mode === 'edit' && !existing) {
|
|
|
|
|
- return null
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- const detailPath = existing ? path(`/customers/${existing.id}`) : path('/customers')
|
|
|
|
|
const pageCopy = copy.customerFormPage
|
|
const pageCopy = copy.customerFormPage
|
|
|
- const modeCopy = mode === 'edit' ? pageCopy.edit : pageCopy.new
|
|
|
|
|
|
|
+ const modeCopy = pageCopy.new
|
|
|
|
|
|
|
|
const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
|
|
const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
|
|
|
event.preventDefault()
|
|
event.preventDefault()
|
|
@@ -50,18 +45,13 @@ export function CustomerFormPage({ mode }: { mode: 'new' | 'edit' }) {
|
|
|
setError('')
|
|
setError('')
|
|
|
setSubmitting(true)
|
|
setSubmitting(true)
|
|
|
try {
|
|
try {
|
|
|
- let image: string | undefined = existing?.image
|
|
|
|
|
- if (photoFile) image = (await uploadMedia(photoFile, 'avatar')).url
|
|
|
|
|
- const payload = formValuesToPayload(form, image)
|
|
|
|
|
- if (mode === 'edit' && existing) {
|
|
|
|
|
- await updateCustomer(existing.id, payload)
|
|
|
|
|
- navigate(path(`/customers/${existing.id}`))
|
|
|
|
|
- } else {
|
|
|
|
|
- await createCustomer(payload)
|
|
|
|
|
- navigate(path('/customers'))
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ let avatar: string | undefined
|
|
|
|
|
+ if (photoFile) avatar = (await uploadMedia(photoFile, 'avatar')).url
|
|
|
|
|
+ const payload = formValuesToPayload(form, avatar)
|
|
|
|
|
+ await createCustomer(payload)
|
|
|
|
|
+ navigate(path('/customers'))
|
|
|
} catch (err) {
|
|
} catch (err) {
|
|
|
- setError(err instanceof Error ? err.message : '保存失败')
|
|
|
|
|
|
|
+ setError(getSubmitErrorMessage(err, locale))
|
|
|
} finally {
|
|
} finally {
|
|
|
setSubmitting(false)
|
|
setSubmitting(false)
|
|
|
}
|
|
}
|
|
@@ -77,149 +67,130 @@ export function CustomerFormPage({ mode }: { mode: 'new' | 'edit' }) {
|
|
|
<section className="stylist-workbench-top ipad-top-space-margin mb-2">
|
|
<section className="stylist-workbench-top ipad-top-space-margin mb-2">
|
|
|
<div className="container">
|
|
<div className="container">
|
|
|
<div className="d-flex align-items-center justify-content-between flex-wrap gap-3 mb-4">
|
|
<div className="d-flex align-items-center justify-content-between flex-wrap gap-3 mb-4">
|
|
|
- <Link to={mode === 'edit' ? detailPath : path('/customers')} className="btn btn-small btn-rounded btn-transparent-light-gray border border-1 border-color-dark-gray fw-700"><i className="feather icon-feather-arrow-left me-6px"></i>{modeCopy.back}</Link>
|
|
|
|
|
|
|
+ <Link to={path('/customers')} className="btn btn-small btn-rounded btn-transparent-light-gray border border-1 border-color-dark-gray fw-700"><i className="feather icon-feather-arrow-left me-6px"></i>{modeCopy.back}</Link>
|
|
|
<div className="d-flex flex-wrap gap-2">
|
|
<div className="d-flex flex-wrap gap-2">
|
|
|
- <Link to={mode === 'edit' ? detailPath : path('/customers')} className="btn btn-large btn-rounded btn-transparent-light-gray border border-1 border-color-dark-gray fw-700">{copy.common.cancel}</Link>
|
|
|
|
|
- <button type="submit" form={mode === 'edit' ? 'customer-edit-form' : 'customer-new-form'} className="btn btn-large btn-rounded btn-base-color btn-box-shadow fw-700"><i className={`feather ${mode === 'edit' ? 'icon-feather-save' : 'icon-feather-user-plus'} me-10px`}></i>{modeCopy.submit}</button>
|
|
|
|
|
|
|
+ <Link to={path('/customers')} className="btn btn-large btn-rounded btn-transparent-light-gray border border-1 border-color-dark-gray fw-700">{copy.common.cancel}</Link>
|
|
|
|
|
+ <button type="submit" form="customer-new-form" className="btn btn-large btn-rounded btn-base-color btn-box-shadow fw-700"><i className="feather icon-feather-user-plus me-10px"></i>{modeCopy.submit}</button>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div className="workbench-panel bg-white border-radius-8px box-shadow-extra-large p-30px">
|
|
<div className="workbench-panel bg-white border-radius-8px box-shadow-extra-large p-30px">
|
|
|
<span className="bg-base-color d-inline-block mb-15px fw-600 text-white text-uppercase border-radius-30px ps-20px pe-20px fs-12">{modeCopy.badge}</span>
|
|
<span className="bg-base-color d-inline-block mb-15px fw-600 text-white text-uppercase border-radius-30px ps-20px pe-20px fs-12">{modeCopy.badge}</span>
|
|
|
<h1 className="fw-700 text-dark-gray ls-minus-1px mb-10px">{modeCopy.heading}</h1>
|
|
<h1 className="fw-700 text-dark-gray ls-minus-1px mb-10px">{modeCopy.heading}</h1>
|
|
|
- <p className="fs-18 lh-30 mb-0">{mode === 'edit' ? modeCopy.lead.replace('{{name}}', existing?.name || '') : modeCopy.lead}</p>
|
|
|
|
|
|
|
+ <p className="fs-18 lh-30 mb-0">{modeCopy.lead}</p>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</section>
|
|
</section>
|
|
|
|
|
|
|
|
<section className="pt-0">
|
|
<section className="pt-0">
|
|
|
<div className="container">
|
|
<div className="container">
|
|
|
- <form id={mode === 'edit' ? 'customer-edit-form' : 'customer-new-form'} className="customer-edit-form" onSubmit={handleSubmit}>
|
|
|
|
|
|
|
+ <form id="customer-new-form" className="customer-edit-form" onSubmit={handleSubmit}>
|
|
|
<div className="row g-4">
|
|
<div className="row g-4">
|
|
|
- {mode === 'edit' ? (
|
|
|
|
|
- <div className="col-xl-4 col-lg-5">
|
|
|
|
|
- <div className="workbench-panel bg-white border-radius-8px box-shadow-extra-large p-30px h-100">
|
|
|
|
|
- <span className="fs-14 fw-700 text-base-color text-uppercase">{pageCopy.photo.badge}</span>
|
|
|
|
|
- <h2 className="fw-700 text-dark-gray fs-26 mb-25px">{pageCopy.photo.title}</h2>
|
|
|
|
|
- <div className="customer-edit-photo">
|
|
|
|
|
- <img src={photoPreview} alt={existing?.name} />
|
|
|
|
|
- <label className="btn btn-small btn-rounded btn-transparent-light-gray border border-1 border-color-dark-gray fw-700 mb-0">
|
|
|
|
|
- <input type="file" accept="image/*" className="d-none" onChange={(e) => setPhotoFile(e.target.files?.[0] || null)} />
|
|
|
|
|
- <i className="feather icon-feather-upload me-6px"></i>{pageCopy.photo.change}
|
|
|
|
|
- </label>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- ) : null}
|
|
|
|
|
-
|
|
|
|
|
- <div className={mode === 'edit' ? 'col-xl-8 col-lg-7' : 'col-xl-8 col-lg-7'}>
|
|
|
|
|
|
|
+ <div className="col-xl-8 col-lg-7">
|
|
|
<div className="workbench-panel bg-white border-radius-8px box-shadow-extra-large p-30px h-100">
|
|
<div className="workbench-panel bg-white border-radius-8px box-shadow-extra-large p-30px h-100">
|
|
|
<span className="fs-14 fw-700 text-base-color text-uppercase">{pageCopy.basic.badge}</span>
|
|
<span className="fs-14 fw-700 text-base-color text-uppercase">{pageCopy.basic.badge}</span>
|
|
|
<h2 className="fw-700 text-dark-gray fs-26 mb-25px">{pageCopy.basic.title}</h2>
|
|
<h2 className="fw-700 text-dark-gray fs-26 mb-25px">{pageCopy.basic.title}</h2>
|
|
|
<div className="row g-3">
|
|
<div className="row g-3">
|
|
|
- <div className="col-md-6"><label htmlFor="customer-name" className="customer-edit-label">{pageCopy.basic.name} {mode === 'new' ? <span className="text-base-color">*</span> : null}</label><input id="customer-name" type="text" className="form-control customer-edit-control" value={form.name} onChange={(event) => patch({ name: event.target.value })} placeholder={pageCopy.basic.namePlaceholder} required /></div>
|
|
|
|
|
- <div className="col-md-6"><label htmlFor="customer-kana" className="customer-edit-label">{pageCopy.basic.kana}</label><input id="customer-kana" type="text" className="form-control customer-edit-control" value={form.kana} onChange={(event) => patch({ kana: event.target.value })} placeholder={pageCopy.basic.kanaPlaceholder} /></div>
|
|
|
|
|
- <div className="col-md-6"><label htmlFor="customer-phone" className="customer-edit-label">{pageCopy.basic.phone} {mode === 'new' ? <span className="text-base-color">*</span> : null}</label><input id="customer-phone" type="tel" className="form-control customer-edit-control" value={form.phone} onChange={(event) => patch({ phone: event.target.value })} placeholder="090-0000-0000" required /></div>
|
|
|
|
|
|
|
+ <div className="col-md-6"><label htmlFor="customer-name" className="customer-edit-label">{pageCopy.basic.name} <span className="text-base-color">*</span></label><input id="customer-name" type="text" className="form-control customer-edit-control" value={form.name} onChange={(event) => patch({ name: event.target.value })} placeholder={pageCopy.basic.namePlaceholder} required /></div>
|
|
|
|
|
+ <div className="col-md-6"><label htmlFor="customer-kana" className="customer-edit-label">{pageCopy.basic.kana}</label><input id="customer-kana" type="text" className="form-control customer-edit-control" value={form.namePronunciation} onChange={(event) => patch({ namePronunciation: event.target.value })} placeholder={pageCopy.basic.kanaPlaceholder} /></div>
|
|
|
|
|
+ <div className="col-md-6"><label htmlFor="customer-phone" className="customer-edit-label">{pageCopy.basic.phone} <span className="text-base-color">*</span></label><input id="customer-phone" type="tel" className="form-control customer-edit-control" value={form.phone} onChange={(event) => patch({ phone: event.target.value })} placeholder="090-0000-0000" required /></div>
|
|
|
<div className="col-md-6"><label htmlFor="customer-email" className="customer-edit-label">{pageCopy.basic.email}</label><input id="customer-email" type="email" className="form-control customer-edit-control" value={form.email} onChange={(event) => patch({ email: event.target.value })} placeholder="name@example.com" /></div>
|
|
<div className="col-md-6"><label htmlFor="customer-email" className="customer-edit-label">{pageCopy.basic.email}</label><input id="customer-email" type="email" className="form-control customer-edit-control" value={form.email} onChange={(event) => patch({ email: event.target.value })} placeholder="name@example.com" /></div>
|
|
|
<div className="col-md-6"><label htmlFor="customer-birthday" className="customer-edit-label">{pageCopy.basic.birthday}</label><input id="customer-birthday" type="date" className="form-control customer-edit-control" value={form.birthday} onChange={(event) => patch({ birthday: event.target.value })} /></div>
|
|
<div className="col-md-6"><label htmlFor="customer-birthday" className="customer-edit-label">{pageCopy.basic.birthday}</label><input id="customer-birthday" type="date" className="form-control customer-edit-control" value={form.birthday} onChange={(event) => patch({ birthday: event.target.value })} /></div>
|
|
|
<div className="col-md-6">
|
|
<div className="col-md-6">
|
|
|
- <label htmlFor="customer-contact" className="customer-edit-label">{mode === 'edit' ? pageCopy.basic.contactEdit : pageCopy.basic.contactNew}</label>
|
|
|
|
|
- {mode === 'edit' ? (
|
|
|
|
|
- <select id="customer-contact" className="form-select customer-edit-control" value={form.lineStatus} onChange={(event) => patch({ lineStatus: event.target.value })}>
|
|
|
|
|
- {pageCopy.basic.contactEditOptions.map((item: string) => <option key={item} value={item}>{item}</option>)}
|
|
|
|
|
- </select>
|
|
|
|
|
- ) : (
|
|
|
|
|
- <select id="customer-contact" className="form-select customer-edit-control" value={form.contact} onChange={(event) => patch({ contact: event.target.value })}>
|
|
|
|
|
- <option value="LINE">LINE</option>
|
|
|
|
|
- <option value="Phone">{pageCopy.basic.contactNewOptions[1]}</option>
|
|
|
|
|
- <option value="Email">{pageCopy.basic.contactNewOptions[2]}</option>
|
|
|
|
|
- </select>
|
|
|
|
|
- )}
|
|
|
|
|
|
|
+ <label htmlFor="customer-contact" className="customer-edit-label">{pageCopy.basic.contactNew}</label>
|
|
|
|
|
+ <select id="customer-contact" className="form-select customer-edit-control" value={form.expectContact} onChange={(event) => patch({ expectContact: event.target.value as CustomerFormValues['expectContact'] })}>
|
|
|
|
|
+ <option value="LINE">LINE</option>
|
|
|
|
|
+ <option value="PHONE">{pageCopy.basic.contactNewOptions[1]}</option>
|
|
|
|
|
+ <option value="EMAIL">{pageCopy.basic.contactNewOptions[2]}</option>
|
|
|
|
|
+ <option value="NONE">{pageCopy.basic.contactNewOptions[3]}</option>
|
|
|
|
|
+ </select>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- {mode === 'new' ? (
|
|
|
|
|
- <div className="col-xl-4 col-lg-5">
|
|
|
|
|
- <div className="workbench-panel bg-white border-radius-8px box-shadow-extra-large p-30px h-100">
|
|
|
|
|
- <span className="fs-14 fw-700 text-base-color text-uppercase">{pageCopy.photo.badge}</span>
|
|
|
|
|
- <h2 className="fw-700 text-dark-gray fs-26 mb-25px">{pageCopy.photo.title}</h2>
|
|
|
|
|
- <div className="customer-edit-photo mb-25px">
|
|
|
|
|
- <img src={photoPreview} alt={form.name || pageCopy.basic.name} />
|
|
|
|
|
- <label className="btn btn-small btn-rounded btn-transparent-light-gray border border-1 border-color-dark-gray fw-700 mb-0">
|
|
|
|
|
- <input type="file" accept="image/*" className="d-none" onChange={(e) => setPhotoFile(e.target.files?.[0] || null)} />
|
|
|
|
|
- <i className="feather icon-feather-upload me-6px"></i>{pageCopy.photo.change}
|
|
|
|
|
- </label>
|
|
|
|
|
- </div>
|
|
|
|
|
- <span className="fs-14 fw-700 text-base-color text-uppercase">{pageCopy.nextStep.badge}</span>
|
|
|
|
|
- <h2 className="fw-700 text-dark-gray fs-26 mb-25px">{pageCopy.nextStep.title}</h2>
|
|
|
|
|
- <div className="customer-new-steps">
|
|
|
|
|
- {pageCopy.nextStep.steps.map((item: string, index: number) => <div key={item}><span>{index + 1}</span><strong>{item}</strong></div>)}
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <div className="col-xl-4 col-lg-5">
|
|
|
|
|
+ <div className="workbench-panel bg-white border-radius-8px box-shadow-extra-large p-30px h-100">
|
|
|
|
|
+ <span className="fs-14 fw-700 text-base-color text-uppercase">{pageCopy.photo.badge}</span>
|
|
|
|
|
+ <h2 className="fw-700 text-dark-gray fs-26 mb-25px">{pageCopy.photo.title}</h2>
|
|
|
|
|
+ <div className="customer-edit-photo mb-25px">
|
|
|
|
|
+ <img src={photoPreview} alt={form.name || pageCopy.basic.name} />
|
|
|
|
|
+ <label className="btn btn-small btn-rounded btn-transparent-light-gray border border-1 border-color-dark-gray fw-700 mb-0">
|
|
|
|
|
+ <input type="file" accept="image/*" className="d-none" onChange={(e) => setPhotoFile(e.target.files?.[0] || null)} />
|
|
|
|
|
+ <i className="feather icon-feather-upload me-6px"></i>{pageCopy.photo.change}
|
|
|
|
|
+ </label>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <span className="fs-14 fw-700 text-base-color text-uppercase">{pageCopy.nextStep.badge}</span>
|
|
|
|
|
+ <h2 className="fw-700 text-dark-gray fs-26 mb-25px">{pageCopy.nextStep.title}</h2>
|
|
|
|
|
+ <div className="customer-new-steps">
|
|
|
|
|
+ {pageCopy.nextStep.steps.map((item: string, index: number) => <div key={item}><span>{index + 1}</span><strong>{item}</strong></div>)}
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
- ) : null}
|
|
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div className="row g-4 mt-1">
|
|
<div className="row g-4 mt-1">
|
|
|
<div className="col-lg-6">
|
|
<div className="col-lg-6">
|
|
|
<div className="workbench-panel bg-white border-radius-8px box-shadow-extra-large p-30px h-100">
|
|
<div className="workbench-panel bg-white border-radius-8px box-shadow-extra-large p-30px h-100">
|
|
|
- <span className="fs-14 fw-700 text-base-color text-uppercase">{mode === 'edit' ? pageCopy.consultation.badgeEdit : pageCopy.consultation.badgeNew}</span>
|
|
|
|
|
- <h2 className="fw-700 text-dark-gray fs-26 mb-25px">{mode === 'edit' ? pageCopy.consultation.titleEdit : pageCopy.consultation.titleNew}</h2>
|
|
|
|
|
|
|
+ <span className="fs-14 fw-700 text-base-color text-uppercase">{pageCopy.consultation.badgeNew}</span>
|
|
|
|
|
+ <h2 className="fw-700 text-dark-gray fs-26 mb-25px">{pageCopy.consultation.titleNew}</h2>
|
|
|
<div className="row g-3">
|
|
<div className="row g-3">
|
|
|
<div className="col-md-6">
|
|
<div className="col-md-6">
|
|
|
- <label htmlFor="visit-date" className="customer-edit-label">{mode === 'edit' ? pageCopy.consultation.visitDateEdit : pageCopy.consultation.visitDateNew}</label>
|
|
|
|
|
- <input id="visit-date" type="date" className="form-control customer-edit-control" value={form.lastVisit} onChange={(event) => patch({ lastVisit: event.target.value })} />
|
|
|
|
|
|
|
+ <label htmlFor="visit-date" className="customer-edit-label">{pageCopy.consultation.visitDateNew}</label>
|
|
|
|
|
+ <input id="visit-date" type="date" className="form-control customer-edit-control" value={form.planDate} onChange={(event) => patch({ planDate: event.target.value })} />
|
|
|
</div>
|
|
</div>
|
|
|
<div className="col-md-6">
|
|
<div className="col-md-6">
|
|
|
- <label htmlFor="visit-purpose" className="customer-edit-label">{mode === 'edit' ? pageCopy.consultation.visitPurposeEdit : pageCopy.consultation.visitPurposeNew}</label>
|
|
|
|
|
- {mode === 'edit' ? (
|
|
|
|
|
- <select id="visit-purpose" className="form-select customer-edit-control" value={form.visitCycle} onChange={(event) => patch({ visitCycle: event.target.value })}>
|
|
|
|
|
- {pageCopy.consultation.visitCycleOptions.map((item: string) => <option key={item} value={item}>{item}</option>)}
|
|
|
|
|
- </select>
|
|
|
|
|
- ) : (
|
|
|
|
|
- <select id="visit-purpose" className="form-select customer-edit-control" value={form.visitCycle} onChange={(event) => patch({ visitCycle: event.target.value })}>
|
|
|
|
|
- {pageCopy.consultation.visitPurposeOptions.map((item: string) => <option key={item} value={item}>{item}</option>)}
|
|
|
|
|
- </select>
|
|
|
|
|
- )}
|
|
|
|
|
|
|
+ <label htmlFor="visit-purpose" className="customer-edit-label">{pageCopy.consultation.visitPurposeNew}</label>
|
|
|
|
|
+ <select id="visit-purpose" className="form-select customer-edit-control" value={form.visitPurpose} onChange={(event) => patch({ visitPurpose: event.target.value as CustomerFormValues['visitPurpose'] })}>
|
|
|
|
|
+ <option value="">{pageCopy.consultation.visitPurposePlaceholder}</option>
|
|
|
|
|
+ <option value="CUT_DYE">{pageCopy.consultation.visitPurposeOptions[0]}</option>
|
|
|
|
|
+ <option value="CUT">{pageCopy.consultation.visitPurposeOptions[1]}</option>
|
|
|
|
|
+ <option value="DYE">{pageCopy.consultation.visitPurposeOptions[2]}</option>
|
|
|
|
|
+ <option value="CONSULT_SIM">{pageCopy.consultation.visitPurposeOptions[3]}</option>
|
|
|
|
|
+ </select>
|
|
|
</div>
|
|
</div>
|
|
|
- <div className="col-12"><label htmlFor="customer-concern" className="customer-edit-label">{mode === 'edit' ? pageCopy.consultation.concernEdit : pageCopy.consultation.concernNew}</label><textarea id="customer-concern" className="form-control customer-edit-control" rows={4} value={form.concern} onChange={(event) => patch({ concern: event.target.value })} placeholder={pageCopy.consultation.concernPlaceholder}></textarea></div>
|
|
|
|
|
- <div className="col-12"><label htmlFor="style-image" className="customer-edit-label">{mode === 'edit' ? pageCopy.consultation.styleEdit : pageCopy.consultation.styleNew}</label><textarea id="style-image" className="form-control customer-edit-control" rows={4} value={form.desiredImage} onChange={(event) => patch({ desiredImage: event.target.value })} placeholder={pageCopy.consultation.stylePlaceholder}></textarea></div>
|
|
|
|
|
|
|
+ <div className="col-md-6"><label htmlFor="customer-trouble" className="customer-edit-label">{pageCopy.consultation.concernNew}</label><textarea id="customer-trouble" className="form-control customer-edit-control" rows={4} value={form.trouble} onChange={(event) => patch({ trouble: event.target.value })} placeholder={pageCopy.consultation.concernPlaceholder}></textarea></div>
|
|
|
|
|
+ <div className="col-md-6"><label htmlFor="customer-consult-content" className="customer-edit-label">{pageCopy.consultation.consultContent}</label><textarea id="customer-consult-content" className="form-control customer-edit-control" rows={4} value={form.consultContent} onChange={(event) => patch({ consultContent: event.target.value })} placeholder={pageCopy.consultation.concernPlaceholder}></textarea></div>
|
|
|
|
|
+ <div className="col-12"><label htmlFor="style-image" className="customer-edit-label">{pageCopy.consultation.styleNew}</label><textarea id="style-image" className="form-control customer-edit-control" rows={4} value={form.expectLook} onChange={(event) => patch({ expectLook: event.target.value })} placeholder={pageCopy.consultation.stylePlaceholder}></textarea></div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div className="col-lg-6">
|
|
<div className="col-lg-6">
|
|
|
<div className="workbench-panel bg-white border-radius-8px box-shadow-extra-large p-30px h-100">
|
|
<div className="workbench-panel bg-white border-radius-8px box-shadow-extra-large p-30px h-100">
|
|
|
- <span className="fs-14 fw-700 text-base-color text-uppercase">{mode === 'edit' ? pageCopy.hair.badgeEdit : pageCopy.hair.badgeNew}</span>
|
|
|
|
|
- <h2 className="fw-700 text-dark-gray fs-26 mb-25px">{mode === 'edit' ? pageCopy.hair.titleEdit : pageCopy.hair.titleNew}</h2>
|
|
|
|
|
|
|
+ <span className="fs-14 fw-700 text-base-color text-uppercase">{pageCopy.hair.badgeNew}</span>
|
|
|
|
|
+ <h2 className="fw-700 text-dark-gray fs-26 mb-25px">{pageCopy.hair.titleNew}</h2>
|
|
|
<div className="row g-3">
|
|
<div className="row g-3">
|
|
|
<div className="col-md-6">
|
|
<div className="col-md-6">
|
|
|
<label htmlFor="hair-length" className="customer-edit-label">{pageCopy.hair.fieldNewLeft}</label>
|
|
<label htmlFor="hair-length" className="customer-edit-label">{pageCopy.hair.fieldNewLeft}</label>
|
|
|
- <select id="hair-length" className="form-select customer-edit-control" value={form.hairLength} onChange={(event) => patch({ hairLength: event.target.value })}>
|
|
|
|
|
- <option value="Short">{pageCopy.hair.lengthOptions[0]}</option>
|
|
|
|
|
- <option value="Medium">{pageCopy.hair.lengthOptions[1]}</option>
|
|
|
|
|
- <option value="Long">{pageCopy.hair.lengthOptions[2]}</option>
|
|
|
|
|
|
|
+ <select id="hair-length" className="form-select customer-edit-control" value={form.hairLength} onChange={(event) => patch({ hairLength: event.target.value as CustomerFormValues['hairLength'] })}>
|
|
|
|
|
+ <option value="SHORT">{pageCopy.hair.lengthOptions[0]}</option>
|
|
|
|
|
+ <option value="MEDIUM">{pageCopy.hair.lengthOptions[1]}</option>
|
|
|
|
|
+ <option value="LONG">{pageCopy.hair.lengthOptions[2]}</option>
|
|
|
|
|
+ <option value="UNCONFIRM">{pageCopy.hair.lengthOptions[3]}</option>
|
|
|
</select>
|
|
</select>
|
|
|
</div>
|
|
</div>
|
|
|
<div className="col-md-6">
|
|
<div className="col-md-6">
|
|
|
<label htmlFor="hair-type" className="customer-edit-label">{pageCopy.hair.fieldNewRight}</label>
|
|
<label htmlFor="hair-type" className="customer-edit-label">{pageCopy.hair.fieldNewRight}</label>
|
|
|
- <select id="hair-type" className="form-select customer-edit-control" value={form.hairType} onChange={(event) => patch({ hairType: event.target.value })}>
|
|
|
|
|
- {pageCopy.hair.hairTypeOptions.map((item: string) => <option key={item} value={item}>{item}</option>)}
|
|
|
|
|
|
|
+ <select id="hair-type" className="form-select customer-edit-control" value={form.hairTexture} onChange={(event) => patch({ hairTexture: event.target.value as CustomerFormValues['hairTexture'] })}>
|
|
|
|
|
+ <option value="UNCONFIRM">{pageCopy.hair.hairTypeOptions[0]}</option>
|
|
|
|
|
+ <option value="THIN">{pageCopy.hair.hairTypeOptions[1]}</option>
|
|
|
|
|
+ <option value="NORMAL">{pageCopy.hair.hairTypeOptions[2]}</option>
|
|
|
|
|
+ <option value="HARD_CRUDE">{pageCopy.hair.hairTypeOptions[3]}</option>
|
|
|
|
|
+ <option value="CURLY">{pageCopy.hair.hairTypeOptions[4]}</option>
|
|
|
</select>
|
|
</select>
|
|
|
</div>
|
|
</div>
|
|
|
<div className="col-12">
|
|
<div className="col-12">
|
|
|
<label htmlFor="formula-note" className="customer-edit-label">{pageCopy.hair.fieldEditLeft}</label>
|
|
<label htmlFor="formula-note" className="customer-edit-label">{pageCopy.hair.fieldEditLeft}</label>
|
|
|
- <textarea id="formula-note" className="form-control customer-edit-control" rows={4} value={form.formulaNote} onChange={(event) => patch({ formulaNote: event.target.value })} placeholder={pageCopy.hair.formulaDefault}></textarea>
|
|
|
|
|
|
|
+ <textarea id="formula-note" className="form-control customer-edit-control" rows={4} value={form.notice} onChange={(event) => patch({ notice: event.target.value })} placeholder={pageCopy.hair.formulaDefault}></textarea>
|
|
|
</div>
|
|
</div>
|
|
|
<div className="col-12">
|
|
<div className="col-12">
|
|
|
<label htmlFor="allergy-note" className="customer-edit-label">{pageCopy.hair.fieldEditRight}</label>
|
|
<label htmlFor="allergy-note" className="customer-edit-label">{pageCopy.hair.fieldEditRight}</label>
|
|
|
- <textarea id="allergy-note" className="form-control customer-edit-control" rows={4} value={form.allergyNote} onChange={(event) => patch({ allergyNote: event.target.value })} placeholder={pageCopy.hair.staffPlaceholder}></textarea>
|
|
|
|
|
|
|
+ <textarea id="allergy-note" className="form-control customer-edit-control" rows={4} value={form.allergy} onChange={(event) => patch({ allergy: event.target.value })} placeholder={pageCopy.hair.staffPlaceholder}></textarea>
|
|
|
</div>
|
|
</div>
|
|
|
<div className="col-12">
|
|
<div className="col-12">
|
|
|
<label htmlFor="staff-note-second" className="customer-edit-label">{pageCopy.hair.staffSecond}</label>
|
|
<label htmlFor="staff-note-second" className="customer-edit-label">{pageCopy.hair.staffSecond}</label>
|
|
|
- <textarea id="staff-note-second" className="form-control customer-edit-control" rows={4} value={form.privateNote} onChange={(event) => patch({ privateNote: event.target.value })} placeholder={pageCopy.hair.staffSecondPlaceholder}></textarea>
|
|
|
|
|
|
|
+ <textarea id="staff-note-second" className="form-control customer-edit-control" rows={4} value={form.innerRemark} onChange={(event) => patch({ innerRemark: event.target.value })} placeholder={pageCopy.hair.staffSecondPlaceholder}></textarea>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -230,58 +201,46 @@ export function CustomerFormPage({ mode }: { mode: 'new' | 'edit' }) {
|
|
|
<div className="d-flex align-items-center justify-content-between flex-wrap gap-2 mb-25px">
|
|
<div className="d-flex align-items-center justify-content-between flex-wrap gap-2 mb-25px">
|
|
|
<div>
|
|
<div>
|
|
|
<span className="fs-14 fw-700 text-base-color text-uppercase">{pageCopy.follow.badge}</span>
|
|
<span className="fs-14 fw-700 text-base-color text-uppercase">{pageCopy.follow.badge}</span>
|
|
|
- <h2 className="fw-700 text-dark-gray fs-26 mb-0">{mode === 'edit' ? pageCopy.follow.titleEdit : pageCopy.follow.titleNew}</h2>
|
|
|
|
|
|
|
+ <h2 className="fw-700 text-dark-gray fs-26 mb-0">{pageCopy.follow.titleNew}</h2>
|
|
|
</div>
|
|
</div>
|
|
|
- <span className="workbench-badge">{mode === 'edit' ? pageCopy.follow.statusEdit : pageCopy.follow.statusNew}</span>
|
|
|
|
|
|
|
+ <span className="workbench-badge">{pageCopy.follow.statusNew}</span>
|
|
|
</div>
|
|
</div>
|
|
|
<div className="row g-3">
|
|
<div className="row g-3">
|
|
|
<div className="col-lg-4 col-md-6">
|
|
<div className="col-lg-4 col-md-6">
|
|
|
- <label htmlFor="follow-timing" className="customer-edit-label">{mode === 'edit' ? pageCopy.follow.timingEdit : pageCopy.follow.timingNew}</label>
|
|
|
|
|
- {mode === 'edit' ? (
|
|
|
|
|
- <input id="follow-timing" type="date" className="form-control customer-edit-control" value={form.followTiming} onChange={(event) => patch({ followTiming: event.target.value })} />
|
|
|
|
|
- ) : (
|
|
|
|
|
- <select id="follow-timing" className="form-select customer-edit-control" value={form.followTiming} onChange={(event) => patch({ followTiming: event.target.value })}>
|
|
|
|
|
- {pageCopy.follow.timingOptions.map((item: string) => <option key={item} value={item}>{item}</option>)}
|
|
|
|
|
- </select>
|
|
|
|
|
- )}
|
|
|
|
|
|
|
+ <label htmlFor="follow-timing" className="customer-edit-label">{pageCopy.follow.timingNew}</label>
|
|
|
|
|
+ <input id="follow-timing" type="date" className="form-control customer-edit-control" value={form.nextFollowDate} onChange={(event) => patch({ nextFollowDate: event.target.value })} />
|
|
|
</div>
|
|
</div>
|
|
|
<div className="col-lg-4 col-md-6">
|
|
<div className="col-lg-4 col-md-6">
|
|
|
- <label htmlFor="next-visit" className="customer-edit-label">{mode === 'edit' ? pageCopy.follow.nextVisitEdit : pageCopy.follow.nextVisitNew}</label>
|
|
|
|
|
- {mode === 'edit' ? (
|
|
|
|
|
- <select id="next-visit" className="form-select customer-edit-control" value={form.followStatus} onChange={(event) => patch({ followStatus: event.target.value })}>
|
|
|
|
|
- {pageCopy.follow.statusOptions.map((item: string) => <option key={item} value={item}>{item}</option>)}
|
|
|
|
|
- </select>
|
|
|
|
|
- ) : (
|
|
|
|
|
- <input id="next-visit" type="date" className="form-control customer-edit-control" value={form.nextVisit} onChange={(event) => patch({ nextVisit: event.target.value })} />
|
|
|
|
|
- )}
|
|
|
|
|
|
|
+ <label htmlFor="next-visit" className="customer-edit-label">{pageCopy.follow.nextVisitNew}</label>
|
|
|
|
|
+ <input id="next-visit" type="date" className="form-control customer-edit-control" value={form.recommendVisitDate} onChange={(event) => patch({ recommendVisitDate: event.target.value })} />
|
|
|
</div>
|
|
</div>
|
|
|
<div className="col-lg-4 col-md-6">
|
|
<div className="col-lg-4 col-md-6">
|
|
|
- <label htmlFor="template-source" className="customer-edit-label">{mode === 'edit' ? pageCopy.follow.templateEdit : pageCopy.follow.templateNew}</label>
|
|
|
|
|
- {mode === 'edit' ? (
|
|
|
|
|
- <select id="template-source" className="form-select customer-edit-control" value={form.contact} onChange={(event) => patch({ contact: event.target.value })}>
|
|
|
|
|
- <option value="LINE">LINE</option>
|
|
|
|
|
- <option value="Phone">{pageCopy.follow.contactOptions[1]}</option>
|
|
|
|
|
- <option value="Email">{pageCopy.follow.contactOptions[2]}</option>
|
|
|
|
|
- </select>
|
|
|
|
|
- ) : (
|
|
|
|
|
- <select id="template-source" className="form-select customer-edit-control" value={form.followStatus} onChange={(event) => patch({ followStatus: event.target.value })}>
|
|
|
|
|
- {pageCopy.follow.templateOptions.map((item: string) => <option key={item} value={item}>{item}</option>)}
|
|
|
|
|
- </select>
|
|
|
|
|
- )}
|
|
|
|
|
|
|
+ <label htmlFor="template-source" className="customer-edit-label">{pageCopy.follow.templateNew}</label>
|
|
|
|
|
+ <select id="template-source" className="form-select customer-edit-control" value={form.firstSuggestHair} onChange={(event) => patch({ firstSuggestHair: event.target.value as CustomerFormValues['firstSuggestHair'] })}>
|
|
|
|
|
+ <option value="AUTO">{pageCopy.follow.templateOptions[0]}</option>
|
|
|
|
|
+ <option value="LONG">{pageCopy.follow.templateOptions[1]}</option>
|
|
|
|
|
+ <option value="MEDIUM">{pageCopy.follow.templateOptions[2]}</option>
|
|
|
|
|
+ <option value="SHORT">{pageCopy.follow.templateOptions[3]}</option>
|
|
|
|
|
+ </select>
|
|
|
</div>
|
|
</div>
|
|
|
- <div className="col-12"><label htmlFor="follow-message" className="customer-edit-label">{mode === 'edit' ? pageCopy.follow.messageEdit : pageCopy.follow.messageNew}</label><textarea id="follow-message" className="form-control customer-edit-control" rows={4} value={form.followMessage} onChange={(event) => patch({ followMessage: event.target.value })}></textarea></div>
|
|
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div className="customer-edit-actions workbench-panel border-radius-8px p-25px mt-4">
|
|
<div className="customer-edit-actions workbench-panel border-radius-8px p-25px mt-4">
|
|
|
<div>
|
|
<div>
|
|
|
- <strong>{mode === 'edit' ? pageCopy.submit.titleEdit : pageCopy.submit.titleNew}</strong>
|
|
|
|
|
- <span>{mode === 'edit' ? pageCopy.submit.leadEdit : pageCopy.submit.leadNew}</span>
|
|
|
|
|
|
|
+ <strong>{pageCopy.submit.titleNew}</strong>
|
|
|
|
|
+ <span>{pageCopy.submit.leadNew}</span>
|
|
|
</div>
|
|
</div>
|
|
|
- <div className="d-flex flex-wrap gap-2 align-items-center">
|
|
|
|
|
- {error ? <span className="fs-14 text-red me-2" role="alert">{error}</span> : null}
|
|
|
|
|
- <Link to={mode === 'edit' ? detailPath : path('/customers')} className="btn btn-large btn-rounded btn-transparent-light-gray border border-1 border-color-dark-gray fw-700">{copy.common.cancel}</Link>
|
|
|
|
|
- <button type="submit" disabled={submitting} className="btn btn-large btn-rounded btn-base-color btn-box-shadow fw-700"><i className={`feather ${mode === 'edit' ? 'icon-feather-save' : 'icon-feather-user-plus'} me-10px`}></i>{modeCopy.submit}</button>
|
|
|
|
|
|
|
+ <div className="customer-edit-action-panel">
|
|
|
|
|
+ {error ? (
|
|
|
|
|
+ <div className="customer-edit-action-feedback" role="alert">
|
|
|
|
|
+ {error}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ ) : null}
|
|
|
|
|
+ <div className="customer-edit-action-buttons">
|
|
|
|
|
+ <Link to={path('/customers')} className="btn btn-large btn-rounded btn-transparent-light-gray border border-1 border-color-dark-gray fw-700">{copy.common.cancel}</Link>
|
|
|
|
|
+ <button type="submit" disabled={submitting} className="btn btn-large btn-rounded btn-base-color btn-box-shadow fw-700"><i className="feather icon-feather-user-plus me-10px"></i>{modeCopy.submit}</button>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</form>
|
|
</form>
|