import { useState, useEffect, useMemo } from "react"; import type { components } from "../../reflector-api"; type GetTranscript = components["schemas"]["GetTranscript"]; type GetTranscriptTopic = components["schemas"]["GetTranscriptTopic"]; import { BoxProps, Button, Dialog, CloseButton, Text, Box, Flex, Checkbox, Combobox, Spinner, createListCollection, } from "@chakra-ui/react"; import { TbBrandZulip } from "react-icons/tb"; import { useZulipStreams, useZulipTopics, useTranscriptPostToZulip, } from "../../lib/apiHooks"; import { featureEnabled } from "../../lib/features"; type ShareZulipProps = { transcript: GetTranscript; topics: GetTranscriptTopic[]; disabled: boolean; }; interface Stream { stream_id: number; name: string; } export default function ShareZulip(props: ShareZulipProps & BoxProps) { const [showModal, setShowModal] = useState(false); const [stream, setStream] = useState(undefined); const [selectedStreamId, setSelectedStreamId] = useState(null); const [topic, setTopic] = useState(undefined); const [includeTopics, setIncludeTopics] = useState(false); const { data: streams = [], isLoading: isLoadingStreams } = useZulipStreams(); const { data: topics = [] } = useZulipTopics(selectedStreamId); const postToZulipMutation = useTranscriptPostToZulip(); const streamItems = useMemo(() => { return streams.map((stream: Stream) => ({ label: stream.name, value: stream.name, })); }, [streams]); const topicItems = useMemo(() => { return topics.map(({ name }) => ({ label: name, value: name, })); }, [topics]); const streamCollection = useMemo( () => createListCollection({ items: streamItems, }), [streamItems], ); const topicCollection = useMemo( () => createListCollection({ items: topicItems, }), [topicItems], ); // Update selected stream ID when stream changes useEffect(() => { if (stream && streams) { const selectedStream = streams.find((s: Stream) => s.name === stream); setSelectedStreamId(selectedStream ? selectedStream.stream_id : null); } else { setSelectedStreamId(null); } }, [stream, streams]); const handleSendToZulip = async () => { if (!props.transcript) return; if (stream && topic) { try { await postToZulipMutation.mutateAsync({ params: { path: { transcript_id: props.transcript.id, }, query: { stream, topic, include_topics: includeTopics, }, }, }); setShowModal(false); } catch (error) { console.error("Error posting to Zulip:", error); } } }; if (!featureEnabled("sendToZulip")) return null; return ( <> setShowModal(e.open)} size="md" > Send to Zulip {isLoadingStreams ? ( ) : ( <> setIncludeTopics(!!e.checked)} > Include topics # { setTopic(undefined); setStream(e.value[0]); }} openOnClick={true} positioning={{ strategy: "fixed", hideWhenDetached: true, }} > No streams found {streamItems.map((item) => ( {item.label} ))} {stream && ( # setTopic(e.value[0])} openOnClick selectionBehavior="replace" skipAnimationOnMount={true} closeOnSelect={true} positioning={{ strategy: "fixed", hideWhenDetached: true, }} > No topics found {topicItems.map((item) => ( {item.label} ))} )} )} ); }