/
masterOK
/
FEF
Обзор
Документация
Войти
/
masterOK
/
FEF
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
MasterCard.tsx
125 строк
4 KB
masterOK
upload files
10 ноя 2025, 19:52
10 ноя 2025, 19:52
2cb4a49
Код
Авторство
О чём код?
import { Link } from "wouter"; import { Card, CardContent, CardFooter } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Star, MapPin, CheckCircle, Clock } from "lucide-react"; import type { Master } from "@shared/schema"; interface MasterCardProps { master: Master & { user: { fullName: string; avatarUrl?: string; city?: string; }; _count?: { reviews: number; }; }; } export function MasterCard({ master }: MasterCardProps) { const rating = parseFloat(master.rating || "0"); const reviewCount = master._count?.reviews || 0; return ( <Card className="overflow-hidden hover-elevate transition-all duration-300" data-testid={`card-master-${master.id}`}> <div className="relative h-48 bg-gradient-to-br from-primary/10 to-primary/5"> <div className="absolute top-4 right-4 flex gap-2"> {master.isVerified && ( <Badge className="bg-trust-verified text-white gap-1"> <CheckCircle className="h-3 w-3" /> Проверен </Badge> )} </div> <div className="absolute -bottom-8 left-6"> <Avatar className="h-16 w-16 border-4 border-background"> <AvatarImage src={master.user.avatarUrl} alt={master.user.fullName} /> <AvatarFallback className="text-lg font-bold bg-primary text-primary-foreground"> {master.user.fullName.charAt(0)} </AvatarFallback> </Avatar> </div> </div> <CardContent className="pt-12 pb-4"> <Link href={`/masters/${master.id}`} className="group" data-testid={`link-master-${master.id}`}> <h3 className="text-xl font-bold mb-1 group-hover:text-primary transition-colors"> {master.user.fullName} </h3> </Link> <p className="text-sm text-muted-foreground mb-3">{master.specialization}</p> <div className="flex items-center gap-4 text-sm text-muted-foreground mb-3"> {master.user.city && ( <div className="flex items-center gap-1"> <MapPin className="h-4 w-4" /> <span>{master.user.city}</span> </div> )} <div className="flex items-center gap-1"> <Clock className="h-4 w-4" /> <span>{master.experienceYears} {master.experienceYears === 1 ? 'год' : 'лет'}</span> </div> </div> <div className="flex items-center gap-2 mb-4"> <div className="flex items-center gap-1"> {[...Array(5)].map((_, i) => ( <Star key={i} className={`h-4 w-4 ${ i < Math.floor(rating) ? "fill-yellow-400 text-yellow-400" : "text-gray-300" }`} /> ))} </div> <span className="text-sm font-medium">{rating.toFixed(1)}</span> <span className="text-sm text-muted-foreground">({reviewCount})</span> </div> {master.description && ( <p className="text-sm text-muted-foreground line-clamp-2 mb-4"> {master.description} </p> )} <div className="flex items-center justify-between"> {master.hourlyRate && ( <div> <span className="text-2xl font-bold text-primary"> {parseFloat(master.hourlyRate).toLocaleString('ru-RU')} ₽ </span> <span className="text-sm text-muted-foreground">/час</span> </div> )} <Badge variant="secondary"> {master.completedOrders} заказов </Badge> </div> </CardContent> <CardFooter className="gap-2"> <Link href={`/masters/${master.id}`}> <span className="flex-1"> <Button variant="outline" className="w-full" data-testid={`button-view-profile-${master.id}`}> Профиль </Button> </span> </Link> <Link href={`/order/create?masterId=${master.id}`}> <span className="flex-1"> <Button className="w-full" data-testid={`button-order-${master.id}`}> Заказать </Button> </span> </Link> </CardFooter> </Card> ); }