order update

This commit is contained in:
Samandar Turgunboyev
2025-12-25 14:58:14 +05:00
parent 8ccee9b63d
commit 768ba9585d
8 changed files with 99 additions and 110 deletions

BIN
public/shablon.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -1,5 +1,5 @@
export interface User {
id: string;
id: number;
first_name: string;
last_name: string;
username: string;
@@ -15,28 +15,30 @@ export interface Product {
}
export interface Item {
id: string;
id: number;
quantity: number;
price: number;
product: Product;
product: {
id: number;
name_uz: string;
name_ru: string;
price: number;
code: string;
unity: string;
};
}
export interface Order {
id: string;
order_number: number;
id: number;
status: string;
total_price: number;
user: User;
payment_type: string;
delivery_type: string;
delivery_price: number;
contact_number: string;
comment: string;
name: string;
user: User;
items: Item[];
created_at: string;
long: number | null;
lat: number | null;
long: number;
lat: number;
}
export interface OrdersResponse {

View File

@@ -55,8 +55,7 @@ const OrderDelete = ({
<DialogHeader>
<DialogTitle>Buyurtmani o'chirish</DialogTitle>
<DialogDescription className="text-md font-semibold">
Siz rostan ham {orderDelete?.order_number} sonli buyurtmani
o'chirmoqchimisiz?
Siz rostan ham {orderDelete?.id} sonli buyurtmani o'chirmoqchimisiz?
</DialogDescription>
</DialogHeader>
<DialogFooter>

View File

@@ -1,25 +1,17 @@
import type { Order } from "@/features/order/lib/type";
import formatPhone from "@/shared/lib/formatPhone";
import formatDate from "@/shared/lib/formatDate";
import formatPrice from "@/shared/lib/formatPrice";
import { Map, Placemark, YMaps } from "@pbe/react-yandex-maps";
import {
Calendar,
CreditCard,
MapIcon,
MessageSquare,
Package,
Phone,
Truck,
User,
X,
} from "lucide-react";
import { type Dispatch, type SetStateAction } from "react";
const deliveryTypeLabel: Record<string, string> = {
YANDEX_GO: "Yandex Go",
DELIVERY_COURIES: "Kuryer orqali yetkazish",
PICKUP: "Ozi olib ketish",
};
interface Props {
detail: boolean;
setDetail: Dispatch<SetStateAction<boolean>>;
@@ -29,20 +21,6 @@ interface Props {
const OrderDetail = ({ detail, setDetail, order }: Props) => {
if (!detail || !order) return null;
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleString("uz-UZ", {
year: "numeric",
month: "long",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
});
};
const formatPrice = (price: number) => {
return new Intl.NumberFormat("uz-UZ").format(price) + " so'm";
};
const getStatusColor = (status: string) => {
const colors: Record<string, string> = {
pending: "bg-yellow-100 text-yellow-800",
@@ -65,9 +43,6 @@ const OrderDetail = ({ detail, setDetail, order }: Props) => {
<div className="fixed right-0 top-0 h-full w-full max-w-2xl bg-white shadow-xl z-50 overflow-y-auto">
<div className="sticky top-0 bg-white border-b px-6 py-4 flex items-center justify-between">
<div>
<h2 className="text-2xl font-bold">
Buyurtma #{order.order_number}
</h2>
<p className="text-sm text-gray-500">ID: {order.id}</p>
</div>
<button
@@ -88,7 +63,7 @@ const OrderDetail = ({ detail, setDetail, order }: Props) => {
</span>
<div className="flex items-center text-sm text-gray-500">
<Calendar className="w-4 h-4 mr-1" />
{formatDate(order.created_at)}
{formatDate.format(order.created_at, "DD-MM-YYYY")}
</div>
</div>
@@ -99,12 +74,6 @@ const OrderDetail = ({ detail, setDetail, order }: Props) => {
{formatPrice(order.total_price)}
</p>
</div>
<div>
<p className="text-gray-500">Yetkazish narxi</p>
<p className="text-xl font-semibold text-gray-700">
{formatPrice(order.delivery_price)}
</p>
</div>
</div>
</div>
@@ -116,36 +85,11 @@ const OrderDetail = ({ detail, setDetail, order }: Props) => {
<div className="space-y-2 text-sm">
<div className="flex justify-between">
<span className="text-gray-500">Ism:</span>
<span className="font-medium">{order.name}</span>
</div>
<div className="flex justify-between items-center">
<span className="text-gray-500">Telefon:</span>
<a
href={`tel:${order.contact_number}`}
className="font-medium text-blue-600 hover:underline flex items-center"
>
<Phone className="w-4 h-4 mr-1" />
{formatPhone(order.contact_number)}
</a>
<span className="font-medium">{order.user.username}</span>
</div>
</div>
</div>
<div className="border rounded-lg p-4">
<h3 className="font-semibold text-lg mb-3 flex items-center">
<Truck className="w-5 h-5 mr-2" />
Yetkazish ma'lumotlari
</h3>
<div className="space-y-2 text-sm">
<div className="flex justify-between">
<span className="text-gray-500">Turi:</span>
<span className="font-medium capitalize">
{deliveryTypeLabel[order.delivery_type] ??
order.delivery_type}
</span>
</div>
</div>
</div>
<div className="border rounded-lg p-4">
{order.lat && order.long && (
<div className="border rounded-lg p-4 space-y-2">
@@ -172,16 +116,6 @@ const OrderDetail = ({ detail, setDetail, order }: Props) => {
)}
</div>
<div className="border rounded-lg p-4">
<h3 className="font-semibold text-lg mb-3 flex items-center">
<CreditCard className="w-5 h-5 mr-2" />
To'lov turi
</h3>
<p className="text-sm font-medium capitalize">
{order.payment_type === "CASH" ? "Naxt" : "Karta orqali"}
</p>
</div>
{order.comment && (
<div className="border rounded-lg p-4">
<h3 className="font-semibold text-lg mb-3 flex items-center">

View File

@@ -2,7 +2,6 @@
import { order_api } from "@/features/order/lib/api";
import type { Order } from "@/features/order/lib/type";
import formatPhone from "@/shared/lib/formatPhone";
import formatPrice from "@/shared/lib/formatPrice";
import { Button } from "@/shared/ui/button";
import {
@@ -35,12 +34,6 @@ interface Props {
setOrderDetail: Dispatch<SetStateAction<Order | null>>;
}
const deliveryTypeLabel: Record<string, string> = {
YANDEX_GO: "Yandex Go",
DELIVERY_COURIES: "Kuryer orqali yetkazish",
PICKUP: "Ozi olib ketish",
};
type OrderStatus =
| "NEW"
// "PROCESSING" |
@@ -113,11 +106,7 @@ const OrderTable = ({
<TableHeader>
<TableRow>
<TableHead>#</TableHead>
<TableHead>Order </TableHead>
<TableHead>Foydalanuvchi</TableHead>
<TableHead>Kontakt</TableHead>
<TableHead>Toʻlov turi</TableHead>
<TableHead>Yetkazib berish</TableHead>
<TableHead>Umumiy narx</TableHead>
<TableHead>Izoh</TableHead>
<TableHead>Holat</TableHead>
@@ -129,18 +118,7 @@ const OrderTable = ({
{orders.map((order, index) => (
<TableRow key={order.id}>
<TableCell>{index + 1}</TableCell>
<TableCell>{order.order_number}</TableCell>
<TableCell>
{order.user.first_name} {order.user.last_name} (
{order.user.username})
</TableCell>
<TableCell>{formatPhone(order.contact_number)}</TableCell>
<TableCell>
{order.payment_type === "CASH" ? "Naxt" : "Karta orqali"}
</TableCell>
<TableCell>
{deliveryTypeLabel[order.delivery_type] ?? order.delivery_type}
</TableCell>
<TableCell>{order.user.username}</TableCell>
<TableCell>{formatPrice(order.total_price, true)}</TableCell>
<TableCell>{order.comment || "-"}</TableCell>
<TableCell>

View File

@@ -5,8 +5,8 @@ export const createPlanFormData = z.object({
name_ru: z.string().min(1, "Majburiy maydon"),
description_uz: z.string().min(1, "Majburiy maydon"),
description_ru: z.string().min(1, "Majburiy maydon"),
category_id: z.string().uuid("Kategoriya notogri"),
unity_id: z.string().uuid("Birlik notogri"),
category_id: z.string(),
unity_id: z.string(),
price: z.number().positive("Narx notogri"),
quantity_left: z.number().min(0),
min_quantity: z.number().min(0),

View File

@@ -0,0 +1,51 @@
"use client";
import { Button } from "@/shared/ui/button";
import { useRef } from "react";
export default function ExcelUpload() {
const fileInputRef = useRef<HTMLInputElement | null>(null);
const handleButtonClick = () => {
fileInputRef.current?.click();
};
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
// Excel format tekshiruvi
const allowedTypes = [
"application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
];
if (!allowedTypes.includes(file.type)) {
alert("Iltimos, faqat Excel (.xls, .xlsx) fayl yuklang");
return;
}
// 👉 shu yerda backendga yuborasiz
// uploadExcel(file)
};
return (
<>
<Button
onClick={handleButtonClick}
className="h-12 bg-blue-500 text-white hover:bg-blue-600"
variant="secondary"
>
Excel yuklash
</Button>
<input
ref={fileInputRef}
type="file"
accept=".xls,.xlsx"
className="hidden"
onChange={handleFileChange}
/>
</>
);
}

View File

@@ -1,5 +1,6 @@
import type { Product } from "@/features/plans/lib/data";
import AddedPlan from "@/features/plans/ui/AddedPlan";
import ExcelUpload from "@/features/plans/ui/ExcelUpload";
import { Button } from "@/shared/ui/button";
import {
Dialog,
@@ -9,7 +10,7 @@ import {
DialogTrigger,
} from "@/shared/ui/dialog";
import { Input } from "@/shared/ui/input";
import { Plus } from "lucide-react";
import { AlertCircle, Plus } from "lucide-react";
import type { Dispatch, SetStateAction } from "react";
interface Props {
@@ -38,6 +39,30 @@ const FilterPlans = ({
value={searchUser}
onChange={(e) => setSearchUser(e.target.value)}
/>
<Dialog>
<DialogTrigger asChild>
<Button
className="h-12 bg-blue-500 text-white hover:bg-blue-600 cursor-pointer"
variant={"secondary"}
>
Excel uchun shablon
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader className="text-xl font-medium">
Excel uchun kerakli shablon
</DialogHeader>
<img src="/shablon.jpg" className="h-full w-full" />
<div className="flex justify-center items-start gap-2">
<AlertCircle className="text-red-500 size-12" />
<p className="text-xl font-medium text-red-500">
Excel shu ko'rinishda bo'lishi kerak aks holda mahsulot qo'shishda
xatolik yuz berishi mumkin.
</p>
</div>
</DialogContent>
</Dialog>
<ExcelUpload />
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
<DialogTrigger asChild>
<Button