main
tsx 203 lines 6.59 KB
Raw
1 import { openUrl } from "@tauri-apps/plugin-opener";
2 import { useLang } from "../context/LanguageContext";
3
4 interface CutCardProps {
5 name: string;
6 address: string;
7 rating: number;
8 reviewCount: number;
9 priceLevel: number;
10 distance: string;
11 openNow: boolean;
12 phone: string;
13 types: string[];
14 onViewDetails: () => void;
15 }
16
17 export default function CutCard({
18 name,
19 address,
20 rating,
21 reviewCount,
22 priceLevel,
23 distance,
24 openNow,
25 phone,
26 types,
27 onViewDetails,
28 }: CutCardProps) {
29 const { lang } = useLang();
30 const isRTL = lang === "fa";
31 const dir = isRTL ? "rtl" : "ltr";
32
33 const getPriceLevelSymbol = (level: number) => {
34 return "$".repeat(level);
35 };
36
37 return (
38 <div
39 dir={dir}
40 className="bg-white shadow-md rounded-lg overflow-hidden hover:shadow-lg transition-shadow duration-200 border border-gray-200 cursor-pointer"
41 onClick={onViewDetails}
42 >
43 {/* Image placeholder */}
44 <div className="w-full h-40 bg-gradient-to-br from-blue-400 to-blue-600 flex items-center justify-center">
45 <div className="text-white text-6xl">💈</div>
46 </div>
47
48 {/* Content */}
49 <div className="p-4">
50 {/* Name and Types */}
51 <div className="mb-2">
52 <h3 className="font-bold text-lg text-gray-900 mb-1">{name}</h3>
53 <p className="text-sm text-gray-500">{types.join("")}</p>
54 </div>
55
56 {/* Rating and Reviews */}
57 <div className="flex items-center gap-2 mb-2">
58 <div className="flex items-center gap-1">
59 <svg
60 className="w-4 h-4 fill-yellow-400 text-yellow-400"
61 viewBox="0 0 24 24"
62 xmlns="http://www.w3.org/2000/svg"
63 >
64 <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" />
65 </svg>
66 <span className="font-semibold text-sm text-gray-900">
67 {rating.toFixed(1)}
68 </span>
69 </div>
70 <span className="text-sm text-gray-500">({reviewCount})</span>
71 <span className="text-sm text-gray-400"></span>
72 <span className="text-sm text-gray-600">
73 {getPriceLevelSymbol(priceLevel)}
74 </span>
75 </div>
76
77 {/* Address */}
78 <div className="flex items-start gap-2 mb-2">
79 <svg
80 className="w-4 h-4 text-gray-500 mt-0.5 flex-shrink-0"
81 viewBox="0 0 24 24"
82 fill="none"
83 stroke="currentColor"
84 strokeWidth="2"
85 strokeLinecap="round"
86 strokeLinejoin="round"
87 xmlns="http://www.w3.org/2000/svg"
88 >
89 <path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" />
90 <circle cx="12" cy="10" r="3" />
91 </svg>
92 <p className="text-sm text-gray-600">{address}</p>
93 </div>
94
95 {/* Distance and Status */}
96 <div className="flex items-center gap-3 mb-3">
97 <span className="text-sm text-gray-600">{distance}</span>
98 <span className="text-sm text-gray-400"></span>
99 <div className="flex items-center gap-1">
100 <svg
101 className="w-4 h-4 text-gray-500"
102 viewBox="0 0 24 24"
103 fill="none"
104 stroke="currentColor"
105 strokeWidth="2"
106 strokeLinecap="round"
107 strokeLinejoin="round"
108 xmlns="http://www.w3.org/2000/svg"
109 >
110 <circle cx="12" cy="12" r="10" />
111 <polyline points="12 6 12 12 16 14" />
112 </svg>
113 <span
114 className={`text-sm font-medium ${
115 openNow ? "text-green-600" : "text-red-600"
116 }`}
117 >
118 {openNow
119 ? lang === "fa"
120 ? "باز است"
121 : lang === "sv"
122 ? "Öppet nu"
123 : "Open now"
124 : lang === "fa"
125 ? "بسته است"
126 : lang === "sv"
127 ? "Stängt"
128 : "Closed"}
129 </span>
130 </div>
131 </div>
132
133 {/* Phone */}
134 <div className="flex items-center gap-2 mb-4">
135 <svg
136 className="w-4 h-4 text-gray-500"
137 viewBox="0 0 24 24"
138 fill="none"
139 stroke="currentColor"
140 strokeWidth="2"
141 strokeLinecap="round"
142 strokeLinejoin="round"
143 xmlns="http://www.w3.org/2000/svg"
144 >
145 <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" />
146 </svg>
147 <a
148 href={`tel:${phone}`}
149 className="text-sm text-blue-600 hover:underline"
150 onClick={(e) => e.stopPropagation()}
151 >
152 {phone}
153 </a>
154 </div>
155
156 {/* Action Buttons */}
157 <div className="flex gap-2">
158 <button
159 className="flex-1 bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg font-medium transition-colors text-sm"
160 onClick={(e) => {
161 e.stopPropagation();
162 onViewDetails();
163 }}
164 >
165 {lang === "fa"
166 ? "مشاهده جزئیات"
167 : lang === "sv"
168 ? "Se detaljer"
169 : "View Details"}
170 </button>
171 <button
172 className="flex-1 bg-gray-100 hover:bg-gray-200 text-gray-700 px-4 py-2 rounded-lg font-medium transition-colors text-sm"
173 onClick={async (e) => {
174 e.stopPropagation();
175 try {
176 // Try to open in native maps app
177 const mapsUrl = `maps://?q=${encodeURIComponent(address)}`;
178 const googleMapsUrl = `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(
179 address,
180 )}`;
181
182 try {
183 await openUrl(mapsUrl);
184 } catch {
185 // If maps:// doesn't work, try Google Maps URL
186 await openUrl(googleMapsUrl);
187 }
188 } catch (error) {
189 console.error("Failed to open maps:", error);
190 }
191 }}
192 >
193 {lang === "fa"
194 ? "مسیریابی"
195 : lang === "sv"
196 ? "Vägbeskrivning"
197 : "Directions"}
198 </button>
199 </div>
200 </div>
201 </div>
202 );
203 }