forked from UKSOURCE/hailearning.edu.vn
Initial commit
This commit is contained in:
255
app/appointment/appointment.json
Normal file
255
app/appointment/appointment.json
Normal file
@@ -0,0 +1,255 @@
|
||||
{
|
||||
"title": "Đặt Lịch Tư Vấn",
|
||||
"subtitle": "Nhận tư vấn miễn phí từ chuyên gia visa của chúng tôi",
|
||||
"hero": {
|
||||
"title": "Tư Vấn Visa Miễn Phí",
|
||||
"description": "Đặt lịch hẹn với chuyên gia để được tư vấn chi tiết về visa và dịch vụ phù hợp nhất cho bạn.",
|
||||
"benefits": [
|
||||
"Tư vấn 1-1 với chuyên gia",
|
||||
"Phân tích hồ sơ miễn phí",
|
||||
"Báo giá chi tiết",
|
||||
"Lộ trình xin visa rõ ràng"
|
||||
]
|
||||
},
|
||||
"appointmentTypes": [
|
||||
{
|
||||
"id": "consultation",
|
||||
"name": "Tư Vấn Tổng Quát",
|
||||
"duration": "30 phút",
|
||||
"price": "Miễn phí",
|
||||
"description": "Tư vấn về loại visa phù hợp, yêu cầu cơ bản và quy trình xin visa",
|
||||
"icon": "💬",
|
||||
"popular": true
|
||||
},
|
||||
{
|
||||
"id": "document-review",
|
||||
"name": "Kiểm Tra Hồ Sơ",
|
||||
"duration": "45 phút",
|
||||
"price": "500,000 VNĐ",
|
||||
"description": "Kiểm tra chi tiết hồ sơ hiện tại và đưa ra lời khuyên cải thiện",
|
||||
"icon": "📋",
|
||||
"popular": false
|
||||
},
|
||||
{
|
||||
"id": "interview-prep",
|
||||
"name": "Luyện Phỏng Vấn",
|
||||
"duration": "60 phút",
|
||||
"price": "800,000 VNĐ",
|
||||
"description": "Luyện tập kỹ năng phỏng vấn visa với chuyên gia có kinh nghiệm",
|
||||
"icon": "🎯",
|
||||
"popular": false
|
||||
},
|
||||
{
|
||||
"id": "premium",
|
||||
"name": "Tư Vấn Cao Cấp",
|
||||
"duration": "90 phút",
|
||||
"price": "1,200,000 VNĐ",
|
||||
"description": "Tư vấn toàn diện bao gồm chiến lược, hồ sơ và luyện phỏng vấn",
|
||||
"icon": "⭐",
|
||||
"popular": false
|
||||
}
|
||||
],
|
||||
"timeSlots": [
|
||||
{
|
||||
"time": "08:00",
|
||||
"label": "8:00 AM",
|
||||
"available": true
|
||||
},
|
||||
{
|
||||
"time": "09:00",
|
||||
"label": "9:00 AM",
|
||||
"available": true
|
||||
},
|
||||
{
|
||||
"time": "10:00",
|
||||
"label": "10:00 AM",
|
||||
"available": false
|
||||
},
|
||||
{
|
||||
"time": "11:00",
|
||||
"label": "11:00 AM",
|
||||
"available": true
|
||||
},
|
||||
{
|
||||
"time": "13:00",
|
||||
"label": "1:00 PM",
|
||||
"available": true
|
||||
},
|
||||
{
|
||||
"time": "14:00",
|
||||
"label": "2:00 PM",
|
||||
"available": true
|
||||
},
|
||||
{
|
||||
"time": "15:00",
|
||||
"label": "3:00 PM",
|
||||
"available": false
|
||||
},
|
||||
{
|
||||
"time": "16:00",
|
||||
"label": "4:00 PM",
|
||||
"available": true
|
||||
},
|
||||
{
|
||||
"time": "17:00",
|
||||
"label": "5:00 PM",
|
||||
"available": true
|
||||
}
|
||||
],
|
||||
"consultants": [
|
||||
{
|
||||
"id": "nguyen-van-a",
|
||||
"name": "Nguyễn Văn A",
|
||||
"title": "Chuyên gia Visa Mỹ & Canada",
|
||||
"experience": "8 năm kinh nghiệm",
|
||||
"specialties": ["Visa Mỹ", "Visa Canada", "Visa du học"],
|
||||
"languages": ["Tiếng Việt", "English"],
|
||||
"rating": 4.9,
|
||||
"reviews": 156,
|
||||
"avatar": "/images/consultant-1.jpg",
|
||||
"description": "Chuyên gia hàng đầu về visa Bắc Mỹ với tỷ lệ thành công 98%"
|
||||
},
|
||||
{
|
||||
"id": "tran-thi-b",
|
||||
"name": "Trần Thị B",
|
||||
"title": "Chuyên gia Visa Châu Âu",
|
||||
"experience": "6 năm kinh nghiệm",
|
||||
"specialties": ["Visa Schengen", "Visa Anh", "Visa du lịch"],
|
||||
"languages": ["Tiếng Việt", "English", "Français"],
|
||||
"rating": 4.8,
|
||||
"reviews": 203,
|
||||
"avatar": "/images/consultant-2.jpg",
|
||||
"description": "Chuyên gia visa châu Âu với kinh nghiệm sống và làm việc tại Pháp"
|
||||
},
|
||||
{
|
||||
"id": "le-van-c",
|
||||
"name": "Lê Văn C",
|
||||
"title": "Chuyên gia Visa Châu Á",
|
||||
"experience": "5 năm kinh nghiệm",
|
||||
"specialties": ["Visa Nhật Bản", "Visa Hàn Quốc", "Visa Singapore"],
|
||||
"languages": ["Tiếng Việt", "日本語", "한국어"],
|
||||
"rating": 4.9,
|
||||
"reviews": 134,
|
||||
"avatar": "/images/consultant-3.jpg",
|
||||
"description": "Chuyên gia visa châu Á với khả năng giao tiếp đa ngôn ngữ"
|
||||
}
|
||||
],
|
||||
"formFields": [
|
||||
{
|
||||
"name": "fullName",
|
||||
"label": "Họ và tên",
|
||||
"type": "text",
|
||||
"required": true,
|
||||
"placeholder": "Nhập họ và tên đầy đủ"
|
||||
},
|
||||
{
|
||||
"name": "email",
|
||||
"label": "Email",
|
||||
"type": "email",
|
||||
"required": true,
|
||||
"placeholder": "example@email.com"
|
||||
},
|
||||
{
|
||||
"name": "phone",
|
||||
"label": "Số điện thoại",
|
||||
"type": "tel",
|
||||
"required": true,
|
||||
"placeholder": "+84 xxx xxx xxx"
|
||||
},
|
||||
{
|
||||
"name": "visaType",
|
||||
"label": "Loại visa quan tâm",
|
||||
"type": "select",
|
||||
"required": true,
|
||||
"options": [
|
||||
"Visa du lịch",
|
||||
"Visa công tác",
|
||||
"Visa du học",
|
||||
"Visa thăm thân",
|
||||
"Visa lao động",
|
||||
"Chưa xác định"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "country",
|
||||
"label": "Quốc gia đích",
|
||||
"type": "select",
|
||||
"required": true,
|
||||
"options": [
|
||||
"Mỹ",
|
||||
"Canada",
|
||||
"Schengen",
|
||||
"Anh",
|
||||
"Úc",
|
||||
"Nhật Bản",
|
||||
"Hàn Quốc",
|
||||
"Singapore",
|
||||
"Khác"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "travelDate",
|
||||
"label": "Dự kiến ngày đi",
|
||||
"type": "date",
|
||||
"required": false,
|
||||
"placeholder": ""
|
||||
},
|
||||
{
|
||||
"name": "previousVisa",
|
||||
"label": "Đã từng xin visa nước này?",
|
||||
"type": "select",
|
||||
"required": false,
|
||||
"options": [
|
||||
"Chưa bao giờ",
|
||||
"Đã xin và được duyệt",
|
||||
"Đã xin nhưng bị từ chối",
|
||||
"Đang trong quá trình xin"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "notes",
|
||||
"label": "Ghi chú thêm",
|
||||
"type": "textarea",
|
||||
"required": false,
|
||||
"placeholder": "Mô tả thêm về tình huống của bạn..."
|
||||
}
|
||||
],
|
||||
"faqs": [
|
||||
{
|
||||
"question": "Tư vấn có thực sự miễn phí không?",
|
||||
"answer": "Có, buổi tư vấn tổng quát 30 phút đầu tiên hoàn toàn miễn phí. Bạn chỉ cần đặt lịch và tham gia."
|
||||
},
|
||||
{
|
||||
"question": "Tôi có thể hủy hoặc đổi lịch hẹn không?",
|
||||
"answer": "Có, bạn có thể hủy hoặc đổi lịch hẹn trước 24 giờ mà không mất phí. Liên hệ với chúng tôi để thay đổi."
|
||||
},
|
||||
{
|
||||
"question": "Buổi tư vấn diễn ra như thế nào?",
|
||||
"answer": "Buổi tư vấn có thể diễn ra trực tiếp tại văn phòng hoặc online qua video call tùy theo lựa chọn của bạn."
|
||||
},
|
||||
{
|
||||
"question": "Tôi cần chuẩn bị gì cho buổi tư vấn?",
|
||||
"answer": "Bạn nên chuẩn bị các câu hỏi cụ thể và nếu có, mang theo hộ chiếu và các giấy tờ liên quan để được tư vấn chính xác hơn."
|
||||
}
|
||||
],
|
||||
"offices": [
|
||||
{
|
||||
"name": "TP. Hồ Chí Minh",
|
||||
"address": "123 Nguyễn Huệ, Quận 1",
|
||||
"phone": "+84 28 1234 5678",
|
||||
"hours": "8:00 - 18:00 (T2-T6), 8:00 - 12:00 (T7)"
|
||||
},
|
||||
{
|
||||
"name": "Hà Nội",
|
||||
"address": "456 Hoàn Kiếm, Hà Nội",
|
||||
"phone": "+84 24 1234 5678",
|
||||
"hours": "8:00 - 18:00 (T2-T6), 8:00 - 12:00 (T7)"
|
||||
},
|
||||
{
|
||||
"name": "Đà Nẵng",
|
||||
"address": "789 Hải Châu, Đà Nẵng",
|
||||
"phone": "+84 236 1234 567",
|
||||
"hours": "8:00 - 18:00 (T2-T6), 8:00 - 12:00 (T7)"
|
||||
}
|
||||
]
|
||||
}
|
||||
501
app/appointment/page.tsx
Normal file
501
app/appointment/page.tsx
Normal file
@@ -0,0 +1,501 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import appointmentData from "./appointment.json";
|
||||
|
||||
export default function AppointmentPage() {
|
||||
const [selectedType, setSelectedType] = useState("consultation");
|
||||
const [selectedConsultant, setSelectedConsultant] = useState("");
|
||||
const [selectedDate, setSelectedDate] = useState("");
|
||||
const [selectedTime, setSelectedTime] = useState("");
|
||||
const [selectedOffice, setSelectedOffice] = useState("online");
|
||||
const [openFaq, setOpenFaq] = useState<number | null>(null);
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
fullName: "",
|
||||
email: "",
|
||||
phone: "",
|
||||
visaType: "",
|
||||
country: "",
|
||||
travelDate: "",
|
||||
previousVisa: "",
|
||||
notes: "",
|
||||
});
|
||||
|
||||
const handleInputChange = (
|
||||
e: React.ChangeEvent<
|
||||
HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
|
||||
>,
|
||||
) => {
|
||||
const { name, value } = e.target;
|
||||
setFormData((prev) => ({
|
||||
...prev,
|
||||
[name]: value,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
console.log("Appointment booked:", {
|
||||
type: selectedType,
|
||||
consultant: selectedConsultant,
|
||||
date: selectedDate,
|
||||
time: selectedTime,
|
||||
office: selectedOffice,
|
||||
...formData,
|
||||
});
|
||||
alert(
|
||||
"Đặt lịch thành công! Chúng tôi sẽ liên hệ xác nhận trong thời gian sớm nhất.",
|
||||
);
|
||||
};
|
||||
|
||||
const toggleFaq = (index: number) => {
|
||||
setOpenFaq(openFaq === index ? null : index);
|
||||
};
|
||||
|
||||
const selectedAppointmentType = appointmentData.appointmentTypes.find(
|
||||
(type) => type.id === selectedType,
|
||||
);
|
||||
const selectedConsultantData = appointmentData.consultants.find(
|
||||
(c) => c.id === selectedConsultant,
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="max-w-6xl mx-auto">
|
||||
{/* Header */}
|
||||
<div className="text-center mb-12">
|
||||
<h1 className="text-4xl font-bold text-gray-900 mb-4">
|
||||
{appointmentData.title}
|
||||
</h1>
|
||||
<p className="text-xl text-gray-600 mb-8">
|
||||
{appointmentData.subtitle}
|
||||
</p>
|
||||
|
||||
{/* Benefits */}
|
||||
<div className="grid md:grid-cols-4 gap-6 max-w-4xl mx-auto">
|
||||
{appointmentData.hero.benefits.map((benefit, index) => (
|
||||
<div key={index} className="bg-blue-50 p-4 rounded-lg">
|
||||
<p className="text-blue-800 font-medium">{benefit}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid lg:grid-cols-3 gap-8">
|
||||
{/* Booking Form */}
|
||||
<div className="lg:col-span-2">
|
||||
<div className="bg-white rounded-lg shadow-lg p-6">
|
||||
<h2 className="text-2xl font-bold text-gray-900 mb-6">
|
||||
Đặt Lịch Hẹn
|
||||
</h2>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
{/* Appointment Type */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-3">
|
||||
Loại tư vấn <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<div className="grid md:grid-cols-2 gap-4">
|
||||
{appointmentData.appointmentTypes.map((type) => (
|
||||
<div
|
||||
key={type.id}
|
||||
className={`border rounded-lg p-4 cursor-pointer transition-colors ${
|
||||
selectedType === type.id
|
||||
? "border-blue-500 bg-blue-50"
|
||||
: "border-gray-200 hover:border-gray-300"
|
||||
}`}
|
||||
onClick={() => setSelectedType(type.id)}
|
||||
>
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<div className="flex items-center">
|
||||
<span className="text-2xl mr-3">{type.icon}</span>
|
||||
<div>
|
||||
<h3 className="font-semibold">{type.name}</h3>
|
||||
{type.popular && (
|
||||
<span className="bg-green-100 text-green-800 px-2 py-1 rounded text-xs">
|
||||
Phổ biến
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<div className="font-bold text-blue-600">
|
||||
{type.price}
|
||||
</div>
|
||||
<div className="text-sm text-gray-500">
|
||||
{type.duration}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-gray-600 text-sm">
|
||||
{type.description}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Consultant Selection */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-3">
|
||||
Chọn chuyên gia
|
||||
</label>
|
||||
<div className="space-y-3">
|
||||
<div
|
||||
className={`border rounded-lg p-4 cursor-pointer transition-colors ${
|
||||
selectedConsultant === ""
|
||||
? "border-blue-500 bg-blue-50"
|
||||
: "border-gray-200 hover:border-gray-300"
|
||||
}`}
|
||||
onClick={() => setSelectedConsultant("")}
|
||||
>
|
||||
<div className="font-medium">
|
||||
Để chúng tôi chọn chuyên gia phù hợp
|
||||
</div>
|
||||
<div className="text-sm text-gray-600">
|
||||
Dựa trên loại visa và quốc gia bạn quan tâm
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{appointmentData.consultants.map((consultant) => (
|
||||
<div
|
||||
key={consultant.id}
|
||||
className={`border rounded-lg p-4 cursor-pointer transition-colors ${
|
||||
selectedConsultant === consultant.id
|
||||
? "border-blue-500 bg-blue-50"
|
||||
: "border-gray-200 hover:border-gray-300"
|
||||
}`}
|
||||
onClick={() => setSelectedConsultant(consultant.id)}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<div className="w-12 h-12 bg-gray-200 rounded-full flex items-center justify-center mr-4">
|
||||
<span className="text-gray-600">👤</span>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="font-semibold">
|
||||
{consultant.name}
|
||||
</div>
|
||||
<div className="text-sm text-gray-600">
|
||||
{consultant.title}
|
||||
</div>
|
||||
<div className="flex items-center text-sm text-gray-500">
|
||||
<span className="mr-2">
|
||||
⭐ {consultant.rating}
|
||||
</span>
|
||||
<span className="mr-2">
|
||||
({consultant.reviews} đánh giá)
|
||||
</span>
|
||||
<span>{consultant.experience}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Date & Time */}
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Ngày hẹn <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="date"
|
||||
value={selectedDate}
|
||||
onChange={(e) => setSelectedDate(e.target.value)}
|
||||
min={new Date().toISOString().split("T")[0]}
|
||||
required
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Giờ hẹn <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<select
|
||||
value={selectedTime}
|
||||
onChange={(e) => setSelectedTime(e.target.value)}
|
||||
required
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||
>
|
||||
<option value="">Chọn giờ</option>
|
||||
{appointmentData.timeSlots.map((slot) => (
|
||||
<option
|
||||
key={slot.time}
|
||||
value={slot.time}
|
||||
disabled={!slot.available}
|
||||
>
|
||||
{slot.label} {!slot.available && "(Đã đặt)"}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Office Selection */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-3">
|
||||
Hình thức tư vấn <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<div className="space-y-3">
|
||||
<div
|
||||
className={`border rounded-lg p-4 cursor-pointer transition-colors ${
|
||||
selectedOffice === "online"
|
||||
? "border-blue-500 bg-blue-50"
|
||||
: "border-gray-200 hover:border-gray-300"
|
||||
}`}
|
||||
onClick={() => setSelectedOffice("online")}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<span className="text-2xl mr-3">💻</span>
|
||||
<div>
|
||||
<div className="font-medium">Tư vấn online</div>
|
||||
<div className="text-sm text-gray-600">
|
||||
Video call qua Zoom/Google Meet
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{appointmentData.offices.map((office, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`border rounded-lg p-4 cursor-pointer transition-colors ${
|
||||
selectedOffice === office.name
|
||||
? "border-blue-500 bg-blue-50"
|
||||
: "border-gray-200 hover:border-gray-300"
|
||||
}`}
|
||||
onClick={() => setSelectedOffice(office.name)}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<span className="text-2xl mr-3">🏢</span>
|
||||
<div>
|
||||
<div className="font-medium">
|
||||
Văn phòng {office.name}
|
||||
</div>
|
||||
<div className="text-sm text-gray-600">
|
||||
{office.address}
|
||||
</div>
|
||||
<div className="text-sm text-gray-500">
|
||||
{office.hours}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Personal Information */}
|
||||
<div className="border-t pt-6">
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-4">
|
||||
Thông Tin Cá Nhân
|
||||
</h3>
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
{appointmentData.formFields.map((field) => (
|
||||
<div
|
||||
key={field.name}
|
||||
className={
|
||||
field.type === "textarea" ? "md:col-span-2" : ""
|
||||
}
|
||||
>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
{field.label}
|
||||
{field.required && (
|
||||
<span className="text-red-500 ml-1">*</span>
|
||||
)}
|
||||
</label>
|
||||
|
||||
{field.type === "textarea" ? (
|
||||
<textarea
|
||||
name={field.name}
|
||||
value={
|
||||
formData[field.name as keyof typeof formData]
|
||||
}
|
||||
onChange={handleInputChange}
|
||||
placeholder={field.placeholder}
|
||||
required={field.required}
|
||||
rows={4}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||
/>
|
||||
) : field.type === "select" ? (
|
||||
<select
|
||||
name={field.name}
|
||||
value={
|
||||
formData[field.name as keyof typeof formData]
|
||||
}
|
||||
onChange={handleInputChange}
|
||||
required={field.required}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||
>
|
||||
<option value="">
|
||||
Chọn {field.label.toLowerCase()}
|
||||
</option>
|
||||
{field.options?.map((option, index) => (
|
||||
<option key={index} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
) : (
|
||||
<input
|
||||
type={field.type}
|
||||
name={field.name}
|
||||
value={
|
||||
formData[field.name as keyof typeof formData]
|
||||
}
|
||||
onChange={handleInputChange}
|
||||
placeholder={field.placeholder}
|
||||
required={field.required}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Submit Button */}
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full bg-blue-600 text-white py-3 px-6 rounded-lg hover:bg-blue-700 transition-colors font-medium text-lg"
|
||||
>
|
||||
Đặt Lịch Hẹn
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Sidebar */}
|
||||
<div className="space-y-6">
|
||||
{/* Booking Summary */}
|
||||
<div className="bg-white rounded-lg shadow-lg p-6">
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-4">
|
||||
Tóm Tắt Đặt Lịch
|
||||
</h3>
|
||||
|
||||
{selectedAppointmentType && (
|
||||
<div className="space-y-3">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-600">Loại tư vấn:</span>
|
||||
<span className="font-medium">
|
||||
{selectedAppointmentType.name}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-600">Thời gian:</span>
|
||||
<span className="font-medium">
|
||||
{selectedAppointmentType.duration}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-600">Phí:</span>
|
||||
<span className="font-medium text-blue-600">
|
||||
{selectedAppointmentType.price}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{selectedConsultantData && (
|
||||
<div className="border-t pt-3">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-600">Chuyên gia:</span>
|
||||
<span className="font-medium">
|
||||
{selectedConsultantData.name}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{selectedDate && selectedTime && (
|
||||
<div className="border-t pt-3">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-600">Ngày giờ:</span>
|
||||
<span className="font-medium">
|
||||
{selectedDate} lúc{" "}
|
||||
{
|
||||
appointmentData.timeSlots.find(
|
||||
(s) => s.time === selectedTime,
|
||||
)?.label
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{selectedOffice && (
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-600">Hình thức:</span>
|
||||
<span className="font-medium">
|
||||
{selectedOffice === "online"
|
||||
? "Online"
|
||||
: `Văn phòng ${selectedOffice}`}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Contact Info */}
|
||||
<div className="bg-blue-50 rounded-lg p-6">
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-4">
|
||||
Cần Hỗ Trợ?
|
||||
</h3>
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center">
|
||||
<span className="text-blue-600 mr-2">📞</span>
|
||||
<span>1900 1234</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<span className="text-blue-600 mr-2">✉️</span>
|
||||
<span>info@visaservice.com</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<span className="text-blue-600 mr-2">💬</span>
|
||||
<span>Chat trực tuyến 24/7</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* FAQs */}
|
||||
<div className="mt-16">
|
||||
<h2 className="text-2xl font-bold text-gray-900 mb-8 text-center">
|
||||
Câu Hỏi Thường Gặp
|
||||
</h2>
|
||||
<div className="max-w-3xl mx-auto space-y-4">
|
||||
{appointmentData.faqs.map((faq, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="bg-white rounded-lg shadow-md overflow-hidden"
|
||||
>
|
||||
<button
|
||||
className="w-full p-6 text-left hover:bg-gray-50 transition-colors"
|
||||
onClick={() => toggleFaq(index)}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="font-semibold text-gray-900">
|
||||
{faq.question}
|
||||
</h3>
|
||||
<span className="text-gray-400">
|
||||
{openFaq === index ? "−" : "+"}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
{openFaq === index && (
|
||||
<div className="px-6 pb-6">
|
||||
<p className="text-gray-700">{faq.answer}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user