290 lines
10 KiB
TypeScript
290 lines
10 KiB
TypeScript
'use client'
|
||
|
||
import React from 'react'
|
||
import MultiSelect from '@/components/ui/Selector'
|
||
import TextInput from '@/components/ui/TextInput'
|
||
import PhoneInput from '@/components/ui/PhoneInput'
|
||
import Button from '@/components/ui/Button'
|
||
import TextAreaInput from '@/components/ui/TextAreaInput'
|
||
import CheckboxInput from '@/components/ui/CheckboxInput'
|
||
import { useForm } from '@/app/hooks/useForm'
|
||
import showToast from '@/components/ui/Toast'
|
||
import { SenderPageProps, SelectOption } from '@/app/types'
|
||
import {
|
||
cargo_types,
|
||
cargo_type_translations,
|
||
transport_types,
|
||
transport_translations,
|
||
} from '@/app/constants'
|
||
|
||
const formatDateToHTML = (date: Date) => {
|
||
const year = date.getFullYear()
|
||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||
const day = String(date.getDate()).padStart(2, '0')
|
||
const hours = String(date.getHours()).padStart(2, '0')
|
||
const minutes = String(date.getMinutes()).padStart(2, '0')
|
||
return `${year}-${month}-${day}T${hours}:${minutes}`
|
||
}
|
||
|
||
const validationRules = {
|
||
transport: { required: true },
|
||
country_from: { required: true, minLength: 2 },
|
||
city_from: { required: true, minLength: 2 },
|
||
country_to: { required: true, minLength: 2 },
|
||
city_to: { required: true, minLength: 2 },
|
||
cargo_type: { required: true },
|
||
departure: {
|
||
required: true,
|
||
pattern: /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/,
|
||
},
|
||
arrival: {
|
||
required: true,
|
||
pattern: /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/,
|
||
},
|
||
contact_number: {
|
||
required: true,
|
||
minLength: 11,
|
||
pattern: /^\+?[0-9]{11,}$/,
|
||
},
|
||
comment: { required: false, minLength: 10 },
|
||
email_notification: { required: false },
|
||
}
|
||
|
||
const SenderPage = () => {
|
||
const today = formatDateToHTML(new Date())
|
||
|
||
const initialValues: SenderPageProps = {
|
||
transport: '',
|
||
country_from: '',
|
||
city_from: '',
|
||
country_to: '',
|
||
city_to: '',
|
||
cargo_type: '',
|
||
departure: '',
|
||
arrival: '',
|
||
contact_number: '',
|
||
comment: '',
|
||
email_notification: false,
|
||
}
|
||
|
||
const cargoOptions: SelectOption[] = cargo_types.map((type, index) => ({
|
||
id: index + 1,
|
||
label: cargo_type_translations[type],
|
||
value: type,
|
||
}))
|
||
|
||
const transportOptions: SelectOption[] = transport_types.map((type, index) => ({
|
||
id: index + 1,
|
||
label: transport_translations[type],
|
||
value: type,
|
||
}))
|
||
|
||
const { values, handleChange, handleSubmit } = useForm<SenderPageProps>(
|
||
initialValues,
|
||
validationRules,
|
||
async values => {
|
||
try {
|
||
// await addNewSpecialist(values, selectedImage || undefined)
|
||
showToast({
|
||
type: 'success',
|
||
message: 'Маршрут успешно создан!',
|
||
})
|
||
} catch {
|
||
showToast({
|
||
type: 'error',
|
||
message: 'Упс, что то пошло не так...',
|
||
})
|
||
}
|
||
}
|
||
)
|
||
|
||
return (
|
||
<form onSubmit={handleSubmit} className="space-y-6">
|
||
<div className="overflow-hidden rounded-2xl bg-white shadow">
|
||
<div className="p-6 sm:p-8">
|
||
<div className="space-y-8">
|
||
<div>
|
||
<h1 className="text-2xl font-semibold text-gray-900">Отправить посылку</h1>
|
||
<p className="mt-1 text-sm text-gray-600">
|
||
Заполните информацию о вашей посылке и маршруте
|
||
</p>
|
||
</div>
|
||
|
||
{/* тип груза и транспорта */}
|
||
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
||
<div>
|
||
<label htmlFor="cargo_type" className="block text-sm font-medium text-gray-700">
|
||
Тип груза
|
||
</label>
|
||
<MultiSelect
|
||
value={values.cargo_type ? [parseInt(values.cargo_type)] : []}
|
||
handleChange={e => {
|
||
handleChange({
|
||
target: {
|
||
id: 'cargo_type',
|
||
value: e.target.value[0]?.toString() || '',
|
||
},
|
||
})
|
||
}}
|
||
name="cargo_type"
|
||
options={cargoOptions}
|
||
className="mt-1"
|
||
placeholder="Выберите тип груза"
|
||
noOptionsMessage="Нет доступных типов груза"
|
||
/>
|
||
</div>
|
||
|
||
<div>
|
||
<label htmlFor="transport" className="block text-sm font-medium text-gray-700">
|
||
Способ перевозки
|
||
</label>
|
||
<MultiSelect
|
||
value={values.transport ? [parseInt(values.transport)] : []}
|
||
handleChange={e => {
|
||
handleChange({
|
||
target: {
|
||
id: 'transport',
|
||
value: e.target.value[0]?.toString() || '',
|
||
},
|
||
})
|
||
}}
|
||
name="transport"
|
||
options={transportOptions}
|
||
className="mt-1"
|
||
placeholder="Выберите способ перевозки"
|
||
noOptionsMessage="Нет доступных способов перевозки"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
{/* маршрут */}
|
||
<div>
|
||
<h2 className="mb-2 text-xl font-medium text-gray-900">Маршрут</h2>
|
||
|
||
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
||
<div className="space-y-6">
|
||
<TextInput
|
||
name="country_from"
|
||
value={values.country_from}
|
||
handleChange={handleChange}
|
||
label="Страна отправления"
|
||
placeholder="Введите страну отправления"
|
||
style="register"
|
||
/>
|
||
<TextInput
|
||
name="country_to"
|
||
value={values.country_to}
|
||
handleChange={handleChange}
|
||
label="Страна назначения"
|
||
placeholder="Введите страну назначения"
|
||
style="register"
|
||
/>
|
||
</div>
|
||
|
||
<div className="space-y-6">
|
||
<TextInput
|
||
name="city_to"
|
||
value={values.city_to}
|
||
handleChange={handleChange}
|
||
label="Город назначения"
|
||
placeholder="Введите город назначения"
|
||
style="register"
|
||
/>
|
||
|
||
<TextInput
|
||
name="country_to"
|
||
value={values.country_to}
|
||
handleChange={handleChange}
|
||
label="Страна назначения"
|
||
placeholder="Введите страну назначения"
|
||
style="register"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* даты */}
|
||
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
||
<div>
|
||
<label htmlFor="departure" className="block text-sm font-medium text-gray-700">
|
||
Дата отправления
|
||
</label>
|
||
<input
|
||
type="datetime-local"
|
||
name="departure"
|
||
id="departure"
|
||
value={values.departure}
|
||
onChange={handleChange}
|
||
min={today}
|
||
className="mt-1 block w-full rounded-xl border border-gray-300 px-3 py-2 focus:border-blue-500 focus:ring-1 focus:ring-blue-500 focus:outline-none"
|
||
/>
|
||
</div>
|
||
|
||
<div>
|
||
<label htmlFor="arrival" className="block text-sm font-medium text-gray-700">
|
||
Дата прибытия
|
||
</label>
|
||
<input
|
||
type="datetime-local"
|
||
name="arrival"
|
||
id="arrival"
|
||
value={values.arrival}
|
||
onChange={handleChange}
|
||
min={values.departure || today}
|
||
className="mt-1 block w-full rounded-xl border border-gray-300 px-3 py-2 focus:border-blue-500 focus:ring-1 focus:ring-blue-500 focus:outline-none"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
{/* контактная информация */}
|
||
<h2 className="mb-2 text-xl font-medium text-gray-900">Контактная информация</h2>
|
||
<div className="space-y-6">
|
||
<PhoneInput
|
||
value={values.contact_number}
|
||
handleChange={handleChange}
|
||
label="Контактный телефон"
|
||
operatorsInfo={false}
|
||
/>
|
||
|
||
<TextAreaInput
|
||
value={values.comment}
|
||
handleChange={handleChange}
|
||
label="Комментарий"
|
||
placeholder="Дополнительная информация о грузе или пожелания"
|
||
name="comment"
|
||
/>
|
||
|
||
<CheckboxInput
|
||
name="email_notification"
|
||
label="Уведомления"
|
||
checked={values.email_notification}
|
||
handleChange={handleChange}
|
||
enabledText="Хочу получать уведомления по email"
|
||
disabledText="Не получать уведомления"
|
||
info="Вы будете получать уведомления о важных событиях на указанный email адрес"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* кнопки действий */}
|
||
<div className="flex justify-end space-x-4">
|
||
<Button
|
||
type="button"
|
||
text="Отмена"
|
||
className="border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:outline-none"
|
||
/>
|
||
|
||
<Button
|
||
type="submit"
|
||
text="Создать маршрут"
|
||
className="bg-orange hover:bg-orange/80 focus:ring-red w-1/3 border border-gray-300 py-2 text-sm font-medium text-white shadow-sm focus:ring-2 focus:ring-offset-2 focus:outline-none"
|
||
/>
|
||
</div>
|
||
</form>
|
||
)
|
||
}
|
||
|
||
export default SenderPage
|