Files
openconcho/packages/web/src/components/workspaces/ScheduleDreamModal.tsx
Offending Commit 988ab36c32 chore(fire-tools): upgrade stamp to v1.13.2
- pnpm catalog: centralize version governance for biome, ts, vitest,
  zod, semantic-release, react, vite, and testing deps
- biome 1.9.4 → 2.4.13: migrate config (organizeImports → assist,
  files.ignore → files.includes, enable tailwindDirectives for @theme)
- zod 3.24.3 → 4.3.6: update error message API to { message: "..." }
  and .errors → .issues in all 4 Zod-using files
- vitest 3.2.3 → 4.1.5
- semantic-release 24.x → 25.0.3
- typescript 6.0.3 (ahead of 5.9.x standard; intentional)
- add commitlint 20.x with conventional config
- add husky 9.x with commit-msg and pre-commit hooks
- add .github/actions/setup composite action; update all 3 workflows
- fix: remove pnpm version: 9 from all workflows (reads packageManager)
- fix: node-version 20 → 24 in all 3 workflows
- add Makefile with dev/build/test/lint/typecheck/install targets
2026-04-27 11:20:47 -05:00

135 lines
3.4 KiB
TypeScript

import type { UseMutationResult } from "@tanstack/react-query";
import { useState } from "react";
import { z } from "zod";
import { FormModal } from "@/components/shared/FormModal";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Caption } from "@/components/ui/typography";
import { COLOR } from "@/lib/constants";
const schema = z.object({
observer: z.string().min(1, { message: "Observer peer ID is required" }),
observed: z.string().optional(),
session_id: z.string().optional(),
});
interface Props {
open: boolean;
workspaceId: string;
onClose: () => void;
mutation: UseMutationResult<
void,
Error,
{ observer: string; observed?: string | null; dream_type: "omni"; session_id?: string | null }
>;
}
export function ScheduleDreamModal({ open, onClose, mutation }: Props) {
const [observer, setObserver] = useState("");
const [observed, setObserved] = useState("");
const [sessionId, setSessionId] = useState("");
const [validationError, setValidationError] = useState("");
const reset = () => {
setObserver("");
setObserved("");
setSessionId("");
setValidationError("");
};
const handleSubmit = async (e: React.SyntheticEvent<HTMLFormElement>) => {
e.preventDefault();
const result = schema.safeParse({
observer,
observed: observed || undefined,
session_id: sessionId || undefined,
});
if (!result.success) {
setValidationError(result.error.issues[0].message);
return;
}
await mutation.mutateAsync({
observer: result.data.observer,
observed: result.data.observed ?? null,
dream_type: "omni",
session_id: result.data.session_id ?? null,
});
reset();
onClose();
};
return (
<FormModal
open={open}
title="Schedule Dream"
onClose={() => {
reset();
onClose();
}}
>
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<Label className="mb-1.5">
Observer peer ID <span style={{ color: COLOR.destructive }}>*</span>
</Label>
<Input
value={observer}
onChange={(e) => {
setObserver(e.target.value);
setValidationError("");
}}
placeholder="peer_id"
/>
</div>
<div>
<Label className="mb-1.5">
Observed peer ID <Caption as="span"> (optional, defaults to observer)</Caption>
</Label>
<Input
value={observed}
onChange={(e) => setObserved(e.target.value)}
placeholder="peer_id"
/>
</div>
<div>
<Label className="mb-1.5">
Session ID <Caption as="span"> (optional)</Caption>
</Label>
<Input
value={sessionId}
onChange={(e) => setSessionId(e.target.value)}
placeholder="session_id"
/>
</div>
{validationError && (
<Caption as="p" style={{ color: COLOR.destructive }}>
{validationError}
</Caption>
)}
{mutation.error && (
<Caption as="p" style={{ color: COLOR.destructive }}>
{mutation.error.message}
</Caption>
)}
<div className="flex justify-end gap-2 pt-2">
<Button
type="button"
variant="surface"
size="sm"
onClick={() => {
reset();
onClose();
}}
>
Cancel
</Button>
<Button type="submit" variant="accent" size="sm" disabled={mutation.isPending}>
{mutation.isPending ? "Scheduling..." : "Schedule"}
</Button>
</div>
</form>
</FormModal>
);
}