import * as React from 'react'; import { __ } from '@wordpress/i18n'; import { BookingApi } from './api'; import { money, type Price } from './pricing'; export interface CreditTransaction { id: number; booking_reference: string | null; created_at: string; transaction_type: string; amount: number; description: string | null; } export interface CreditAccount { id: number; user_id: number; currency: string; is_active: number; balance: number; user: { id: number; display_name: string; }; transactions?: CreditTransaction[]; } interface Settings { enable_credit: boolean; enable_pay_on_site: boolean; } interface OwnCredit { accounts: CreditAccount[]; currency: string; balance: number; account: CreditAccount | null; settings: Settings; } export function methodLabel(method: string | null): string { const labels: Record = { credit: __('Credit', 'abece-booking'), pay_on_site: __('Pay on site', 'abece-booking'), cash: __('Cash', 'abece-booking'), manual: __('Manual payment', 'abece-booking'), bank_transfer: __('Bank transfer', 'abece-booking'), qr_payment: __('QR payment', 'abece-booking') }; return method ? labels[method] ?? method : __('Not required', 'abece-booking'); } export function paymentLabel(status: string): string { const labels: Record = { refund_pending: __('Refund pending', 'abece-booking'), partially_refunded: __('Partially refunded', 'abece-booking'), partially_paid: __('Partially paid', 'abece-booking'), paid: __('Paid', 'abece-booking'), unpaid: __('Unpaid', 'abece-booking'), refunded: __('Refunded', 'abece-booking'), not_required: __('Not required', 'abece-booking') }; return labels[status] ?? status; } export declare function CreditHistory(props: { rows: CreditTransaction[]; currency: string; }): React.JSX.Element; export declare function OwnCreditView(props: { api: BookingApi; refresh?: number; }): React.JSX.Element; export interface PaymentChoiceState { method: string; confirmed: boolean; ready: boolean; } export function usePaymentChoice(api: BookingApi, price: Price | null, admin: boolean, user: number | null | 'self', canManageCredit = false, refresh = 0, resourceId: number | null = null) { const [method, setMethod] = React.useState('pay_on_site'), [confirmed, setConfirmed] = React.useState(false); const [credit, setCredit] = React.useState<{ key: string; currency: string; balance: number; active: boolean; inactive: boolean; methods: string[]; } | null>(null), [error, setError] = React.useState(''); const currency = price?.currency, amount = price?.final_amount ?? 0, key = JSON.stringify([currency, amount, admin, user, canManageCredit, refresh, resourceId]); React.useEffect(() => { let live = true; setCredit(null); setError(''); setConfirmed(false); if (!currency || !amount || !resourceId) return; const query: Record = { currency, resource_id: String(resourceId), ...(admin && typeof user === 'number' ? { customer_user_id: String(user) } : {}) }; Promise.all([(Promise.resolve({ accounts: [], currency, balance: 0, account: null, settings: { enable_credit: false, enable_pay_on_site: true } })) as Promise, (Promise.resolve(null)) as Promise<{ items: CreditAccount[]; }> | Promise, api.request<{ methods: string[]; }>(admin ? 'admin/payment-methods' : 'payment-methods', 'GET', undefined, query)]).then(([own, accounts, available]) => { if (!live) return; const account = admin ? accounts?.items.find(a => a.currency === currency) : own.account; const data = { key, currency, balance: account?.balance ?? 0, active: !!account?.is_active, inactive: !!account && !account.is_active, methods: available.methods }; setCredit(data); setMethod(current => data.methods.includes(current) && (current !== 'credit' || data.active && data.balance >= amount) ? current : data.methods.find(m => m !== 'credit') ?? (data.active && data.balance >= amount && data.methods.includes('credit') ? 'credit' : '')); }).catch(e => { if (live) setError(e.message); }); return () => { live = false; }; }, [api, key]); const currentCredit = credit?.key === key ? credit : null, canCredit = !!currentCredit?.methods.includes('credit'), sufficient = !!currentCredit?.active && (currentCredit?.balance ?? 0) >= amount; const ready = !amount || !!currentCredit && currentCredit.methods.includes(method) && (method !== 'credit' || canCredit && sufficient && (!admin || confirmed)); return { method, setMethod, confirmed, setConfirmed, credit: currentCredit, error, canCredit, sufficient, ready, admin, amount, currency }; } export function PaymentChoice({ state: s }: { state: ReturnType; }) { const group = React.useId(); if (!s.amount) return null; const descriptions: Record = { pay_on_site: __('Pay when visiting the venue.', 'abece-booking'), bank_transfer: __('Payment instructions will be shown after booking.', 'abece-booking'), qr_payment: __('A QR code will be created after booking.', 'abece-booking') }; return
{__('Payment method', 'abece-booking')}{s.error &&

{s.error}

}{!s.credit && !s.error &&

{__('Loading…', 'abece-booking')}

}
{s.credit?.methods.map(m => { const disabled = m === 'credit' && !s.sufficient, description = m === 'credit' ? `${__('Credit', 'abece-booking')}: ${money(s.credit?.balance ?? 0, s.currency!)}` : descriptions[m]; const explanation = disabled ? (s.credit?.inactive ? __('This credit account is inactive.', 'abece-booking') : __('Insufficient credit.', 'abece-booking')) : null; return ; })}
{s.admin && s.method === 'credit' && }{s.credit && !s.ready && s.method !== 'credit' &&

{__('Select an available payment method.', 'abece-booking')}

}
; }