Issue Summary
Create the escrow creation route /hotel/[id]/escrow/create in apps/web/
with a stub that shows the invoice Pending state, a disabled PAY button, the
Process stepper (step 1 active), and registers the XDRSigningFlow and
ProcessStepper component placeholders. This is step 3 of the waterfall.
Type of Issue
Depends on
Issue #69 (apartment detail) — BOOK button links here.
Files to create
apps/web/src/app/hotel/[id]/escrow/
└── create/
└── page.tsx
apps/web/src/components/escrow/
├── ProcessStepper.tsx ← stub (4-step visual stepper)
├── InvoiceHeader.tsx ← stub (invoice number + status badge)
└── XDRSigningFlowStub.tsx ← stub (sign with wallet UI placeholder)
apps/web/src/app/hotel/[id]/escrow/create/page.tsx
// TODO: replace PAY button with real XDRSigningFlow once merged in frontend-SafeTrust
// Sources:
// frontend-SafeTrust/src/components/escrow/XDRSigningFlow.tsx
// frontend-SafeTrust/src/components/escrow/ProcessStepper.tsx
// frontend-SafeTrust/src/components/escrow/InvoiceHeader.tsx
//
// Flow (when wired):
// PAY → signXDR() via Freighter → POST /helper/send-transaction
// → router.push(`/hotel/${id}/escrow/${newEscrowId}`)
import { ProcessStepper } from '@/components/escrow/ProcessStepper';
import { InvoiceHeader } from '@/components/escrow/InvoiceHeader';
export default function EscrowCreatePage({
params,
}: {
params: { id: string };
}) {
return (
<div className="max-w-5xl mx-auto p-6">
<InvoiceHeader invoiceNumber="INV4257-09-012" status="pending" />
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6 mt-6">
{/* Left — property details + PAY */}
<div className="lg:col-span-2 border rounded-lg p-6 bg-card space-y-4">
<div className="flex items-center justify-between">
<h2 className="text-xl font-bold">La sabana</h2>
{/* TODO: replace with real PAY → XDRSigningFlow */}
<button
disabled
className="bg-orange-400 text-white font-bold px-6 py-2 rounded opacity-60 cursor-not-allowed"
title="Wallet signing — coming soon"
>
PAY
</button>
</div>
{/* Image placeholder */}
<div className="grid grid-cols-4 gap-2">
{[1, 2, 3, 4].map((i) => (
<div key={i} className="h-20 bg-muted rounded" />
))}
</div>
<p className="text-sm text-muted-foreground">
📍 329 Calle santos, paseo colón, San José
</p>
<div className="flex gap-4 text-sm">
<span>🛏 2 bd</span><span>🐾 pet friendly</span><span>🚿 1 ba</span>
</div>
<div>
<h3 className="font-semibold mb-1">Property details</h3>
<p className="text-sm text-muted-foreground">
Beautiful apartment in the heart of San José.
</p>
</div>
<div>
<h3 className="font-semibold mb-1">Owner contact</h3>
<p className="text-sm">📞 +506 64852179</p>
<p className="text-sm">✉️ albertoCasas100@gmail.com</p>
</div>
</div>
{/* Right — Notes + Process stepper */}
<div className="space-y-4">
<div className="border rounded-lg p-4 bg-card">
<h3 className="font-semibold mb-2">Notes</h3>
<textarea
className="w-full text-sm border rounded p-2 h-24 resize-none"
placeholder="Add notes..."
/>
</div>
<ProcessStepper currentStep={1} />
</div>
</div>
</div>
);
}
apps/web/src/components/escrow/ProcessStepper.tsx
// TODO: replace with real ProcessStepper once merged in frontend-SafeTrust
// Source: frontend-SafeTrust/src/components/escrow/ProcessStepper.tsx
// Steps: 1-Escrow created · 2-Payment sent · 3-Deposit blocked · 4-Deposit released
const STEPS = [
'Escrow created',
'Payment sent',
'Deposit blocked',
'Deposit released',
];
export function ProcessStepper({ currentStep }: { currentStep: 1 | 2 | 3 | 4 }) {
return (
<div className="border rounded-lg p-4 bg-card">
<h3 className="font-semibold mb-3">Process</h3>
<div className="space-y-3">
{STEPS.map((label, index) => {
const stepNum = index + 1;
const isActive = stepNum <= currentStep;
return (
<div key={label} className="flex items-center gap-3">
<div
className={`w-8 h-8 rounded-full flex items-center justify-center text-xs font-bold flex-shrink-0 ${
isActive
? 'bg-green-500 text-white'
: 'bg-muted text-muted-foreground border'
}`}
>
{stepNum}
</div>
<span className={`text-sm ${isActive ? 'text-foreground font-medium' : 'text-muted-foreground'}`}>
{label}
</span>
</div>
);
})}
</div>
</div>
);
}
apps/web/src/components/escrow/InvoiceHeader.tsx
// TODO: replace with real InvoiceHeader once merged in frontend-SafeTrust
// Source: frontend-SafeTrust/src/components/escrow/InvoiceHeader.tsx
const STATUS_STYLES: Record<string, string> = {
pending: 'bg-pink-100 text-pink-800',
paid: 'bg-green-100 text-green-800',
blocked: 'bg-blue-100 text-blue-800',
released: 'bg-lime-100 text-lime-800',
};
export function InvoiceHeader({
invoiceNumber,
status,
paidAt,
}: {
invoiceNumber: string;
status: 'pending' | 'paid' | 'blocked' | 'released';
paidAt?: string;
}) {
const label =
status === 'pending' ? 'Pending' :
status === 'paid' ? 'Paid' :
status === 'blocked' ? 'Deposit blocked' :
'Deposit released';
return (
<div>
<div className="flex items-center gap-3">
<h1 className="text-2xl font-bold">{invoiceNumber}</h1>
<span className={`text-xs font-semibold px-3 py-1 rounded-full ${STATUS_STYLES[status]}`}>
{label}
</span>
</div>
{paidAt && (
<p className="text-xs text-muted-foreground mt-1">Paid at {paidAt}</p>
)}
</div>
);
}
Packages required in apps/web/package.json
"dependencies": {
"@creit.tech/stellar-wallets-kit": "latest"
}
Acceptance Criteria
References
Issue Summary
Create the escrow creation route
/hotel/[id]/escrow/createinapps/web/with a stub that shows the invoice Pending state, a disabled PAY button, the
Process stepper (step 1 active), and registers the
XDRSigningFlowandProcessSteppercomponent placeholders. This is step 3 of the waterfall.Type of Issue
Depends on
Issue #69 (apartment detail) — BOOK button links here.
Files to create
apps/web/src/app/hotel/[id]/escrow/create/page.tsxapps/web/src/components/escrow/ProcessStepper.tsxapps/web/src/components/escrow/InvoiceHeader.tsxPackages required in
apps/web/package.jsonAcceptance Criteria
apps/web/src/app/hotel/[id]/escrow/create/page.tsxexistsGET /hotel/1/escrow/createrenders without errorsInvoiceHeaderrenders with "INV4257-09-012" and pink "Pending" badgetitletooltipProcessStepperrenders with Step 1 (green), Steps 2–4 (dimmed)@creit.tech/stellar-wallets-kitadded toapps/web/package.jsonpnpm build --filter @safetrust/webpassesReferences