110 lines
4.2 KiB
TypeScript
110 lines
4.2 KiB
TypeScript
import Image from "next/image";
|
|
import { BadgeCheck, Star } from "lucide-react";
|
|
import type { OrganizerTrust } from "@/server/services/trust.service";
|
|
|
|
interface OrganizerTrustPanelProps {
|
|
name: string;
|
|
image: string | null;
|
|
trust: OrganizerTrust;
|
|
}
|
|
|
|
export function OrganizerTrustPanel({
|
|
name,
|
|
image,
|
|
trust,
|
|
}: OrganizerTrustPanelProps) {
|
|
return (
|
|
<div className="rounded-xl border border-neutral-200 bg-white p-4 sm:p-5">
|
|
<h2 className="mb-3 text-xs font-bold text-neutral-700 sm:text-sm">
|
|
Organizer & kepercayaan
|
|
</h2>
|
|
<div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:gap-4">
|
|
<div className="flex items-center gap-3">
|
|
{image ? (
|
|
<Image
|
|
src={image}
|
|
alt=""
|
|
width={48}
|
|
height={48}
|
|
className="h-12 w-12 shrink-0 rounded-full object-cover ring-2 ring-white shadow"
|
|
/>
|
|
) : (
|
|
<div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-full bg-primary-600 text-lg font-bold text-white shadow">
|
|
{name.charAt(0).toUpperCase()}
|
|
</div>
|
|
)}
|
|
<div className="min-w-0">
|
|
<p className="truncate text-sm font-bold text-neutral-900 sm:text-base">
|
|
{name}
|
|
</p>
|
|
<div className="mt-1.5 flex flex-wrap gap-1.5">
|
|
{trust.isVerified && (
|
|
<span
|
|
className="inline-flex items-center gap-1 rounded-full bg-primary-100 px-2 py-0.5 text-[10px] font-bold uppercase tracking-wide text-primary-800 sm:text-xs"
|
|
title="Identitas organizer telah diverifikasi (KTP & rekening)"
|
|
>
|
|
<BadgeCheck size={12} strokeWidth={2} aria-hidden />
|
|
Verified Organizer
|
|
</span>
|
|
)}
|
|
{trust.isTripLeader && (
|
|
<span className="inline-flex items-center rounded-full bg-secondary-100 px-2 py-0.5 text-[10px] font-bold uppercase tracking-wide text-secondary-900 sm:text-xs">
|
|
Trip leader
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="flex flex-1 flex-wrap gap-3 border-t border-neutral-100 pt-3 sm:border-t-0 sm:border-l sm:pl-4 sm:pt-0">
|
|
<div className="min-w-[100px] rounded-lg bg-white/80 px-3 py-2 shadow-sm ring-1 ring-neutral-100">
|
|
<p className="text-[10px] font-medium text-neutral-500 sm:text-xs">
|
|
Trip selesai
|
|
</p>
|
|
<p className="text-lg font-bold text-primary-700">
|
|
{trust.tripsCompleted}
|
|
</p>
|
|
{trust.tripsCreated > trust.tripsCompleted && (
|
|
<p className="text-[10px] text-neutral-400">
|
|
+ {trust.tripsCreated - trust.tripsCompleted} berjalan
|
|
</p>
|
|
)}
|
|
</div>
|
|
<div className="min-w-[100px] rounded-lg bg-white/80 px-3 py-2 shadow-sm ring-1 ring-neutral-100">
|
|
<p className="text-[10px] font-medium text-neutral-500 sm:text-xs">
|
|
Peserta dilayani
|
|
</p>
|
|
<p className="text-lg font-bold text-secondary-700">
|
|
{trust.totalParticipantsServed}
|
|
</p>
|
|
</div>
|
|
<div className="min-w-[100px] rounded-lg bg-white/80 px-3 py-2 shadow-sm ring-1 ring-neutral-100">
|
|
<p className="text-[10px] font-medium text-neutral-500 sm:text-xs">
|
|
Rating organizer
|
|
</p>
|
|
<p className="flex items-center gap-1 text-lg font-bold text-amber-700">
|
|
{trust.avgRating != null ? (
|
|
<>
|
|
{trust.avgRating}
|
|
<Star
|
|
size={15}
|
|
strokeWidth={2}
|
|
fill="currentColor"
|
|
aria-hidden
|
|
/>
|
|
</>
|
|
) : (
|
|
"—"
|
|
)}
|
|
</p>
|
|
{trust.reviewCount > 0 && (
|
|
<p className="text-[10px] text-neutral-400">
|
|
dari {trust.reviewCount} ulasan trip
|
|
</p>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|