first commit
This commit is contained in:
437
src/features/cart/ui/OrderPage.tsx
Normal file
437
src/features/cart/ui/OrderPage.tsx
Normal file
@@ -0,0 +1,437 @@
|
||||
'use client';
|
||||
|
||||
import formatPhone from '@/shared/lib/formatPhone';
|
||||
import { Input } from '@/shared/ui/input';
|
||||
import { Label } from '@/shared/ui/label';
|
||||
import { Textarea } from '@/shared/ui/textarea';
|
||||
import {
|
||||
Building2,
|
||||
CheckCircle2,
|
||||
Clock,
|
||||
CreditCard,
|
||||
MapPin,
|
||||
Package,
|
||||
Truck,
|
||||
User,
|
||||
Wallet,
|
||||
} from 'lucide-react';
|
||||
import Image from 'next/image';
|
||||
import { useState } from 'react';
|
||||
|
||||
const OrderPage = () => {
|
||||
const [formData, setFormData] = useState({
|
||||
fullName: '',
|
||||
phone: '+998',
|
||||
email: '',
|
||||
city: '',
|
||||
address: '',
|
||||
postalCode: '',
|
||||
notes: '',
|
||||
});
|
||||
|
||||
const [paymentMethod, setPaymentMethod] = useState('cash');
|
||||
const [deliveryMethod, setDeliveryMethod] = useState('standard');
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [orderSuccess, setOrderSuccess] = useState(false);
|
||||
|
||||
// Cart items from previous page (in real app, this would come from context/store)
|
||||
const cartItems = [
|
||||
{
|
||||
id: 5,
|
||||
name: 'Coca-Cola 1.5L',
|
||||
price: 12000,
|
||||
quantity: 2,
|
||||
image: '/classic-coca-cola.png',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: 'Pepsi 2L',
|
||||
price: 11000,
|
||||
quantity: 1,
|
||||
image: '/pepsi-bottle.jpg',
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: 'Sprite 1.5L',
|
||||
price: 10000,
|
||||
quantity: 3,
|
||||
image: '/clear-soda-bottle.png',
|
||||
},
|
||||
];
|
||||
|
||||
const subtotal = cartItems.reduce(
|
||||
(sum, item) => sum + item.price * item.quantity,
|
||||
0,
|
||||
);
|
||||
const deliveryFee =
|
||||
deliveryMethod === 'express' ? 25000 : subtotal > 50000 ? 0 : 15000;
|
||||
const total = subtotal + deliveryFee;
|
||||
|
||||
const handleInputChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||
) => {
|
||||
setFormData({
|
||||
...formData,
|
||||
[e.target.name]: e.target.value,
|
||||
});
|
||||
};
|
||||
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
setIsSubmitting(true);
|
||||
|
||||
// Simulate API call
|
||||
setTimeout(() => {
|
||||
setIsSubmitting(false);
|
||||
setOrderSuccess(true);
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
if (orderSuccess) {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 flex items-center justify-center p-4">
|
||||
<div className="bg-white rounded-lg shadow-lg p-8 max-w-md w-full text-center">
|
||||
<div className="w-20 h-20 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
||||
<CheckCircle2 className="w-12 h-12 text-green-600" />
|
||||
</div>
|
||||
<h2 className="text-2xl font-bold text-gray-800 mb-2">
|
||||
Buyurtma qabul qilindi!
|
||||
</h2>
|
||||
<p className="text-gray-600 mb-4">
|
||||
Buyurtma raqami:{' '}
|
||||
<span className="font-bold">
|
||||
#ORD-{Math.floor(Math.random() * 10000)}
|
||||
</span>
|
||||
</p>
|
||||
<p className="text-gray-500 mb-6">
|
||||
Buyurtmangiz muvaffaqiyatli qabul qilindi. Tez orada sizga aloqaga
|
||||
chiqamiz.
|
||||
</p>
|
||||
<div className="bg-blue-50 p-4 rounded-lg mb-6">
|
||||
<p className="text-sm text-gray-700">
|
||||
Buyurtma holati haqida SMS orqali xabardor qilinasiz
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => (window.location.href = '/')}
|
||||
className="w-full bg-blue-600 text-white py-3 rounded-lg font-semibold hover:bg-blue-700 transition"
|
||||
>
|
||||
Bosh sahifaga qaytish
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 py-8">
|
||||
<div className="max-w-7xl mx-auto px-4">
|
||||
{/* Header */}
|
||||
<div className="mb-6">
|
||||
<h1 className="text-3xl font-bold text-gray-800 mb-2">
|
||||
Buyurtmani rasmiylashtirish
|
||||
</h1>
|
||||
<p className="text-gray-600">{"Ma'lumotlaringizni to'ldiring"}</p>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
{/* Left Column - Forms */}
|
||||
<div className="lg:col-span-2 space-y-6">
|
||||
{/* Contact Information */}
|
||||
<div className="bg-white rounded-lg shadow-md p-6">
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
<User className="w-5 h-5 text-blue-600" />
|
||||
<h2 className="text-xl font-semibold">
|
||||
{"Shaxsiy ma'lumotlar"}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<Label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
{"To'liq ism"}
|
||||
</Label>
|
||||
<Input
|
||||
type="text"
|
||||
name="fullName"
|
||||
value={formData.fullName}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
className="w-full border h-12 border-gray-300 rounded-lg px-4 py-3 focus:outline-none focus:border-blue-500"
|
||||
placeholder="Ismingiz va familiyangiz"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Telefon raqam
|
||||
</Label>
|
||||
<Input
|
||||
type="tel"
|
||||
name="phone"
|
||||
value={formatPhone(formData.phone)}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
className="w-full h-12 border border-gray-300 rounded-lg px-4 py-3 focus:outline-none focus:border-blue-500"
|
||||
placeholder="+998 90 123 45 67"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Delivery Address */}
|
||||
<div className="bg-white rounded-lg shadow-md p-6">
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
<MapPin className="w-5 h-5 text-blue-600" />
|
||||
<h2 className="text-xl font-semibold">
|
||||
Yetkazib berish manzili
|
||||
</h2>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<Label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Shahar
|
||||
</Label>
|
||||
<Input
|
||||
type="text"
|
||||
name="city"
|
||||
value={formData.city}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
className="w-full border h-12 border-gray-300 rounded-lg px-4 py-3 focus:outline-none focus:border-blue-500"
|
||||
placeholder="Toshkent"
|
||||
/>
|
||||
</div>
|
||||
<div className="md:col-span-2">
|
||||
<Label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
{"To'liq manzil"}
|
||||
</Label>
|
||||
<Textarea
|
||||
name="address"
|
||||
value={formData.address}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
rows={3}
|
||||
className="w-full border min-h-32 max-h-44 border-gray-300 rounded-lg px-4 py-3 focus:outline-none focus:border-blue-500"
|
||||
placeholder="Ko'cha, uy raqami, xonadon..."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-white rounded-lg shadow-md p-6">
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
<Truck className="w-5 h-5 text-blue-600" />
|
||||
<h2 className="text-xl font-semibold">
|
||||
Yetkazib berish usuli
|
||||
</h2>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<label className="flex items-center p-4 border-2 rounded-lg cursor-pointer transition hover:bg-gray-50">
|
||||
<Input
|
||||
type="radio"
|
||||
name="delivery"
|
||||
value="standard"
|
||||
checked={deliveryMethod === 'standard'}
|
||||
onChange={(e) => setDeliveryMethod(e.target.value)}
|
||||
className="w-4 h-4 text-blue-600"
|
||||
/>
|
||||
<div className="ml-4 flex-1">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<Clock className="w-5 h-5 text-gray-600" />
|
||||
<span className="font-semibold">
|
||||
Standart yetkazib berish
|
||||
</span>
|
||||
</div>
|
||||
<span className="font-bold text-blue-600">
|
||||
{subtotal > 50000 ? 'Bepul' : "15,000 so'm"}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm text-gray-500 mt-1">
|
||||
2-3 kun ichida
|
||||
</p>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label className="flex items-center p-4 border-2 rounded-lg cursor-pointer transition hover:bg-gray-50">
|
||||
<Input
|
||||
type="radio"
|
||||
name="delivery"
|
||||
value="express"
|
||||
checked={deliveryMethod === 'express'}
|
||||
onChange={(e) => setDeliveryMethod(e.target.value)}
|
||||
className="w-4 h-4 text-blue-600"
|
||||
/>
|
||||
<div className="ml-4 flex-1">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<Package className="w-5 h-5 text-gray-600" />
|
||||
<span className="font-semibold">
|
||||
Tez yetkazib berish
|
||||
</span>
|
||||
</div>
|
||||
<span className="font-bold text-blue-600">
|
||||
{"25,000 so'm"}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm text-gray-500 mt-1">1 kun ichida</p>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-white rounded-lg shadow-md p-6">
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
<CreditCard className="w-5 h-5 text-blue-600" />
|
||||
<h2 className="text-xl font-semibold">{"To'lov usuli"}</h2>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<Label className="flex items-center p-4 border-2 rounded-lg cursor-pointer transition hover:bg-gray-50">
|
||||
<Input
|
||||
type="radio"
|
||||
name="payment"
|
||||
value="cash"
|
||||
checked={paymentMethod === 'cash'}
|
||||
onChange={(e) => setPaymentMethod(e.target.value)}
|
||||
className="w-4 h-4 text-blue-600"
|
||||
/>
|
||||
<div className="ml-4 flex items-center gap-3">
|
||||
<Wallet className="w-6 h-6 text-green-600" />
|
||||
<div>
|
||||
<span className="font-semibold">Naqd pul</span>
|
||||
<p className="text-sm text-gray-500">
|
||||
{"Yetkazib berishda to'lash"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Label>
|
||||
|
||||
<Label className="flex items-center p-4 border-2 rounded-lg cursor-pointer transition hover:bg-gray-50">
|
||||
<Input
|
||||
type="radio"
|
||||
name="payment"
|
||||
value="card"
|
||||
checked={paymentMethod === 'card'}
|
||||
onChange={(e) => setPaymentMethod(e.target.value)}
|
||||
className="w-4 h-4 text-blue-600"
|
||||
/>
|
||||
<div className="ml-4 flex items-center gap-3">
|
||||
<CreditCard className="w-6 h-6 text-blue-600" />
|
||||
<div>
|
||||
<span className="font-semibold">Plastik karta</span>
|
||||
<p className="text-sm text-gray-500">
|
||||
{"Online to'lov"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Label>
|
||||
|
||||
<Label className="flex items-center p-4 border-2 rounded-lg cursor-pointer transition hover:bg-gray-50">
|
||||
<Input
|
||||
type="radio"
|
||||
name="payment"
|
||||
value="terminal"
|
||||
checked={paymentMethod === 'terminal'}
|
||||
onChange={(e) => setPaymentMethod(e.target.value)}
|
||||
className="w-4 h-4 text-blue-600"
|
||||
/>
|
||||
<div className="ml-4 flex items-center gap-3">
|
||||
<Building2 className="w-6 h-6 text-purple-600" />
|
||||
<div>
|
||||
<span className="font-semibold">Terminal orqali</span>
|
||||
<p className="text-sm text-gray-500">
|
||||
Yetkazib berishda terminal
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Column - Order Summary */}
|
||||
<div className="lg:col-span-1">
|
||||
<div className="bg-white rounded-lg shadow-md p-6 sticky top-4">
|
||||
<h3 className="text-xl font-bold mb-4">Mahsulotlar</h3>
|
||||
|
||||
{/* Cart Items */}
|
||||
<div className="space-y-3 mb-4 max-h-60 overflow-y-auto">
|
||||
{cartItems.map((item) => (
|
||||
<div key={item.id} className="flex gap-3 pb-3 border-b">
|
||||
<Image
|
||||
width={500}
|
||||
height={500}
|
||||
src={item.image}
|
||||
alt={item.name}
|
||||
className="w-16 h-16 object-contain bg-gray-100 rounded"
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<h4 className="font-medium text-sm">{item.name}</h4>
|
||||
<p className="text-sm text-gray-500">
|
||||
{item.quantity} x {item.price.toLocaleString()}{' '}
|
||||
{"so'm"}
|
||||
</p>
|
||||
<p className="font-semibold text-sm">
|
||||
{(item.price * item.quantity).toLocaleString()}{' '}
|
||||
{"so'm"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Pricing */}
|
||||
<div className="space-y-2 mb-4 pt-4 border-t">
|
||||
<div className="flex justify-between text-gray-600">
|
||||
<span>Mahsulotlar:</span>
|
||||
<span>
|
||||
{subtotal.toLocaleString()} {"so'm"}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between text-gray-600">
|
||||
<span>Yetkazib berish:</span>
|
||||
<span>
|
||||
{deliveryFee === 0 ? (
|
||||
<span className="text-green-600 font-semibold">
|
||||
Bepul
|
||||
</span>
|
||||
) : (
|
||||
`${deliveryFee.toLocaleString()} so'm`
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="border-t pt-4 mb-6">
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-lg font-semibold">Jami:</span>
|
||||
<span className="text-2xl font-bold text-blue-600">
|
||||
{total.toLocaleString()} {"so'm"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
className="w-full bg-blue-600 text-white py-4 rounded-lg font-semibold hover:bg-blue-700 transition disabled:bg-gray-400 disabled:cursor-not-allowed"
|
||||
>
|
||||
{isSubmitting ? (
|
||||
<span className="flex items-center justify-center gap-2">
|
||||
<div className="w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin" />
|
||||
Yuborilmoqda...
|
||||
</span>
|
||||
) : (
|
||||
'Buyurtmani tasdiqlash'
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default OrderPage;
|
||||
Reference in New Issue
Block a user