order create
This commit is contained in:
BIN
public/logos/product.png
Normal file
BIN
public/logos/product.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 79 KiB |
BIN
src/assets/product.png
Normal file
BIN
src/assets/product.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 79 KiB |
@@ -5,25 +5,71 @@ import { AxiosResponse } from 'axios';
|
|||||||
interface CartItem {
|
interface CartItem {
|
||||||
id: string;
|
id: string;
|
||||||
cart_item: {
|
cart_item: {
|
||||||
id: string;
|
id: number;
|
||||||
product_name: string;
|
product: {
|
||||||
product_id: string;
|
id: number;
|
||||||
product_image: string;
|
images: {
|
||||||
|
id: number;
|
||||||
|
image: string;
|
||||||
|
}[];
|
||||||
|
liked: boolean;
|
||||||
|
meansurement: null | string;
|
||||||
|
inventory_id: null | string;
|
||||||
|
product_id: string;
|
||||||
|
code: string;
|
||||||
|
name: string;
|
||||||
|
short_name: string;
|
||||||
|
weight_netto: null | string;
|
||||||
|
weight_brutto: null | string;
|
||||||
|
litr: null | string;
|
||||||
|
box_type_code: null | string;
|
||||||
|
box_quant: null | string;
|
||||||
|
groups: number[];
|
||||||
|
state: 'A' | 'P';
|
||||||
|
barcodes: string | null;
|
||||||
|
article_code: null | string;
|
||||||
|
marketing_group_code: null | string;
|
||||||
|
inventory_kinds: { id: number; name: string }[];
|
||||||
|
sector_codes: { id: number; code: string }[];
|
||||||
|
prices: {
|
||||||
|
id: number;
|
||||||
|
price: string;
|
||||||
|
price_type: {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
code: string;
|
||||||
|
};
|
||||||
|
}[];
|
||||||
|
};
|
||||||
quantity: number;
|
quantity: number;
|
||||||
product_price: number;
|
|
||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderCreateBody {
|
export interface OrderCreateBody {
|
||||||
items: {
|
order: {
|
||||||
product_id: number;
|
filial_code: string;
|
||||||
quantity: number;
|
delivery_date: string;
|
||||||
|
room_code: string;
|
||||||
|
robot_code: string;
|
||||||
|
deal_time: string;
|
||||||
|
status: string;
|
||||||
|
sales_manager_code: string;
|
||||||
|
person_code: string;
|
||||||
|
currency_code: string;
|
||||||
|
owner_person_code: string;
|
||||||
|
note: string;
|
||||||
|
order_products: [
|
||||||
|
{
|
||||||
|
inventory_kind: string;
|
||||||
|
product_code: string;
|
||||||
|
on_balance: string;
|
||||||
|
order_quant: number;
|
||||||
|
price_type_code: string;
|
||||||
|
product_price: string;
|
||||||
|
warehouse_code: string;
|
||||||
|
},
|
||||||
|
];
|
||||||
}[];
|
}[];
|
||||||
comment: string;
|
|
||||||
long: number;
|
|
||||||
lat: number;
|
|
||||||
date: string;
|
|
||||||
time: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const cart_api = {
|
export const cart_api = {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import { useTranslations } from 'next-intl';
|
|||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
|
import ProductBanner from '@/assets/product.png';
|
||||||
|
|
||||||
const CartPage = () => {
|
const CartPage = () => {
|
||||||
const { cart_id } = useCartId();
|
const { cart_id } = useCartId();
|
||||||
@@ -102,7 +103,10 @@ const CartPage = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const subtotal = cartItems.reduce(
|
const subtotal = cartItems.reduce(
|
||||||
(sum, item) => sum + item.product_price * Number(item.quantity),
|
(sum, item) =>
|
||||||
|
sum +
|
||||||
|
Math.max(...item.product.prices.map((e) => Number(e.price))) *
|
||||||
|
Number(item.quantity),
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -145,7 +149,9 @@ const CartPage = () => {
|
|||||||
<Button
|
<Button
|
||||||
variant="destructive"
|
variant="destructive"
|
||||||
size="icon"
|
size="icon"
|
||||||
onClick={() => deleteCartItem({ cart_item_id: item.id })}
|
onClick={() =>
|
||||||
|
deleteCartItem({ cart_item_id: String(item.id) })
|
||||||
|
}
|
||||||
className="absolute right-2 w-7 h-7 top-2 cursor-pointer"
|
className="absolute right-2 w-7 h-7 top-2 cursor-pointer"
|
||||||
>
|
>
|
||||||
<Trash className="size-4" />
|
<Trash className="size-4" />
|
||||||
@@ -153,8 +159,12 @@ const CartPage = () => {
|
|||||||
|
|
||||||
<div className="w-24 h-40 bg-gray-100 rounded-lg flex-shrink-0 overflow-hidden">
|
<div className="w-24 h-40 bg-gray-100 rounded-lg flex-shrink-0 overflow-hidden">
|
||||||
<Image
|
<Image
|
||||||
src={BASE_URL + item.product_image}
|
src={
|
||||||
alt={item.product_name}
|
item.product.images.length > 0
|
||||||
|
? BASE_URL + item.product.images[0].image
|
||||||
|
: ProductBanner
|
||||||
|
}
|
||||||
|
alt={item.product.name}
|
||||||
width={500}
|
width={500}
|
||||||
height={500}
|
height={500}
|
||||||
className="object-cover"
|
className="object-cover"
|
||||||
@@ -164,11 +174,16 @@ const CartPage = () => {
|
|||||||
|
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<h3 className="font-semibold text-lg mb-1">
|
<h3 className="font-semibold text-lg mb-1">
|
||||||
{item.product_name}
|
{item.product.name}
|
||||||
</h3>
|
</h3>
|
||||||
<div className="flex items-center gap-2 mb-3 max-lg:flex-col max-lg:items-start max-lg:gap-1">
|
<div className="flex items-center gap-2 mb-3 max-lg:flex-col max-lg:items-start max-lg:gap-1">
|
||||||
<span className="text-blue-600 font-bold text-xl">
|
<span className="text-blue-600 font-bold text-xl">
|
||||||
{formatPrice(item.product_price, true)}
|
{formatPrice(
|
||||||
|
Math.max(
|
||||||
|
...item.product.prices.map((e) => Number(e.price)),
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -176,7 +191,7 @@ const CartPage = () => {
|
|||||||
<button
|
<button
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
handleQuantityChange(
|
handleQuantityChange(
|
||||||
item.id,
|
String(item.id),
|
||||||
Number(quantities[item.id]) - 1,
|
Number(quantities[item.id]) - 1,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -197,7 +212,7 @@ const CartPage = () => {
|
|||||||
// Debounce bilan update
|
// Debounce bilan update
|
||||||
const valNum = Number(val);
|
const valNum = Number(val);
|
||||||
if (!isNaN(valNum))
|
if (!isNaN(valNum))
|
||||||
handleQuantityChange(item.id, valNum);
|
handleQuantityChange(String(item.id), valNum);
|
||||||
}}
|
}}
|
||||||
type="text"
|
type="text"
|
||||||
className="w-16 text-center"
|
className="w-16 text-center"
|
||||||
@@ -206,7 +221,7 @@ const CartPage = () => {
|
|||||||
<button
|
<button
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
handleQuantityChange(
|
handleQuantityChange(
|
||||||
item.id,
|
String(item.id),
|
||||||
Number(quantities[item.id]) + 1,
|
Number(quantities[item.id]) + 1,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,10 +95,19 @@ const OrderPage = () => {
|
|||||||
|
|
||||||
const { mutate, isPending } = useMutation({
|
const { mutate, isPending } = useMutation({
|
||||||
mutationFn: (body: OrderCreateBody) => cart_api.createOrder(body),
|
mutationFn: (body: OrderCreateBody) => cart_api.createOrder(body),
|
||||||
onSuccess: () => {
|
onSuccess: (res) => {
|
||||||
setOrderSuccess(true);
|
const message = JSON.parse(res.data.response);
|
||||||
setCart(cart_id);
|
if (message.successes.length > 0) {
|
||||||
queryClinet.refetchQueries({ queryKey: ['cart_items'] });
|
setOrderSuccess(true);
|
||||||
|
setCart(cart_id);
|
||||||
|
|
||||||
|
queryClinet.refetchQueries({ queryKey: ['cart_items'] });
|
||||||
|
} else {
|
||||||
|
toast.error('Xatolik yuz berdi', {
|
||||||
|
richColors: true,
|
||||||
|
position: 'top-center',
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onError: (error: AxiosError) => {
|
onError: (error: AxiosError) => {
|
||||||
(
|
(
|
||||||
@@ -123,7 +132,10 @@ const OrderPage = () => {
|
|||||||
const [selectedTimeSlot, setSelectedTimeSlot] = useState<string>('');
|
const [selectedTimeSlot, setSelectedTimeSlot] = useState<string>('');
|
||||||
|
|
||||||
const subtotal = cartItems?.reduce(
|
const subtotal = cartItems?.reduce(
|
||||||
(sum, item) => sum + item.product_price * item.quantity,
|
(sum, item) =>
|
||||||
|
sum +
|
||||||
|
Math.max(...item.product.prices.map((e) => Number(e.price))) *
|
||||||
|
item.quantity,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -247,18 +259,45 @@ const OrderPage = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const items = cartItems.map((item) => ({
|
const order_products: {
|
||||||
product_id: Number(item.product_id),
|
inventory_kind: sting;
|
||||||
quantity: item.quantity,
|
product_code: sting;
|
||||||
}));
|
on_balance: sting;
|
||||||
|
order_quant: number;
|
||||||
|
price_type_code: sting;
|
||||||
|
product_price: sting;
|
||||||
|
warehouse_code: sting;
|
||||||
|
}[] = [];
|
||||||
|
|
||||||
|
cartItems.forEach((e) => {
|
||||||
|
order_products.push({
|
||||||
|
inventory_kind: 'G',
|
||||||
|
product_code: e.product.code,
|
||||||
|
on_balance: 'Y',
|
||||||
|
order_quant: e.quantity,
|
||||||
|
price_type_code: e.product.prices[0].price_type.code,
|
||||||
|
product_price: e.product.prices[0].price,
|
||||||
|
warehouse_code: 'wh1',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
mutate({
|
mutate({
|
||||||
comment: value.comment,
|
order: [
|
||||||
items: items,
|
{
|
||||||
long: Number(value.long),
|
filial_code: 'dodge',
|
||||||
lat: Number(value.lat),
|
delivery_date: formatDate.format(deliveryDate, 'DD.MM.YYYY'),
|
||||||
date: formatDate.format(deliveryDate, 'YYYY-MM-DD'),
|
room_code: '100',
|
||||||
time: selectedTimeSlot,
|
deal_time: formatDate.format(deliveryDate, 'DD.MM.YYYY'),
|
||||||
|
robot_code: 'r2',
|
||||||
|
status: 'B#N',
|
||||||
|
sales_manager_code: '1',
|
||||||
|
person_code: '12345678',
|
||||||
|
currency_code: '860',
|
||||||
|
owner_person_code: '1234567',
|
||||||
|
note: value.comment,
|
||||||
|
order_products: order_products,
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ const Product = () => {
|
|||||||
{product &&
|
{product &&
|
||||||
!isLoading &&
|
!isLoading &&
|
||||||
product.results
|
product.results
|
||||||
.filter((product) => product.is_active)
|
.filter((product) => product.state === 'A')
|
||||||
.map((item) => (
|
.map((item) => (
|
||||||
<ProductCard key={item.id} product={item} error={isError} />
|
<ProductCard key={item.id} product={item} error={isError} />
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -10,17 +10,34 @@ export interface ProductList {
|
|||||||
|
|
||||||
export interface ProductListResult {
|
export interface ProductListResult {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
images: { id: number; image: string }[];
|
||||||
image: string;
|
|
||||||
price: number;
|
|
||||||
description: string;
|
|
||||||
liked: boolean;
|
liked: boolean;
|
||||||
unity: {
|
meansurement: null | string;
|
||||||
id: string;
|
inventory_id: null | string;
|
||||||
name: string;
|
product_id: string;
|
||||||
};
|
code: string;
|
||||||
min_quantity: number;
|
name: string;
|
||||||
is_active: boolean;
|
short_name: string;
|
||||||
|
weight_netto: null | string;
|
||||||
|
weight_brutto: null | string;
|
||||||
|
litr: null | string;
|
||||||
|
box_type_code: null | string;
|
||||||
|
box_quant: null | string;
|
||||||
|
groups: number[];
|
||||||
|
state: 'A' | 'P';
|
||||||
|
barcodes: string;
|
||||||
|
article_code: null | string;
|
||||||
|
marketing_group_code: null | string;
|
||||||
|
inventory_kinds: { id: number; name: string }[];
|
||||||
|
sector_codes: { id: number; code: string }[];
|
||||||
|
prices: {
|
||||||
|
id: number;
|
||||||
|
price: string;
|
||||||
|
price_type: {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProductDetail {
|
export interface ProductDetail {
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ export function CategoryCarousel({ category }: { category: CategoryResult }) {
|
|||||||
{product &&
|
{product &&
|
||||||
!isLoading &&
|
!isLoading &&
|
||||||
product.results
|
product.results
|
||||||
.filter((product) => product.is_active)
|
.filter((product) => product.state === 'A')
|
||||||
.map((product) => (
|
.map((product) => (
|
||||||
<CarouselItem
|
<CarouselItem
|
||||||
key={product.id}
|
key={product.id}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { useTranslations } from 'next-intl';
|
|||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { MouseEvent, useEffect, useRef, useState } from 'react';
|
import { MouseEvent, useEffect, useRef, useState } from 'react';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
|
import LogosProduct from '@/assets/product.png';
|
||||||
|
|
||||||
export function ProductCard({
|
export function ProductCard({
|
||||||
product,
|
product,
|
||||||
@@ -89,7 +90,7 @@ export function ProductCard({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const item = cartItems?.data?.cart_item?.find(
|
const item = cartItems?.data?.cart_item?.find(
|
||||||
(item) => Number(item.product_id) === product.id,
|
(item) => Number(item.product.id) === product.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
setQuantity(item ? item.quantity : 0);
|
setQuantity(item ? item.quantity : 0);
|
||||||
@@ -120,7 +121,7 @@ export function ProductCard({
|
|||||||
|
|
||||||
if (newQty > 1) {
|
if (newQty > 1) {
|
||||||
const cartItemId = cartItems?.data?.cart_item.find(
|
const cartItemId = cartItems?.data?.cart_item.find(
|
||||||
(item) => Number(item.product_id) === product.id,
|
(item) => Number(item.product.id) === product.id,
|
||||||
)?.id;
|
)?.id;
|
||||||
if (cartItemId) {
|
if (cartItemId) {
|
||||||
updateCartItem({
|
updateCartItem({
|
||||||
@@ -207,12 +208,14 @@ export function ProductCard({
|
|||||||
<Image
|
<Image
|
||||||
fill
|
fill
|
||||||
src={
|
src={
|
||||||
product?.image?.includes(BASE_URL)
|
product.images.length > 0
|
||||||
? product.image
|
? product?.images[0].image?.includes(BASE_URL)
|
||||||
: BASE_URL + product.image
|
? product.images[0].image
|
||||||
|
: BASE_URL + product.images[0].image
|
||||||
|
: LogosProduct
|
||||||
}
|
}
|
||||||
alt={product.name}
|
alt={product.name}
|
||||||
className="object-contain"
|
className="object-cover"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -230,9 +233,13 @@ export function ProductCard({
|
|||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<span className="text-lg sm:text-xl font-bold text-green-600">
|
{product.prices.length > 0 && (
|
||||||
{formatPrice(product.price, true)}
|
<span className="text-lg sm:text-xl font-bold text-green-600">
|
||||||
</span>
|
{formatPrice(
|
||||||
|
Math.max(...product.prices.map((p) => Number(p.price))),
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* {product. && (
|
{/* {product. && (
|
||||||
<div className="text-xs sm:text-sm text-slate-400 line-through">
|
<div className="text-xs sm:text-sm text-slate-400 line-through">
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ const Footer = () => {
|
|||||||
</h3>
|
</h3>
|
||||||
<ul className="space-y-2 text-sm">
|
<ul className="space-y-2 text-sm">
|
||||||
{category?.slice(0, 6)?.map((link) => (
|
{category?.slice(0, 6)?.map((link) => (
|
||||||
<Fragment key={link.name}>
|
<Fragment key={link.id}>
|
||||||
<li
|
<li
|
||||||
key={link.id}
|
key={link.id}
|
||||||
className="text-white hover:text-gray-300 transition-colors cursor-pointer"
|
className="text-white hover:text-gray-300 transition-colors cursor-pointer"
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import Image from 'next/image';
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import 'swiper/css';
|
import 'swiper/css';
|
||||||
import { banner_api } from '../lib/api';
|
import { banner_api } from '../lib/api';
|
||||||
|
import CategoryImage from '@/assets/water-bottle.png';
|
||||||
|
|
||||||
const Welcome = () => {
|
const Welcome = () => {
|
||||||
const [api, setApi] = useState<CarouselApi>();
|
const [api, setApi] = useState<CarouselApi>();
|
||||||
@@ -129,7 +130,9 @@ const Welcome = () => {
|
|||||||
<Link href={`/category/${banner.id}`}>
|
<Link href={`/category/${banner.id}`}>
|
||||||
<div className="flex flex-col gap-1 items-center justify-start bg-white p-3 rounded-lg shadow-md cursor-pointer space-x-3">
|
<div className="flex flex-col gap-1 items-center justify-start bg-white p-3 rounded-lg shadow-md cursor-pointer space-x-3">
|
||||||
<Image
|
<Image
|
||||||
src={BASE_URL + banner.image}
|
src={
|
||||||
|
banner.image ? BASE_URL + banner.image : CategoryImage
|
||||||
|
}
|
||||||
alt={banner.name}
|
alt={banner.name}
|
||||||
width={500}
|
width={500}
|
||||||
height={500}
|
height={500}
|
||||||
|
|||||||
Reference in New Issue
Block a user