Untitled
unknown
plain_text
10 months ago
14 kB
12
Indexable
import { useState } from "react";
import {
Calendar,
Clock,
CreditCard,
FileText,
} from "lucide-react";
import { Button } from "../ui/button";
import { Input } from "../ui/input";
import { Label } from "../ui/label";
import { Textarea } from "../ui/textarea";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
} from "../ui/dialog";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "../ui/select";
import {
Card,
CardContent,
CardHeader,
CardTitle,
} from "../ui/card";
import { Separator } from "../ui/separator";
import { Badge } from "../ui/badge";
import {
Avatar,
AvatarFallback,
AvatarImage,
} from "../ui/avatar";
import { MentorInfo } from "../mentors/MentorInfo";
import { Mentor } from "../../types";
interface BookingModalProps {
mentor: Mentor | null;
isOpen: boolean;
onClose: () => void;
onConfirmBooking: (bookingData: {
mentorId: string;
date: string;
time: string;
duration: number;
notes: string;
totalPrice: number;
}) => void;
}
export function BookingModal({
mentor,
isOpen,
onClose,
onConfirmBooking,
}: BookingModalProps) {
const [selectedDate, setSelectedDate] = useState("");
const [selectedTime, setSelectedTime] = useState("");
const [duration, setDuration] = useState(60);
const [notes, setNotes] = useState("");
const [isLoading, setIsLoading] = useState(false);
if (!mentor) return null;
const availableDates = [
"2024-01-20",
"2024-01-21",
"2024-01-22",
"2024-01-23",
"2024-01-24",
];
const availableTimes = [
"09:00",
"10:00",
"11:00",
"14:00",
"15:00",
"16:00",
"17:00",
];
const durationOptions = [
{ value: 30, label: "30 phút" },
{ value: 60, label: "1 giờ" },
{ value: 90, label: "1.5 giờ" },
{ value: 120, label: "2 giờ" },
];
const subtotal = (mentor.hourlyRate * duration) / 60;
const tax = subtotal * 0.1; // 10% tax
const platformFee = 2.99;
const totalPrice = subtotal + tax + platformFee;
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!selectedDate || !selectedTime) return;
setIsLoading(true);
try {
await onConfirmBooking({
mentorId: mentor.id,
date: selectedDate,
time: selectedTime,
duration,
notes,
totalPrice,
});
onClose();
} catch (error) {
console.error("Booking error:", error);
} finally {
setIsLoading(false);
}
};
return (
<Dialog open={isOpen} onOpenChange={onClose}>
<DialogContent
className="max-w-2xl max-h-[90vh] overflow-y-auto glass-blue-strong border-white/30"
style={{
background: "rgba(59, 130, 246, 0.15)",
backdropFilter: "blur(20px)",
WebkitBackdropFilter: "blur(20px)",
border: "1px solid rgba(255, 255, 255, 0.3)",
boxShadow:
"0 25px 50px -12px rgba(30, 58, 138, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.1)",
}}
>
<DialogHeader style={{ color: "white" }}>
<DialogTitle className="text-2xl !text-white">
Đặt lịch tư vấn
</DialogTitle>
<DialogDescription
className="!text-white"
style={{ color: "white" }}
>
Chọn thời gian và hoàn tất việc đặt lịch tư vấn với
mentor
</DialogDescription>
</DialogHeader>
<form
onSubmit={handleSubmit}
className="space-y-6 [&_*]:!text-white [&_h1]:!text-white [&_h2]:!text-white [&_h3]:!text-white [&_h4]:!text-white [&_p]:!text-white [&_span]:!text-white [&_div]:!text-white [&_label]:!text-white [&_input]:!text-white [&_textarea]:!text-white [&_button]:!text-white"
>
{/* Mentor Info */}
<Card className="glass border-white/30">
<CardContent className="p-4">
<div className="flex items-center space-x-4">
<Avatar className="h-16 w-16 glass border-white/20">
<AvatarImage
src={mentor.avatar}
alt={mentor.fullName}
/>
<AvatarFallback className="bg-gradient-secondary text-white">
{mentor.fullName
.split(" ")
.map((n) => n[0])
.join("")}
</AvatarFallback>
</Avatar>
<div className="flex-1">
<h3 className="font-semibold text-lg text-white">
{mentor.fullName}
</h3>
<div className="flex items-center space-x-2 text-sm text-white/70">
<span>{mentor.experience}</span>
<span>•</span>
<span>${mentor.hourlyRate}/giờ</span>
</div>
<div className="flex flex-wrap gap-1 mt-2">
{mentor.skills.slice(0, 3).map((skill) => (
<Badge
key={skill}
className="bg-blue-500/20 text-blue-200 border-blue-500/30 text-xs"
>
{skill}
</Badge>
))}
</div>
</div>
</div>
</CardContent>
</Card>
{/* Booking Details */}
<div className="grid md:grid-cols-2 gap-6">
{/* Date & Time Selection */}
<div className="space-y-4">
<div className="space-y-2">
<Label
htmlFor="date"
className="flex items-center space-x-2 text-white"
>
<Calendar className="h-4 w-4" />
<span>Chọn ngày</span>
</Label>
<Select
value={selectedDate}
onValueChange={setSelectedDate}
required
>
<SelectTrigger
className="glass border-white/30 text-white"
style={{ color: "white" }}
>
<SelectValue
placeholder="Chọn ngày"
style={{ color: "white" }}
/>
</SelectTrigger>
<SelectContent className="bg-white/95 backdrop-blur-md border-white/30">
{availableDates.map((date) => (
<SelectItem
key={date}
value={date}
className="focus:bg-blue-100"
>
{new Date(date).toLocaleDateString(
"vi-VN",
{
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
},
)}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label
htmlFor="time"
className="flex items-center space-x-2 text-white"
>
<Clock className="h-4 w-4" />
<span>Chọn giờ</span>
</Label>
<Select
value={selectedTime}
onValueChange={setSelectedTime}
required
>
<SelectTrigger
className="glass border-white/30 text-white"
style={{ color: "white" }}
>
<SelectValue
placeholder="Chọn giờ"
style={{ color: "white" }}
/>
</SelectTrigger>
<SelectContent className="bg-white/95 backdrop-blur-md border-white/30">
{availableTimes.map((time) => (
<SelectItem
key={time}
value={time}
className="focus:bg-blue-100"
>
{time}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label
htmlFor="duration"
className="text-white"
>
Thời lượng
</Label>
<Select
value={duration.toString()}
onValueChange={(value) =>
setDuration(parseInt(value))
}
>
<SelectTrigger
className="glass border-white/30 text-white"
style={{ color: "white" }}
>
<SelectValue style={{ color: "white" }} />
</SelectTrigger>
<SelectContent className="bg-white/95 backdrop-blur-md border-white/30">
{durationOptions.map((option) => (
<SelectItem
key={option.value}
value={option.value.toString()}
className="focus:bg-blue-100"
>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
{/* Price Breakdown */}
<Card className="glass border-white/30">
<CardHeader>
<CardTitle className="flex items-center space-x-2 text-lg text-white">
<CreditCard className="h-5 w-5" />
<span>Chi tiết thanh toán</span>
</CardTitle>
</CardHeader>
<CardContent className="space-y-3">
<div className="flex justify-between text-white">
<span>
{duration} phút × ${mentor.hourlyRate}/giờ
</span>
<span>${subtotal.toFixed(2)}</span>
</div>
<div className="flex justify-between text-sm text-white/70">
<span>Thuế (10%)</span>
<span>${tax.toFixed(2)}</span>
</div>
<div className="flex justify-between text-sm text-white/70">
<span>Phí dịch vụ</span>
<span>${platformFee.toFixed(2)}</span>
</div>
<Separator className="bg-white/20" />
<div className="flex justify-between font-semibold text-lg text-white">
<span>Tổng cộng</span>
<span>${totalPrice.toFixed(2)}</span>
</div>
</CardContent>
</Card>
</div>
{/* Notes */}
<div className="space-y-2">
<Label
htmlFor="notes"
className="flex items-center space-x-2 text-white"
>
<FileText className="h-4 w-4" />
<span>Ghi chú cho mentor (tùy chọn)</span>
</Label>
<Textarea
id="notes"
placeholder="Mô tả những gì bạn muốn thảo luận trong buổi tư vấn..."
value={notes}
onChange={(e) => setNotes(e.target.value)}
rows={3}
// GỠ: liquid-border nếu nó có pseudo-element tô nền
className="
!text-white placeholder-white/60 border-white/25
!bg-transparent hover:!bg-transparent focus:!bg-transparent
backdrop-blur-md
ring-0 focus-visible:ring-2 focus-visible:ring-white/30 focus-visible:ring-offset-0
"
// Tránh inline style xung đột – chỉ giữ phần cần thiết
style={{
WebkitBackdropFilter: "blur(12px)",
backgroundClip: "padding-box",
}}
/>
</div>
{/* Action Buttons */}
<div className="flex space-x-3">
<Button
type="button"
variant="outline"
onClick={onClose}
className="flex-1 border-white/30 text-white hover:bg-white/10"
>
Hủy
</Button>
<Button
type="submit"
className="flex-1 gradient-secondary hover:scale-105 transition-transform"
disabled={
!selectedDate || !selectedTime || isLoading
}
>
{isLoading
? "Đang xử lý..."
: `Xác nhận - ${totalPrice.toFixed(2)}`}
</Button>
</div>
</form>
</DialogContent>
</Dialog>
);
}Editor is loading...
Leave a Comment