diff --git a/frontend/.storybook/main.ts b/frontend/.storybook/main.ts
index bec4e50..c6535af 100644
--- a/frontend/.storybook/main.ts
+++ b/frontend/.storybook/main.ts
@@ -1,4 +1,4 @@
-import type { StorybookConfig } from '@storybook/nextjs';
+import type { StorybookConfig } from '@storybook/nextjs-vite';
const config: StorybookConfig = {
stories: [
@@ -11,7 +11,7 @@ const config: StorybookConfig = {
'@storybook/addon-a11y',
'@chromatic-com/storybook',
],
- framework: '@storybook/nextjs',
+ framework: '@storybook/nextjs-vite',
staticDirs: ['../public'],
};
diff --git a/frontend/app/sandbox/playground/page.tsx b/frontend/app/sandbox/playground/page.tsx
index fa21742..9fe1a18 100644
--- a/frontend/app/sandbox/playground/page.tsx
+++ b/frontend/app/sandbox/playground/page.tsx
@@ -26,8 +26,8 @@ export default function PlaygroundPage() {
const [loading, setLoading] = useState(false);
const client = new BridgeletClient({
- baseUrl: process.env.NEXT_PUBLIC_API_BASE_URL,
- apiKey: process.env.NEXT_PUBLIC_API_KEY,
+ baseUrl: process.env[`NEXT_PUBLIC_API_BASE_URL`],
+ apiKey: process.env[`NEXT_PUBLIC_API_KEY`],
} as BridgeletClientOptions);
const handleEndpointChange = (endpoint: Endpoint) => {
@@ -49,18 +49,18 @@ export default function PlaygroundPage() {
let result: unknown;
switch (selected) {
case "getClaimDetails":
- result = await client.getClaimDetails(params.token);
+ result = await client.getClaimDetails(params[`token`] ?? "");
break;
case "createPaymentIntent":
result = await client.createPaymentIntent({
- senderPublicKey: params.senderPublicKey,
- amountStroops: params.amountStroops,
- assetCode: params.assetCode,
+ senderPublicKey: params[`senderPublicKey`] ?? "",
+ amountStroops: params[`amountStroops`] ?? "",
+ assetCode: params[`assetCode`] ?? "",
});
break;
case "redeemClaim":
- result = await client.redeemClaim(params.token, {
- recipientPublicKey: params.recipientPublicKey,
+ result = await client.redeemClaim(params[`token`] ?? "", {
+ recipientPublicKey: params[`recipientPublicKey`] ?? "",
});
break;
}
diff --git a/frontend/components/claim-status-card.stories.tsx b/frontend/components/claim-status-card.stories.tsx
index d6fe077..a14d08f 100644
--- a/frontend/components/claim-status-card.stories.tsx
+++ b/frontend/components/claim-status-card.stories.tsx
@@ -10,18 +10,14 @@ export default meta;
type Story = StoryObj;
-export const Loading: Story = {
- args: { status: 'loading' },
-};
-
-export const Unclaimed: Story = {
- args: { status: 'unclaimed', amount: '100', asset: 'USDC', expiresAt: '2026-07-15T12:00:00Z' },
+export const Available: Story = {
+ args: { status: 'available', amountStroops: '1000000000', assetCode: 'USDC', expiresAt: '2026-07-15T12:00:00Z' },
};
export const Claimed: Story = {
- args: { status: 'claimed', amount: '100', asset: 'USDC' },
+ args: { status: 'claimed' },
};
export const Expired: Story = {
- args: { status: 'expired', amount: '50', asset: 'XLM', expiresAt: '2026-06-01T00:00:00Z' },
-};
+ args: { status: 'expired', expiresAt: '2026-06-01T00:00:00Z', supportEmail: 'support@bridgelet.com' },
+};
\ No newline at end of file
diff --git a/frontend/components/claim-status-card.tsx b/frontend/components/claim-status-card.tsx
index 58cdb00..048c59d 100644
--- a/frontend/components/claim-status-card.tsx
+++ b/frontend/components/claim-status-card.tsx
@@ -142,7 +142,7 @@ function AvailablePanel({
type="button"
onClick={handleClaim}
disabled={claiming}
- className="w-full rounded-lg bg-green-600 px-4 py-2.5 text-sm font-semibold text-white transition hover:bg-green-700 disabled:opacity-60 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600"
+ className="w-full rounded-lg bg-green-600 px-4 py-2.5 text-sm font-semibold text-white transition hover:bg-green-700 disabled:opacity-60 focus-visible:outline focus-visible:outline-offset-2 focus-visible:outline-green-600"
>
{claiming ? 'Claiming…' : 'Claim now'}
diff --git a/frontend/components/send-form/steps/confirm-step.tsx b/frontend/components/send-form/steps/confirm-step.tsx
index dd4c49a..8a8b8cb 100644
--- a/frontend/components/send-form/steps/confirm-step.tsx
+++ b/frontend/components/send-form/steps/confirm-step.tsx
@@ -3,6 +3,7 @@
import { useState } from 'react';
import type { SendFormState } from '../index';
import { useNfc } from '@/hooks/use-nfc';
+import { createPaymentIntent } from '@/lib/bridgelet';
type ConfirmStepProps = {
state: SendFormState;
@@ -20,10 +21,19 @@ export function ConfirmStep({ state, onBack }: ConfirmStepProps) {
setSubmitting(true);
setError(null);
try {
- // Placeholder: wire up to POST /api/accounts + POST /send in a real impl.
- await new Promise((res) => setTimeout(res, 800));
- // Set a mock claim URL for the NFC experiment since the backend isn't wired
- setClaimUrl('https://bridgelet.example.com/claim/mock-token-123');
+ const amountStroops = Math.round(Number.parseFloat(state.amountXlm) * 10_000_000).toString();
+ const response = await createPaymentIntent({
+ senderPublicKey: state.publicKey,
+ amountStroops,
+ assetCode: state.assetCode,
+ memo: state.memo || undefined,
+ });
+
+ const resolvedClaimUrl = response.claimUrl.startsWith('http')
+ ? response.claimUrl
+ : `${window.location.origin}${response.claimUrl}`;
+
+ setClaimUrl(resolvedClaimUrl);
setSubmitted(true);
} catch (err) {
setError(err instanceof Error ? err.message : 'Something went wrong.');
@@ -44,7 +54,22 @@ export function ConfirmStep({ state, onBack }: ConfirmStepProps) {
A claim link has been sent to {state.recipientEmail}. They have 24
hours to claim their funds.
-
+
+ {claimUrl && (
+
+ )}
+
{isSupported && claimUrl && (