Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 136 additions & 10 deletions frontend/components/dashboard/dashboard-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ export function DashboardView({ session, onDisconnect }: DashboardViewProps) {
>(null);
const [streamFormMessage, setStreamFormMessage] =
React.useState<StreamFormMessageState | null>(null);
const [isFormSubmitting, setIsFormSubmitting] = React.useState(false);

// --- Snapshot State (merged) ---
const [snapshot, setSnapshot] = React.useState<DashboardSnapshot | null>(null);
Expand Down Expand Up @@ -556,7 +557,7 @@ export function DashboardView({ session, onDisconnect }: DashboardViewProps) {
}
};

const handleFormCreateStream = (event: React.FormEvent<HTMLFormElement>) => {
const handleFormCreateStream = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
const hasRequiredFields =
streamForm.recipient.trim() &&
Expand All @@ -573,15 +574,57 @@ export function DashboardView({ session, onDisconnect }: DashboardViewProps) {
return;
}

// Convert StreamFormValues to StreamFormData for handleCreateStream if possible
// or just show alert for now as per upstream mock logic
alert(
`Stream prepared for ${streamForm.recipient} with ${streamForm.totalAmount} ${streamForm.token}. You can still edit any field before final submission integration.`,
);
setStreamFormMessage({
text: "Stream draft is ready for submission integration.",
tone: "success",
});
const recipient = streamForm.recipient.trim();
if (!/^G[A-Z0-9]{55}$/.test(recipient)) {
setStreamFormMessage({
text: "Recipient must be a valid Stellar public key.",
tone: "error",
});
return;
}

const startDate = new Date(streamForm.startsAt);
const endDate = new Date(streamForm.endsAt);
if (Number.isNaN(startDate.getTime()) || Number.isNaN(endDate.getTime())) {
setStreamFormMessage({
text: "Start and end times must be valid dates.",
tone: "error",
});
return;
}

const durationSeconds = Math.floor((endDate.getTime() - startDate.getTime()) / 1000);
if (durationSeconds <= 0) {
setStreamFormMessage({
text: "End time must be after start time.",
tone: "error",
});
return;
}

setIsFormSubmitting(true);
try {
await handleCreateStream({
recipient,
token: streamForm.token.trim(),
amount: streamForm.totalAmount.trim(),
duration: String(durationSeconds),
durationUnit: "seconds",
});

handleResetStreamForm();
setStreamFormMessage({
text: "Stream submitted to wallet and confirmed on-chain.",
tone: "success",
});
} catch (err) {
setStreamFormMessage({
text: toSorobanErrorMessage(err),
tone: "error",
});
} finally {
setIsFormSubmitting(false);
}
};

// ── Tab content ─────────────────────────────────────────────────────────────
Expand Down Expand Up @@ -783,6 +826,89 @@ export function DashboardView({ session, onDisconnect }: DashboardViewProps) {
placeholder="USDC"
/>
</label>
<label>
Total Amount
<input
required
type="number"
min="0"
step="0.0000001"
value={streamForm.totalAmount}
onChange={(event) =>
updateStreamForm("totalAmount", event.target.value)
}
placeholder="100"
/>
</label>
</div>

<div className="stream-form__row">
<label>
Starts At
<input
required
type="datetime-local"
value={streamForm.startsAt}
onChange={(event) =>
updateStreamForm("startsAt", event.target.value)
}
/>
</label>
<label>
Ends At
<input
required
type="datetime-local"
value={streamForm.endsAt}
onChange={(event) =>
updateStreamForm("endsAt", event.target.value)
}
/>
</label>
</div>

<div className="stream-form__row">
<label>
Cadence (seconds)
<input
type="number"
min="1"
step="1"
value={streamForm.cadenceSeconds}
onChange={(event) =>
updateStreamForm("cadenceSeconds", event.target.value)
}
/>
</label>
</div>

<label>
Note
<textarea
value={streamForm.note}
onChange={(event) =>
updateStreamForm("note", event.target.value)
}
placeholder="Optional internal note for this stream configuration."
/>
</label>

<div className="stream-form__actions">
<button
type="submit"
className="wallet-button"
disabled={isFormSubmitting}
>
{isFormSubmitting ? "Submitting..." : "Create Stream"}
</button>
<button
type="button"
className="secondary-button"
disabled={isFormSubmitting}
onClick={handleResetStreamForm}
>
Reset
</button>
</div>
</form>
</div>
Expand Down
Loading