React 'Schedule a Meeting' Shared State Example

Shared State example of a 'Schedule Meeting' React form with the agent using hooks.

// ScheduleMeetingForm.tsx
import { useEffect, useRef, useState } from "react";

type MeetingState = {
  title: string;
  date: string;        // "2025-09-01"
  startTime: string;   // "14:00"
  endTime: string;     // "15:00"
  attendees: string;   // comma-separated emails
  location: string;    // "Zoom" | "Office TLV" | "Google Meet" | custom
  notes?: string;
};

interface Props {
  agentKey: string;
  initial?: Partial<MeetingState>;
}

export default function ScheduleMeetingForm({ agentKey, initial }: Props) {
  const [form, setForm] = useState<MeetingState>({
    title: initial?.title ?? "",
    date: initial?.date ?? "",
    startTime: initial?.startTime ?? "",
    endTime: initial?.endTime ?? "",
    attendees: initial?.attendees ?? "",
    location: initial?.location ?? "",
    notes: initial?.notes ?? "",
  });

  const agentRef = useRef<any | null>(null);
  const stateKey = "meeting_form";
	const stateDescription = `
    type MeetingState = {
      title: string;
      date: string;        // "2025-09-01"
      startTime: string;   // "14:00"
      endTime: string;     // "15:00"
      attendees: string;   // comma-separated emails
      location: string;    // "Zoom" | "Office TLV" | "Google Meet" | custom
      notes?: string;
    };

    interface Props {
      agentKey: string;
      initial?: Partial<MeetingState>;
    }`;

  useEffect(() => {
    agentRef.current = (window as any).eucera?.agent(agentKey);

    const handleStateChange = (key: string, nextState: unknown) => {
      if (key === stateKey) setForm(nextState as MeetingState);
    };

    agentRef.current?.shareState(stateKey, form, handleStateChange, stateDescription);

    return () => {
      agentRef.current?.clearState(stateKey);
      agentRef.current = null;
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [agentKey]);

  const updateField = <K extends keyof MeetingState>(k: K, v: MeetingState[K]) => {
    const next = { ...form, [k]: v };
    setForm(next);
    agentRef.current?.shareState(stateKey, next);
  };

  return (
    <form style={{ display: "grid", gap: 12, maxWidth: 520 }}>
      <label>
        Title
        <input
          value={form.title}
          onChange={(e) => updateField("title", e.target.value)}
          placeholder="Weekly Sync"
        />
      </label>

      <div style={{ display: "grid", gap: 12, gridTemplateColumns: "1fr 1fr" }}>
        <label>
          Date
          <input
            type="date"
            value={form.date}
            onChange={(e) => updateField("date", e.target.value)}
          />
        </label>
        <label>
          Start
          <input
            type="time"
            value={form.startTime}
            onChange={(e) => updateField("startTime", e.target.value)}
          />
        </label>
        <label>
          End
          <input
            type="time"
            value={form.endTime}
            onChange={(e) => updateField("endTime", e.target.value)}
          />
        </label>
        <label>
          Location
          <input
            value={form.location}
            onChange={(e) => updateField("location", e.target.value)}
            placeholder="Zoom / Office TLV / Meet"
          />
        </label>
      </div>

      <label>
        Attendees (comma-separated emails)
        <input
          value={form.attendees}
          onChange={(e) => updateField("attendees", e.target.value)}
          placeholder="[email protected], [email protected]"
        />
      </label>

      <label>
        Notes
        <textarea
          value={form.notes ?? ""}
          onChange={(e) => updateField("notes", e.target.value)}
          placeholder="Agenda, prep, etc."
        />
      </label>

      <small>
        {/* The agent tracks "meeting_form" and can act on it (e.g., draft invites). */}
        Snapshot: {JSON.stringify(form)}
      </small>
    </form>
  );
}