434 lines
13 KiB
TypeScript
434 lines
13 KiB
TypeScript
'use client'
|
||
|
||
import {zodResolver} from '@hookform/resolvers/zod'
|
||
import dynamic from 'next/dynamic'
|
||
import React, {useEffect, useMemo, useRef, useState} from 'react'
|
||
import {useFieldArray, useForm} from 'react-hook-form'
|
||
import toast from 'react-hot-toast'
|
||
import {z} from 'zod'
|
||
|
||
import {onProductCreateAction} from '@/actions/admin/product'
|
||
import {i18nDefaultLocale, i18nLocales} from '@/i18n-config'
|
||
import {BaseEditorConfig} from '@/lib/config/editor'
|
||
import {createProductFormSchema} from '@/lib/schemas/admin/product'
|
||
import {toEmptyParams} from '@/lib/utils'
|
||
import {Button} from '@/ui/button'
|
||
import {
|
||
Form,
|
||
FormControl,
|
||
FormDescription,
|
||
FormField,
|
||
FormItem,
|
||
FormLabel,
|
||
FormMessage
|
||
} from '@/ui/form'
|
||
import {Input} from '@/ui/input'
|
||
import {Switch} from '@/ui/switch'
|
||
import {Tabs, TabsContent, TabsList, TabsTrigger} from '@/ui/tabs'
|
||
|
||
const JoditEditor = dynamic(() => import('jodit-react'), {ssr: false})
|
||
|
||
let localesValues = {
|
||
title: '',
|
||
shortTitle: '',
|
||
headingTitle: '',
|
||
description: '',
|
||
content: '',
|
||
instruction: ''
|
||
}
|
||
|
||
let metaValues = {
|
||
title: '',
|
||
description: '',
|
||
keywords: '',
|
||
author: ''
|
||
}
|
||
|
||
export default function ProductCreateEditForm({data}: {data?: any}) {
|
||
const [loading, setLoading] = useState(false)
|
||
const [error, setError] = useState('')
|
||
const [success, setSuccess] = useState('')
|
||
const [description0, setDescription0] = useState(
|
||
data?.locales[0].description || ''
|
||
)
|
||
const [description1, setDescription1] = useState(
|
||
data?.locales[1].description || ''
|
||
)
|
||
const [content0, setContent0] = useState(data?.locales[0].content || '')
|
||
const [content1, setContent1] = useState(data?.locales[1].content || '')
|
||
const [instruction0, setInstruction0] = useState(
|
||
data?.locales[0].instruction || ''
|
||
)
|
||
const [instruction1, setInstruction1] = useState(
|
||
data?.locales[1].instruction || ''
|
||
)
|
||
const editor = useRef(null) //declared a null value
|
||
|
||
const config = useMemo(() => BaseEditorConfig, [])
|
||
|
||
const form = useForm<z.infer<typeof createProductFormSchema>>({
|
||
resolver: zodResolver(createProductFormSchema),
|
||
mode: 'onBlur',
|
||
defaultValues: data
|
||
? (data => {
|
||
const {locales, meta} = data
|
||
|
||
return {
|
||
published: data.toStore[0].published,
|
||
price: data.toStore[0].price,
|
||
pricePromotional: data.toStore[0].pricePromotional,
|
||
image: data.image,
|
||
locales: toEmptyParams(locales) as any,
|
||
meta: meta
|
||
? (toEmptyParams(meta) as any)
|
||
: [{...metaValues}, {...metaValues}]
|
||
}
|
||
})(data)
|
||
: {
|
||
published: false,
|
||
price: '0',
|
||
pricePromotional: '0',
|
||
image: '',
|
||
locales: [
|
||
{lang: 'uk', ...localesValues},
|
||
{lang: 'ru', ...localesValues}
|
||
],
|
||
meta: [{...metaValues}, {...metaValues}]
|
||
}
|
||
})
|
||
|
||
const {register, setValue} = form
|
||
|
||
useEffect(() => {
|
||
register('locales.0.description')
|
||
register('locales.0.content')
|
||
register('locales.0.instruction')
|
||
register('locales.1.description')
|
||
register('locales.1.content')
|
||
register('locales.1.instruction')
|
||
}, [register])
|
||
|
||
const {fields: localeFields} = useFieldArray({
|
||
name: 'locales',
|
||
control: form.control
|
||
})
|
||
|
||
const {fields: metaFields} = useFieldArray({
|
||
name: 'meta',
|
||
control: form.control
|
||
})
|
||
|
||
console.log(form.formState.errors)
|
||
|
||
const onSubmit = async (values: z.infer<typeof createProductFormSchema>) => {
|
||
setLoading(true)
|
||
onProductCreateAction(values).then((res: any) => {
|
||
if (res?.error) {
|
||
setError(res?.error)
|
||
setSuccess('')
|
||
setLoading(false)
|
||
toast.error(res?.error)
|
||
} else {
|
||
setSuccess(res?.success as string)
|
||
setError('')
|
||
setLoading(false)
|
||
toast.success(res?.success)
|
||
}
|
||
})
|
||
}
|
||
|
||
return (
|
||
<Form {...form}>
|
||
<form
|
||
action=''
|
||
onSubmit={form.handleSubmit(onSubmit)}
|
||
className='bgs-grasy-50/50 mx-auto mb-8 min-w-[640px] max-w-[992px] flex-1 space-y-5 rounded-lg border p-4'
|
||
>
|
||
<div className='mx-auto my-4 w-full space-y-4'>
|
||
<h1 className='mb-6 text-center text-2xl font-bold text-brand-violet'>
|
||
ДОДАВАННЯ ТОВАРУ ДО БАЗИ
|
||
</h1>
|
||
<div className='my-4 space-y-4'>
|
||
<FormField
|
||
control={form.control}
|
||
name='published'
|
||
render={({field}) => (
|
||
<FormItem className='flex flex-row items-center justify-between rounded-lg border bg-gray-50 p-4'>
|
||
<div className='space-y-0.5'>
|
||
<FormLabel className='text-base'>Опублікувати</FormLabel>
|
||
<FormDescription>
|
||
Відразу після збереження буде розміщено на сайті
|
||
</FormDescription>
|
||
</div>
|
||
<FormControl>
|
||
<Switch
|
||
checked={field.value}
|
||
onCheckedChange={field.onChange}
|
||
/>
|
||
</FormControl>
|
||
</FormItem>
|
||
)}
|
||
/>
|
||
<div className='flex flex-row items-center justify-between gap-4 rounded-lg border bg-gray-50 p-4'>
|
||
<div className='w-1/2'>
|
||
<FormField
|
||
control={form.control}
|
||
name='price'
|
||
render={({field}) => (
|
||
<FormItem className={'w-full'}>
|
||
<FormLabel>Ціна за одиницю товару</FormLabel>
|
||
<FormControl>
|
||
<Input type='text' placeholder='' {...field} />
|
||
</FormControl>
|
||
<FormMessage />
|
||
</FormItem>
|
||
)}
|
||
/>
|
||
</div>
|
||
<div className='w-1/2'>
|
||
<FormField
|
||
control={form.control}
|
||
name='pricePromotional'
|
||
render={({field}) => (
|
||
<FormItem className={'w-full'}>
|
||
<FormLabel>Акційна Ціна</FormLabel>
|
||
<FormControl>
|
||
<Input type='text' placeholder='' {...field} />
|
||
</FormControl>
|
||
<FormMessage />
|
||
</FormItem>
|
||
)}
|
||
/>
|
||
</div>
|
||
</div>
|
||
<fieldset className='flex gap-4 rounded-lg border bg-gray-50 p-4'>
|
||
<FormField
|
||
control={form.control}
|
||
name='image'
|
||
render={({field}) => (
|
||
<FormItem className={'w-full'}>
|
||
<FormLabel>Головне зображення</FormLabel>
|
||
<FormControl>
|
||
<Input type='text' placeholder='' {...field} />
|
||
</FormControl>
|
||
<FormDescription>
|
||
Вкажіть шліх до зображення відносно публічної папки
|
||
</FormDescription>
|
||
<FormMessage />
|
||
</FormItem>
|
||
)}
|
||
/>
|
||
</fieldset>
|
||
</div>
|
||
<Tabs
|
||
defaultValue={i18nDefaultLocale}
|
||
className='min-h-[560px] rounded-lg border p-4'
|
||
>
|
||
<TabsList className='grid w-full grid-cols-2'>
|
||
{i18nLocales.map(locale => (
|
||
<TabsTrigger key={locale.icon} value={locale.code}>
|
||
{locale.nameUkr}
|
||
</TabsTrigger>
|
||
))}
|
||
</TabsList>
|
||
{localeFields.map((_, index) => (
|
||
<TabsContent
|
||
id={`form-tab-${form.getValues(`locales.${index}.lang`)}`}
|
||
value={form.getValues(`locales.${index}.lang`)}
|
||
key={index}
|
||
className='space-y-4'
|
||
>
|
||
<FormField
|
||
control={form.control}
|
||
key={index}
|
||
name={`locales.${index}.lang`}
|
||
render={({field}) => (
|
||
<FormItem className={'w-full'}>
|
||
{/*<FormLabel>Мова</FormLabel>*/}
|
||
<FormControl>
|
||
<Input type='hidden' placeholder='' {...field} />
|
||
</FormControl>
|
||
<FormMessage />
|
||
</FormItem>
|
||
)}
|
||
/>
|
||
<fieldset className='flex gap-4 rounded-lg border bg-gray-50 p-4'>
|
||
<div className='w-1/2'>
|
||
<FormField
|
||
control={form.control}
|
||
key={index + 1}
|
||
name={`locales.${index}.title`}
|
||
render={({field}) => (
|
||
<FormItem className={'w-full'}>
|
||
<FormLabel>Назва товару</FormLabel>
|
||
<FormControl>
|
||
<Input placeholder='' {...field} />
|
||
</FormControl>
|
||
<FormMessage />
|
||
</FormItem>
|
||
)}
|
||
/>
|
||
</div>
|
||
<div className='w-1/2'>
|
||
<FormField
|
||
control={form.control}
|
||
key={index + 2}
|
||
name={`locales.${index}.shortTitle`}
|
||
render={({field}) => (
|
||
<FormItem className={'w-full'}>
|
||
<FormLabel>Скорочена назва товару</FormLabel>
|
||
<FormControl>
|
||
<Input placeholder='' {...field} />
|
||
</FormControl>
|
||
<FormMessage />
|
||
</FormItem>
|
||
)}
|
||
/>
|
||
</div>
|
||
</fieldset>
|
||
|
||
<fieldset className='rounded-lg border bg-gray-50 p-4'>
|
||
<FormField
|
||
control={form.control}
|
||
key={index + 3}
|
||
name={`locales.${index}.headingTitle`}
|
||
render={({field}) => (
|
||
<FormItem className={'w-full'}>
|
||
<FormLabel>
|
||
Назва товару у описі та коротка анотація
|
||
</FormLabel>
|
||
<FormControl>
|
||
<Input placeholder='' {...field} />
|
||
</FormControl>
|
||
<FormMessage />
|
||
</FormItem>
|
||
)}
|
||
/>
|
||
|
||
<JoditEditor
|
||
key={index + 4}
|
||
ref={editor}
|
||
config={config}
|
||
value={index === 0 ? description0 : description1}
|
||
className='mt-4 w-full'
|
||
onBlur={value => {
|
||
index === 0
|
||
? setDescription0(value)
|
||
: setDescription1(value)
|
||
setValue(`locales.${index}.description`, value)
|
||
}}
|
||
/>
|
||
</fieldset>
|
||
<fieldset className='rounded-lg border bg-gray-50 p-4'>
|
||
<FormLabel>Опис товару</FormLabel>
|
||
<JoditEditor
|
||
key={index + 5}
|
||
ref={editor}
|
||
config={config}
|
||
value={index === 0 ? content0 : content1}
|
||
className='mt-4 w-full'
|
||
onBlur={value => {
|
||
index === 0 ? setContent0(value) : setContent1(value)
|
||
setValue(`locales.${index}.content`, value)
|
||
}}
|
||
/>
|
||
</fieldset>
|
||
<fieldset className='rounded-lg border bg-gray-50 p-4'>
|
||
<FormLabel>Інструкція до товару</FormLabel>
|
||
<JoditEditor
|
||
key={index + 2125}
|
||
ref={editor}
|
||
config={config}
|
||
value={index === 0 ? instruction0 : instruction1}
|
||
className='mt-4 w-full'
|
||
onBlur={value => {
|
||
index === 0
|
||
? setInstruction0(value)
|
||
: setInstruction1(value)
|
||
setValue(`locales.${index}.instruction`, value)
|
||
}}
|
||
/>
|
||
</fieldset>
|
||
</TabsContent>
|
||
))}
|
||
{metaFields.map((_, index) => (
|
||
<TabsContent
|
||
id={`form-tab-${form.getValues(`locales.${index}.lang`)}`}
|
||
value={form.getValues(`locales.${index}.lang`)}
|
||
key={index}
|
||
className='space-y-4'
|
||
>
|
||
<fieldset className='rounded-lg border bg-gray-50 p-4'>
|
||
<legend className='rounded-lg border bg-gray-200 px-16 py-1 text-xl font-bold'>
|
||
META ДАНІ
|
||
</legend>
|
||
<FormField
|
||
control={form.control}
|
||
key={index + 'meta.title'}
|
||
name={`meta.${index}.title`}
|
||
render={({field}) => (
|
||
<FormItem className={'w-full'}>
|
||
<FormLabel>Назва</FormLabel>
|
||
<FormControl>
|
||
<Input type='text' placeholder='' {...field} />
|
||
</FormControl>
|
||
<FormMessage />
|
||
</FormItem>
|
||
)}
|
||
/>
|
||
<FormField
|
||
control={form.control}
|
||
key={index + 'meta.description'}
|
||
name={`meta.${index}.description`}
|
||
render={({field}) => (
|
||
<FormItem className={'w-full'}>
|
||
<FormLabel>Опис</FormLabel>
|
||
<FormControl>
|
||
<Input type='text' placeholder='' {...field} />
|
||
</FormControl>
|
||
<FormMessage />
|
||
</FormItem>
|
||
)}
|
||
/>
|
||
<FormField
|
||
control={form.control}
|
||
key={index + 'meta.keywords'}
|
||
name={`meta.${index}.keywords`}
|
||
render={({field}) => (
|
||
<FormItem className={'w-full'}>
|
||
<FormLabel>Ключові слова</FormLabel>
|
||
<FormControl>
|
||
<Input type='text' placeholder='' {...field} />
|
||
</FormControl>
|
||
<FormMessage />
|
||
</FormItem>
|
||
)}
|
||
/>
|
||
<FormField
|
||
control={form.control}
|
||
key={index + 'meta.author'}
|
||
name={`meta.${index}.author`}
|
||
render={({field}) => (
|
||
<FormItem className={'w-full'}>
|
||
<FormLabel>Автор</FormLabel>
|
||
<FormControl>
|
||
<Input type='text' placeholder='' {...field} />
|
||
</FormControl>
|
||
<FormMessage />
|
||
</FormItem>
|
||
)}
|
||
/>
|
||
</fieldset>
|
||
</TabsContent>
|
||
))}
|
||
</Tabs>
|
||
</div>
|
||
|
||
<Button type='submit' className='!mt-0 w-full'>
|
||
Створити
|
||
</Button>
|
||
</form>
|
||
</Form>
|
||
)
|
||
}
|