add payment, trust badge, handle race condition, fix booking schema

This commit is contained in:
arifal
2026-04-20 23:57:31 +07:00
parent ba5f64ae0e
commit fcdca34460
33 changed files with 1781 additions and 138 deletions
@@ -0,0 +1,79 @@
import Image from "next/image";
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-linear-to-br from-white to-neutral-50 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 rounded-full bg-blue-100 px-2 py-0.5 text-[10px] font-bold uppercase tracking-wide text-blue-800 sm:text-xs">
Verified
</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 dibuat
</p>
<p className="text-lg font-bold text-neutral-800">
{trust.tripsCreated}
</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="text-lg font-bold text-amber-700">
{trust.avgRating != null ? `${trust.avgRating}` : "—"}
</p>
{trust.reviewCount > 0 && (
<p className="text-[10px] text-neutral-400">
dari {trust.reviewCount} ulasan trip
</p>
)}
</div>
</div>
</div>
</div>
);
}