Skip to content

📌feat: scaffold apps/web/src/app/hotel/[id]/escrow/create/ route placeholder #71

@sotoJ24

Description

@sotoJ24

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

  • Feature Request

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

  • apps/web/src/app/hotel/[id]/escrow/create/page.tsx exists
  • GET /hotel/1/escrow/create renders without errors
  • InvoiceHeader renders with "INV4257-09-012" and pink "Pending" badge
  • PAY button renders as disabled with title tooltip
  • 4 image placeholders render
  • ProcessStepper renders with Step 1 (green), Steps 2–4 (dimmed)
  • Notes textarea is interactive
  • @creit.tech/stellar-wallets-kit added to apps/web/package.json
  • All TODO comments reference correct source files
  • pnpm build --filter @safetrust/web passes

References


Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions