order update
This commit is contained in:
BIN
public/shablon.jpg
Normal file
BIN
public/shablon.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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: "O‘zi 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">
|
||||
|
||||
@@ -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: "O‘zi 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>
|
||||
|
||||
@@ -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 noto‘g‘ri"),
|
||||
unity_id: z.string().uuid("Birlik noto‘g‘ri"),
|
||||
category_id: z.string(),
|
||||
unity_id: z.string(),
|
||||
price: z.number().positive("Narx noto‘g‘ri"),
|
||||
quantity_left: z.number().min(0),
|
||||
min_quantity: z.number().min(0),
|
||||
|
||||
51
src/features/plans/ui/ExcelUpload.tsx
Normal file
51
src/features/plans/ui/ExcelUpload.tsx
Normal 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}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user