stuff done
This commit is contained in:
@@ -1,4 +1,48 @@
|
||||
input.bw-cart-item-counter{
|
||||
font-size: 36px;
|
||||
background: chocolate;
|
||||
.bwOrderForm {
|
||||
& > h2, & > h3 {
|
||||
@apply text-center text-brand-violet text-2xl;
|
||||
}
|
||||
|
||||
[role="tablist"] {
|
||||
@apply bg-transparent rounded-none shadow-none m-0 pb-5 border-b-2 border-brand-violet h-[unset];
|
||||
|
||||
button {
|
||||
@apply justify-start rounded-none font-normal text-xl pl-0;
|
||||
}
|
||||
|
||||
[data-state=active] {
|
||||
@apply text-brand-violet shadow-none;
|
||||
}
|
||||
[data-state=inactive] {
|
||||
@apply text-gray-600 ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.registeredForm{
|
||||
/*@apply bg-brand-yellow-100;*/
|
||||
|
||||
& > h2, & > h3 {
|
||||
@apply text-brand-violet text-2xl mt-9 mb-2;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
@apply md:flex md:items-start md:justify-between md:gap-8
|
||||
}
|
||||
|
||||
label {
|
||||
@apply text-lg font-normal block mt-8 leading-none;
|
||||
}
|
||||
|
||||
input {
|
||||
@apply border-t-0 border-r-0 border-l-0 border-stone-400 rounded-none text-foreground text-lg p-0;
|
||||
}
|
||||
|
||||
textarea {
|
||||
@apply min-h-[72px] w-full border-b border-stone-400 p-2 ;
|
||||
}
|
||||
|
||||
[role="combobox"] {
|
||||
@apply w-full text-lg pl-0 text-foreground border-t-0 h-[unset] pb-2 border-r-0 border-l-0 rounded-none shadow-none border-stone-400;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
// import styles from '@/components/pages/cart/cart.module.scss'
|
||||
import {Minus, Plus} from 'lucide-react'
|
||||
import {Minus, Plus, X} from 'lucide-react'
|
||||
import Image from 'next/image'
|
||||
|
||||
import {Link} from '@/i18n/routing'
|
||||
import useCartStore, {CartItem} from '@/store/cart-store'
|
||||
import {Button} from '@/ui/button'
|
||||
|
||||
export default function CartItems() {
|
||||
const {cartItems} = useCartStore()
|
||||
|
||||
export default function CartItems({cartItems}: {cartItems: CartItem[]}) {
|
||||
const {increaseQuantity, decreaseQuantity, removeItemFromCart} =
|
||||
useCartStore()
|
||||
|
||||
const onIncreaseQuantity = (productId: number) => {
|
||||
increaseQuantity(productId)
|
||||
}
|
||||
@@ -23,22 +21,33 @@ export default function CartItems() {
|
||||
removeItemFromCart(productId)
|
||||
}
|
||||
|
||||
if (cartItems && cartItems.length > 0) {
|
||||
return (
|
||||
<>
|
||||
{cartItems?.map((item: CartItem, i: number) => (
|
||||
<div className='my-4 flex items-center' key={i}>
|
||||
return (
|
||||
<>
|
||||
{cartItems?.map((item: CartItem, i: number) => (
|
||||
<article key={i} className='bxg-emerald-200 mb-6'>
|
||||
<h3 className='bxg-brand-yellow-300 flex w-full items-center justify-between text-foreground'>
|
||||
<div className='text-lg font-medium'>{item.title}</div>
|
||||
<div className='w-16 flex-none text-right'>
|
||||
<Button
|
||||
variant={'ghost'}
|
||||
className='rounded-0 h-[3rem] w-[3rem] px-0 text-brand-violet'
|
||||
onClick={() => onRemoveItem(item.id)}
|
||||
/*title={t('clear_cart')}*/
|
||||
>
|
||||
<X />
|
||||
</Button>
|
||||
</div>
|
||||
</h3>
|
||||
<div className='flex items-center'>
|
||||
<div className='col'>
|
||||
{item.title}
|
||||
<Image
|
||||
src={(item?.image || '').replace('.jpg', '-thumb.jpg')}
|
||||
alt=''
|
||||
width={96}
|
||||
height={96}
|
||||
className='rounded-md border'
|
||||
width={64}
|
||||
height={64}
|
||||
style={{
|
||||
width: '96px',
|
||||
height: '96px',
|
||||
width: '64px',
|
||||
height: '64px',
|
||||
objectFit: 'cover'
|
||||
}}
|
||||
/>
|
||||
@@ -47,17 +56,17 @@ export default function CartItems() {
|
||||
<div className='flex w-16 flex-none items-center justify-center'>
|
||||
<Button
|
||||
variant={'outline'}
|
||||
className='rounded-0 h-[3rem] w-[3rem] text-2xl leading-none text-brand-violet'
|
||||
className='rounded-0 h-[3rem] w-[3rem] text-brand-violet'
|
||||
onClick={() => onDecreaseQuantity(item.id)}
|
||||
>
|
||||
<Minus />
|
||||
</Button>
|
||||
<div className='mx-4 text-xl font-bold leading-none text-brand-violet'>
|
||||
<div className='mx-4 text-xl font-bold text-brand-violet'>
|
||||
{item.quantity}
|
||||
</div>
|
||||
<Button
|
||||
variant={'outline'}
|
||||
className='rounded-0 h-[3rem] w-[3rem] text-2xl leading-none text-brand-violet'
|
||||
className='rounded-0 h-[3rem] w-[3rem] text-brand-violet'
|
||||
onClick={() => onIncreaseQuantity(item.id)}
|
||||
>
|
||||
<Plus />
|
||||
@@ -68,19 +77,8 @@ export default function CartItems() {
|
||||
{(item.price * item.quantity).toFixed(2)} грн
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div className='flex h-72 flex-col items-center justify-center'>
|
||||
<h2 className='mb-5 mt-10 text-3xl font-bold'>Cart is Empty</h2>
|
||||
<Link
|
||||
href={'/catalog'}
|
||||
className='rounded-md bg-orange-500 px-6 py-2 text-white'
|
||||
>
|
||||
Продовжити покупки
|
||||
</Link>
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
290
components/pages/cart/registered-order-form.tsx
Normal file
290
components/pages/cart/registered-order-form.tsx
Normal file
@@ -0,0 +1,290 @@
|
||||
'use client'
|
||||
|
||||
import {zodResolver} from '@hookform/resolvers/zod'
|
||||
import {DeliveryOption} from '@prisma/client'
|
||||
import {useLocale} from 'next-intl'
|
||||
import React, {useEffect, useState} from 'react'
|
||||
import {useForm} from 'react-hook-form'
|
||||
import toast from 'react-hot-toast'
|
||||
import {z} from 'zod'
|
||||
|
||||
import {onPlacingOrder} from '@/actions/admin/place-order'
|
||||
import NovaPost from '@/app/[locale]/(root)/(shop)/cart/nova-post'
|
||||
import SearchAddress from '@/components/pages/cart/search-address'
|
||||
import {
|
||||
DeliveryOptionTypeDescription,
|
||||
createOrderFormSchema
|
||||
} from '@/lib/schemas/admin/order'
|
||||
import {dump} from '@/lib/utils'
|
||||
import useCartStore from '@/store/cart-store'
|
||||
import {SessionUser} from '@/types/auth'
|
||||
import {Button} from '@/ui/button'
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage
|
||||
} from '@/ui/form'
|
||||
import {Input} from '@/ui/input'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue
|
||||
} from '@/ui/select'
|
||||
|
||||
export default function RegisteredOrderForm({
|
||||
styles,
|
||||
user,
|
||||
onSubmitHandler
|
||||
}: {
|
||||
styles: string
|
||||
user?: SessionUser | null
|
||||
onSubmitHandler: any
|
||||
}) {
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [error, setError] = useState('')
|
||||
const [success, setSuccess] = useState('')
|
||||
const [deliveryOption, setDeliveryOption] = useState('')
|
||||
|
||||
const locale = useLocale()
|
||||
const [warehouseRef, setWarehouseRef] = useState(JSON.stringify({}))
|
||||
|
||||
const warehouseSubmit = (warehouse: any) => {
|
||||
setWarehouseRef(
|
||||
Object.keys(warehouse).length > 0
|
||||
? JSON.stringify(warehouse)
|
||||
: JSON.stringify({})
|
||||
)
|
||||
|
||||
setValue(
|
||||
'address',
|
||||
Object.keys(warehouse).length > 0
|
||||
? JSON.stringify(warehouse)
|
||||
: JSON.stringify({})
|
||||
)
|
||||
}
|
||||
const {cartItems, clearCart} = useCartStore()
|
||||
const form = useForm<z.infer<typeof createOrderFormSchema>>({
|
||||
resolver: zodResolver(createOrderFormSchema),
|
||||
mode: 'onBlur',
|
||||
defaultValues: {
|
||||
user_id: user ? user.id.toString() : '',
|
||||
is_quick: false,
|
||||
lang: locale,
|
||||
first_name: '',
|
||||
surname: '',
|
||||
delivery_option: '',
|
||||
phone: '',
|
||||
email: '',
|
||||
address: warehouseRef,
|
||||
notes: '',
|
||||
details: JSON.stringify(cartItems)
|
||||
}
|
||||
})
|
||||
|
||||
const {register, setValue} = form
|
||||
|
||||
useEffect(() => {
|
||||
register('delivery_option')
|
||||
register('address')
|
||||
register('details')
|
||||
}, [register])
|
||||
|
||||
const deliveryOptionHandler = (value: string) => {
|
||||
setDeliveryOption(value)
|
||||
setValue('delivery_option', value)
|
||||
}
|
||||
|
||||
const onSubmit = async (values: z.infer<typeof createOrderFormSchema>) => {
|
||||
setLoading(true)
|
||||
setValue('details', JSON.stringify(cartItems))
|
||||
onPlacingOrder(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)
|
||||
clearCart()
|
||||
toast.success(res?.success)
|
||||
}
|
||||
|
||||
onSubmitHandler(res)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form className={styles} action='' onSubmit={form.handleSubmit(onSubmit)}>
|
||||
{/*<pre>{dump(user)}</pre>*/}
|
||||
<h2>1. {locale !== 'ru' ? 'Особисті дані' : 'Личные данные'}</h2>
|
||||
<fieldset>
|
||||
<div className='md:w-1/2'>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='first_name'
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>{locale !== 'ru' ? "Ім'я" : 'Имя'}*</FormLabel>
|
||||
<FormControl>
|
||||
<Input type='text' placeholder='' {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className='md:w-1/2'>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='surname'
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{locale !== 'ru' ? 'Прізвище' : 'Фамилия'}*
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input type='text' placeholder='' {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<div className='md:w-1/2'>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='phone'
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>Телефон*</FormLabel>
|
||||
<FormControl>
|
||||
<Input type='text' {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className='md:w-1/2'>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='email'
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>E-mail*</FormLabel>
|
||||
<FormControl>
|
||||
<Input type='text' {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<h2>
|
||||
2.{' '}
|
||||
{locale !== 'ru'
|
||||
? 'Інформація про доставку'
|
||||
: 'Информация о доставке'}
|
||||
</h2>
|
||||
<fieldset>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='delivery_option'
|
||||
render={({field}) => (
|
||||
<FormItem className='block w-full'>
|
||||
<FormLabel>
|
||||
{locale !== 'ru'
|
||||
? 'Варіанти доставки'
|
||||
: 'Варианты доставки'}{' '}
|
||||
</FormLabel>
|
||||
<Select
|
||||
/*onValueChange={field.onChange}*/
|
||||
onValueChange={deliveryOptionHandler}
|
||||
defaultValue={field.value}
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue
|
||||
placeholder={
|
||||
locale !== 'ru'
|
||||
? 'Оберіть варіант доставки'
|
||||
: 'Выберите вариант доставки'
|
||||
}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{Object.keys(DeliveryOption).map(
|
||||
(option: string, index: number) => (
|
||||
<SelectItem key={index} value={option}>
|
||||
{DeliveryOptionTypeDescription[option] || option}
|
||||
</SelectItem>
|
||||
)
|
||||
)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage className='ml-3' />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</fieldset>
|
||||
|
||||
{deliveryOption === 'NP' && (
|
||||
<NovaPost onSelectHandler={warehouseSubmit} />
|
||||
)}
|
||||
|
||||
{deliveryOption === 'COURIER' && (
|
||||
/*<NovaPost onWarehouseSelect={warehouseSubmit} />*/
|
||||
<SearchAddress onSelectHandler={warehouseSubmit} />
|
||||
)}
|
||||
|
||||
{deliveryOption === 'PICKUP' && (
|
||||
<div className='py-6 text-lg'>Дані де і коли можна забрати</div>
|
||||
)}
|
||||
|
||||
<fieldset>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='notes'
|
||||
render={({field}) => (
|
||||
<FormItem className='block w-full'>
|
||||
<FormLabel>
|
||||
{locale !== 'ru'
|
||||
? 'Додаткова інформація'
|
||||
: 'Дополнительная информация'}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<textarea {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
{/*<pre>{warehouseRef}</pre>*/}
|
||||
<Button
|
||||
type='submit'
|
||||
size={'lg'}
|
||||
className='float-right mx-auto mb-6 mt-16 h-[unset] w-[200px] py-2 text-xl text-brand-violet'
|
||||
>
|
||||
{locale !== 'ru' ? 'Оформити замовлення' : 'Оформить заказ'}
|
||||
</Button>
|
||||
</fieldset>
|
||||
</form>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
152
components/pages/cart/search-address.tsx
Normal file
152
components/pages/cart/search-address.tsx
Normal file
@@ -0,0 +1,152 @@
|
||||
'use client'
|
||||
|
||||
import {
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList
|
||||
} from 'cmdk'
|
||||
import {Check, ChevronsUpDown, MapPinCheck, MapPinPlus} from 'lucide-react'
|
||||
import {useLocale, useTranslations} from 'next-intl'
|
||||
import {useState} from 'react'
|
||||
import {useDebouncedCallback} from 'use-debounce'
|
||||
|
||||
import {
|
||||
type Settlement,
|
||||
Street,
|
||||
formatSettlement,
|
||||
getApi
|
||||
} from '@/lib/nova-post-helper'
|
||||
import {cn, dump} from '@/lib/utils'
|
||||
import {Button} from '@/ui/button'
|
||||
import {Command} from '@/ui/command'
|
||||
import {Popover, PopoverContent, PopoverTrigger} from '@/ui/popover'
|
||||
|
||||
const url = '/api/nova-post'
|
||||
|
||||
export default function SearchAddress({
|
||||
onSelectHandler
|
||||
}: {
|
||||
onSelectHandler: any
|
||||
}) {
|
||||
const t = useTranslations('cart.post')
|
||||
const locale = useLocale()
|
||||
const [streets, setStreets] = useState([])
|
||||
const [streetsOpen, setStreetsOpen] = useState(false)
|
||||
const [streetsValue, setStreetsValue] = useState('')
|
||||
|
||||
const handleStreetSearch = useDebouncedCallback(
|
||||
async (e: string): Promise<void> => {
|
||||
if (e.length < 3) {
|
||||
setStreets([])
|
||||
return
|
||||
}
|
||||
|
||||
const response = await getApi(url + `?scope=streets&q=` + encodeURI(e))
|
||||
|
||||
if (response.ok) {
|
||||
let json = JSON.parse(JSON.stringify(await response.json()))
|
||||
const {Addresses} = json[0]
|
||||
setStreets(Addresses)
|
||||
} else {
|
||||
setStreets([])
|
||||
}
|
||||
},
|
||||
1000
|
||||
)
|
||||
|
||||
const streetDescription = (streetsValue: string): string => {
|
||||
const street: Street | undefined = streets.find(
|
||||
(street: Street) => street.Present === streetsValue
|
||||
)
|
||||
|
||||
if (!street) {
|
||||
return ''
|
||||
}
|
||||
|
||||
return streetsValue
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='py-2'>
|
||||
{/*<pre>{dump(streets[0]['Addresses'])}</pre>*/}
|
||||
<div>
|
||||
<Popover open={streetsOpen} onOpenChange={setStreetsOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant='outline'
|
||||
role='combobox'
|
||||
/*aria-expanded={open}*/
|
||||
className='w-full justify-between border border-brand-violet'
|
||||
>
|
||||
<span className='inline-flex items-center gap-x-3'>
|
||||
{streetsValue ? (
|
||||
<>
|
||||
<MapPinCheck />
|
||||
{streetDescription(streetsValue)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<MapPinPlus />
|
||||
{locale !== 'ru' ? 'Шукати вулицю' : 'Искать улицу'}
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
<ChevronsUpDown className='opacity-50' />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className='w-[640px] p-2'>
|
||||
<Command>
|
||||
<CommandInput
|
||||
className='border border-brand-violet p-2'
|
||||
placeholder={locale !== 'ru' ? 'Почати пошук' : 'Начать поиск'}
|
||||
onValueChange={(e: string) => handleStreetSearch(e)}
|
||||
/>
|
||||
<CommandList>
|
||||
<CommandEmpty className='my-1'>{t('notFount')}</CommandEmpty>
|
||||
<CommandGroup className='max-h-[320px] w-full overflow-y-auto'>
|
||||
{streets.map((street: Street, index: number) => (
|
||||
<CommandItem
|
||||
className='my-2 flex'
|
||||
key={index}
|
||||
value={street?.Present}
|
||||
onSelect={(currentValue: string) => {
|
||||
setStreetsValue(
|
||||
currentValue === streetsValue ? '' : currentValue
|
||||
)
|
||||
|
||||
onSelectHandler(
|
||||
currentValue === streetsValue
|
||||
? {}
|
||||
: {
|
||||
Ref: street.SettlementStreetRef,
|
||||
Description: street.Present,
|
||||
DescriptionRu:
|
||||
street.SettlementStreetDescriptionRu
|
||||
}
|
||||
)
|
||||
|
||||
setStreetsOpen(false)
|
||||
}}
|
||||
>
|
||||
{street?.Present}
|
||||
<Check
|
||||
className={cn(
|
||||
'ml-auto',
|
||||
streetsValue === street?.Present
|
||||
? 'opacity-100'
|
||||
: 'opacity-0'
|
||||
)}
|
||||
/>
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -25,22 +25,23 @@ import {Link} from '@/i18n/routing'
|
||||
import {getMetaOfFile} from '@/lib/config/resources'
|
||||
import {getProductResources} from '@/lib/data/models/product'
|
||||
import {CategoryPageSqlSchema} from '@/lib/data/models/sqlSchemas'
|
||||
import {db} from '@/lib/db/prisma/client'
|
||||
import {dump, thisLocale, toPrice} from '@/lib/utils'
|
||||
import {Button} from '@/ui/button'
|
||||
import {Separator} from '@/ui/separator'
|
||||
import {Tabs, TabsContent, TabsList, TabsTrigger} from '@/ui/tabs'
|
||||
|
||||
export default async function ProductPageIndex({id}: {id: string}) {
|
||||
const t = await getTranslations('Common')
|
||||
|
||||
const data: CategoryPageSqlSchema[] = await db.$queryRawTyped(
|
||||
getProductByIdWitData(id)
|
||||
)
|
||||
|
||||
export default async function ProductPageIndex({
|
||||
data,
|
||||
id
|
||||
}: {
|
||||
data: CategoryPageSqlSchema[]
|
||||
id: string
|
||||
}) {
|
||||
const locale = await thisLocale(data)
|
||||
if (!locale) notFound()
|
||||
|
||||
const t = await getTranslations('Common')
|
||||
|
||||
const resources: ProductResource[] | null = await getProductResources(
|
||||
parseInt(id)
|
||||
)
|
||||
@@ -70,11 +71,11 @@ export default async function ProductPageIndex({id}: {id: string}) {
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
<div className='flex w-[82%] items-center justify-between'>
|
||||
<h1 className='my-4 text-3xl font-bold text-brand-violet-950'>
|
||||
<div className='flex w-full items-center justify-between'>
|
||||
<h1 className='font-heading mt-4 text-3xl font-semibold'>
|
||||
{locale.title}
|
||||
</h1>
|
||||
<AddCartButton
|
||||
{/*<AddCartButton
|
||||
product={{
|
||||
id: locale.productId,
|
||||
quantity: 1,
|
||||
@@ -82,9 +83,9 @@ export default async function ProductPageIndex({id}: {id: string}) {
|
||||
price: toPrice(locale.price),
|
||||
image: locale.image
|
||||
}}
|
||||
/>
|
||||
/>*/}
|
||||
</div>
|
||||
<Separator className='my-4 w-[82%] border-b border-brand-violet' />
|
||||
<Separator className='my-4 h-0 border-b-2 border-brand-violet' />
|
||||
<ProductCarousel images={resources} title={locale.title} />
|
||||
<Tabs defaultValue='article' className=''>
|
||||
<TabsList className='grid w-full grid-cols-2'>
|
||||
|
||||
Reference in New Issue
Block a user