add payment, trust badge, handle race condition, fix booking schema
This commit is contained in:
@@ -4,15 +4,23 @@ import { useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
import { joinTripAction, cancelJoinAction } from "@/features/trip/actions";
|
||||
import { markParticipantPaidAction } from "@/features/booking/actions";
|
||||
|
||||
interface JoinTripButtonProps {
|
||||
tripId: string;
|
||||
isLoggedIn: boolean;
|
||||
isOrganizer: boolean;
|
||||
isJoined: boolean;
|
||||
/** Status partisipasi user saat isJoined (bukan organizer) */
|
||||
participationStatus?: "PENDING" | "CONFIRMED" | null;
|
||||
/** Status pembayaran manual (peserta) */
|
||||
participantPayment?: {
|
||||
markedPaidAt: string | Date | null;
|
||||
paymentConfirmedAt: string | Date | null;
|
||||
} | null;
|
||||
isFull: boolean;
|
||||
tripStatus: string;
|
||||
/** Tanggal berangkat sudah lewat (hari kalender UTC) */
|
||||
/** Tanggal berangkat trip sudah lewat */
|
||||
isDeparturePast?: boolean;
|
||||
}
|
||||
|
||||
@@ -21,6 +29,8 @@ export function JoinTripButton({
|
||||
isLoggedIn,
|
||||
isOrganizer,
|
||||
isJoined,
|
||||
participationStatus,
|
||||
participantPayment,
|
||||
isFull,
|
||||
tripStatus,
|
||||
isDeparturePast,
|
||||
@@ -98,6 +108,29 @@ export function JoinTripButton({
|
||||
}
|
||||
}
|
||||
|
||||
async function handleMarkPaid() {
|
||||
setLoading(true);
|
||||
setError("");
|
||||
const result = await markParticipantPaidAction(tripId);
|
||||
setLoading(false);
|
||||
if (result.error) {
|
||||
setError(result.error);
|
||||
} else {
|
||||
router.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
const pay = participantPayment;
|
||||
const showMarkPaid =
|
||||
isJoined &&
|
||||
pay &&
|
||||
!pay.paymentConfirmedAt &&
|
||||
!pay.markedPaidAt &&
|
||||
!isDeparturePast;
|
||||
const waitingPaymentConfirm =
|
||||
isJoined && pay && pay.markedPaidAt && !pay.paymentConfirmedAt;
|
||||
const paymentDone = isJoined && pay && pay.paymentConfirmedAt;
|
||||
|
||||
return (
|
||||
<div>
|
||||
{error && (
|
||||
@@ -105,6 +138,42 @@ export function JoinTripButton({
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
{isJoined && participationStatus === "PENDING" && (
|
||||
<div className="mb-3 rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm font-medium leading-relaxed text-amber-900">
|
||||
Permintaan ikut trip kamu{" "}
|
||||
<span className="font-semibold">menunggu persetujuan organizer</span>.
|
||||
Kamu bisa membatalkan kapan saja sebelum disetujui.
|
||||
</div>
|
||||
)}
|
||||
{isJoined && participationStatus === "CONFIRMED" && (
|
||||
<div className="mb-3 rounded-xl border border-secondary-200 bg-secondary-50 px-4 py-3 text-sm font-medium text-secondary-900">
|
||||
Kamu sudah{" "}
|
||||
<span className="font-semibold">terkonfirmasi</span> sebagai peserta
|
||||
trip ini.
|
||||
</div>
|
||||
)}
|
||||
{waitingPaymentConfirm && (
|
||||
<div className="mb-3 rounded-xl border border-primary-200 bg-primary-50 px-4 py-3 text-sm font-medium leading-relaxed text-primary-950">
|
||||
Kamu sudah menandai <span className="font-semibold">sudah bayar</span>.
|
||||
Tunggu organizer mengonfirmasi pembayaran.
|
||||
</div>
|
||||
)}
|
||||
{paymentDone && (
|
||||
<div className="mb-3 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm font-medium text-emerald-900">
|
||||
Pembayaran kamu sudah{" "}
|
||||
<span className="font-semibold">dikonfirmasi organizer</span>.
|
||||
</div>
|
||||
)}
|
||||
{showMarkPaid && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleMarkPaid}
|
||||
disabled={loading}
|
||||
className="mb-3 w-full rounded-xl border-2 border-primary-500 bg-white py-3 text-sm font-bold text-primary-700 transition-colors hover:bg-primary-50 disabled:opacity-50"
|
||||
>
|
||||
{loading ? "Memproses..." : "Saya sudah bayar"}
|
||||
</button>
|
||||
)}
|
||||
{isJoined ? (
|
||||
<button
|
||||
onClick={handleCancel}
|
||||
|
||||
Reference in New Issue
Block a user