main
tsx 292 lines 11.2 KB
Raw
1 import { useLang } from "../context/LanguageContext";
2
3 interface BarbershopDetailProps {
4 shop: {
5 id: number;
6 name: { [key: string]: string };
7 address: { [key: string]: string };
8 rating: number;
9 reviewCount: number;
10 priceLevel: number;
11 distance: { [key: string]: string };
12 openNow: boolean;
13 phone: string;
14 types: string[];
15 imageUrl?: string;
16 };
17 onClose: () => void;
18 onDirections: () => void;
19 }
20
21 export default function BarbershopDetail({
22 shop,
23 onClose,
24 onDirections,
25 }: BarbershopDetailProps) {
26 const { lang } = useLang();
27 const isRTL = lang === "fa";
28 const dir = isRTL ? "rtl" : "ltr";
29
30 const getPriceLevelSymbol = (level: number) => {
31 return "$".repeat(level);
32 };
33
34 const getTranslation = (key: string) => {
35 const translations: { [key: string]: { [lang: string]: string } } = {
36 close: { fa: "بستن", en: "Close", sv: "Stäng" },
37 call: { fa: "تماس", en: "Call", sv: "Ring" },
38 directions: { fa: "مسیریابی", en: "Directions", sv: "Vägbeskrivning" },
39 openNow: { fa: "باز است", en: "Open now", sv: "Öppet nu" },
40 closed: { fa: "بسته است", en: "Closed", sv: "Stängt" },
41 reviews: { fa: "نظرات", en: "reviews", sv: "recensioner" },
42 priceLevel: { fa: "سطح قیمت", en: "Price Level", sv: "Prisnivå" },
43 distanceAway: { fa: "فاصله", en: "away", sv: "bort" },
44 about: { fa: "درباره", en: "About", sv: "Om" },
45 services: { fa: "خدمات", en: "Services", sv: "Tjänster" },
46 contact: { fa: "تماس", en: "Contact", sv: "Kontakt" },
47 phoneNumber: {
48 fa: "شماره تلفن",
49 en: "Phone Number",
50 sv: "Telefonnummer",
51 },
52 address: { fa: "آدرس", en: "Address", sv: "Adress" },
53 openingHours: { fa: "ساعات کاری", en: "Opening Hours", sv: "Öppettider" },
54 monday: { fa: "دوشنبه", en: "Monday", sv: "Måndag" },
55 tuesday: { fa: "سه‌شنبه", en: "Tuesday", sv: "Tisdag" },
56 wednesday: { fa: "چهارشنبه", en: "Wednesday", sv: "Onsdag" },
57 thursday: { fa: "پنج‌شنبه", en: "Thursday", sv: "Torsdag" },
58 friday: { fa: "جمعه", en: "Friday", sv: "Fredag" },
59 saturday: { fa: "شنبه", en: "Saturday", sv: "Lördag" },
60 sunday: { fa: "یکشنبه", en: "Sunday", sv: "Söndag" },
61 };
62 return translations[key]?.[lang] || key;
63 };
64
65 // Mock opening hours data
66 const openingHours = [
67 { day: getTranslation("monday"), hours: "09:00 - 18:00" },
68 { day: getTranslation("tuesday"), hours: "09:00 - 18:00" },
69 { day: getTranslation("wednesday"), hours: "09:00 - 18:00" },
70 { day: getTranslation("thursday"), hours: "09:00 - 19:00" },
71 { day: getTranslation("friday"), hours: "09:00 - 19:00" },
72 { day: getTranslation("saturday"), hours: "10:00 - 16:00" },
73 { day: getTranslation("sunday"), hours: getTranslation("closed") },
74 ];
75
76 return (
77 <div
78 className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4 animate-fadeIn"
79 onClick={onClose}
80 >
81 <div
82 dir={dir}
83 className="bg-white rounded-2xl max-w-2xl w-full max-h-[90vh] overflow-y-auto shadow-2xl animate-slideUp"
84 onClick={(e) => e.stopPropagation()}
85 style={{ scrollBehavior: "smooth" }}
86 >
87 {/* Header Image */}
88 <div className="relative w-full h-64 bg-gradient-to-br from-blue-400 to-blue-600 flex items-center justify-center">
89 <div className="text-white text-8xl">💈</div>
90 <button
91 onClick={onClose}
92 className="absolute top-4 right-4 bg-white bg-opacity-90 hover:bg-opacity-100 rounded-full p-2 transition-all shadow-lg"
93 aria-label={getTranslation("close")}
94 >
95 <svg
96 className="w-6 h-6 text-gray-800"
97 viewBox="0 0 24 24"
98 fill="none"
99 stroke="currentColor"
100 strokeWidth="2"
101 strokeLinecap="round"
102 strokeLinejoin="round"
103 >
104 <line x1="18" y1="6" x2="6" y2="18" />
105 <line x1="6" y1="6" x2="18" y2="18" />
106 </svg>
107 </button>
108 </div>
109
110 {/* Content */}
111 <div className="p-6">
112 {/* Title and Status */}
113 <div className="mb-4">
114 <h2 className="text-3xl font-bold text-gray-900 mb-2">
115 {shop.name[lang]}
116 </h2>
117 <div className="flex items-center gap-2 flex-wrap">
118 <span className="text-sm text-gray-500">
119 {shop.types.join("")}
120 </span>
121 <span className="text-sm text-gray-400"></span>
122 <span
123 className={`text-sm font-semibold ${
124 shop.openNow ? "text-green-600" : "text-red-600"
125 }`}
126 >
127 {shop.openNow
128 ? getTranslation("openNow")
129 : getTranslation("closed")}
130 </span>
131 </div>
132 </div>
133
134 {/* Rating and Info */}
135 <div className="flex items-center gap-4 mb-6 pb-6 border-b">
136 <div className="flex items-center gap-1">
137 <svg
138 className="w-5 h-5 fill-yellow-400 text-yellow-400"
139 viewBox="0 0 24 24"
140 >
141 <path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" />
142 </svg>
143 <span className="font-bold text-lg text-gray-900">
144 {shop.rating.toFixed(1)}
145 </span>
146 </div>
147 <span className="text-sm text-gray-600">
148 ({shop.reviewCount} {getTranslation("reviews")})
149 </span>
150 <span className="text-sm text-gray-400"></span>
151 <span className="text-sm font-semibold text-gray-700">
152 {getPriceLevelSymbol(shop.priceLevel)}
153 </span>
154 <span className="text-sm text-gray-400"></span>
155 <span className="text-sm text-gray-600">
156 {shop.distance[lang]} {getTranslation("distanceAway")}
157 </span>
158 </div>
159
160 {/* Action Buttons */}
161 <div className="grid grid-cols-2 gap-3 mb-6">
162 <button
163 onClick={onDirections}
164 className="flex items-center justify-center gap-2 bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-lg font-semibold transition-colors"
165 >
166 <svg
167 className="w-5 h-5"
168 viewBox="0 0 24 24"
169 fill="none"
170 stroke="currentColor"
171 strokeWidth="2"
172 strokeLinecap="round"
173 strokeLinejoin="round"
174 >
175 <polygon points="3 11 22 2 13 21 11 13 3 11" />
176 </svg>
177 {getTranslation("directions")}
178 </button>
179 <a
180 href={`tel:${shop.phone}`}
181 className="flex items-center justify-center gap-2 bg-gray-100 hover:bg-gray-200 text-gray-700 px-6 py-3 rounded-lg font-semibold transition-colors"
182 onClick={(e) => e.stopPropagation()}
183 >
184 <svg
185 className="w-5 h-5"
186 viewBox="0 0 24 24"
187 fill="none"
188 stroke="currentColor"
189 strokeWidth="2"
190 strokeLinecap="round"
191 strokeLinejoin="round"
192 >
193 <path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" />
194 </svg>
195 {getTranslation("call")}
196 </a>
197 </div>
198
199 {/* Contact Information */}
200 <div className="mb-6">
201 <h3 className="text-lg font-bold text-gray-900 mb-3">
202 {getTranslation("contact")}
203 </h3>
204
205 {/* Address */}
206 <div className="flex items-start gap-3 mb-3">
207 <svg
208 className="w-5 h-5 text-gray-500 mt-0.5 flex-shrink-0"
209 viewBox="0 0 24 24"
210 fill="none"
211 stroke="currentColor"
212 strokeWidth="2"
213 strokeLinecap="round"
214 strokeLinejoin="round"
215 >
216 <path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" />
217 <circle cx="12" cy="10" r="3" />
218 </svg>
219 <div>
220 <p className="text-sm font-semibold text-gray-700 mb-1">
221 {getTranslation("address")}
222 </p>
223 <p className="text-sm text-gray-600">{shop.address[lang]}</p>
224 </div>
225 </div>
226
227 {/* Phone */}
228 <div className="flex items-start gap-3">
229 <svg
230 className="w-5 h-5 text-gray-500 mt-0.5 flex-shrink-0"
231 viewBox="0 0 24 24"
232 fill="none"
233 stroke="currentColor"
234 strokeWidth="2"
235 strokeLinecap="round"
236 strokeLinejoin="round"
237 >
238 <path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" />
239 </svg>
240 <div>
241 <p className="text-sm font-semibold text-gray-700 mb-1">
242 {getTranslation("phoneNumber")}
243 </p>
244 <a
245 href={`tel:${shop.phone}`}
246 className="text-sm text-blue-600 hover:underline"
247 onClick={(e) => e.stopPropagation()}
248 >
249 {shop.phone}
250 </a>
251 </div>
252 </div>
253 </div>
254
255 {/* Opening Hours */}
256 <div className="mb-6">
257 <h3 className="text-lg font-bold text-gray-900 mb-3">
258 {getTranslation("openingHours")}
259 </h3>
260 <div className="space-y-2">
261 {openingHours.map((item, index) => (
262 <div key={index} className="flex justify-between text-sm">
263 <span className="text-gray-600">{item.day}</span>
264 <span className="font-medium text-gray-900">
265 {item.hours}
266 </span>
267 </div>
268 ))}
269 </div>
270 </div>
271
272 {/* Services */}
273 <div className="pb-2">
274 <h3 className="text-lg font-bold text-gray-900 mb-3">
275 {getTranslation("services")}
276 </h3>
277 <div className="flex flex-wrap gap-2">
278 {shop.types.map((type, index) => (
279 <span
280 key={index}
281 className="bg-blue-100 text-blue-800 px-3 py-1.5 rounded-full text-sm font-medium hover:bg-blue-200 transition-colors"
282 >
283 {type}
284 </span>
285 ))}
286 </div>
287 </div>
288 </div>
289 </div>
290 </div>
291 );
292 }