import { useState, useEffect, useMemo } from "react"; import { featureEnabled } from "../../domainContext"; import { GetTranscript, GetTranscriptTopic } from "../../api"; import { BoxProps, Button, Dialog, CloseButton, Text, Box, Flex, Checkbox, Combobox, Spinner, Portal, useFilter, useListCollection, } from "@chakra-ui/react"; import { TbBrandZulip } from "react-icons/tb"; import useApi from "../../lib/useApi"; type ShareZulipProps = { transcriptResponse: GetTranscript; topicsResponse: GetTranscriptTopic[]; disabled: boolean; }; interface Stream { stream_id: number; name: string; } interface Topic { name: string; } export default function ShareZulip(props: ShareZulipProps & BoxProps) { const [showModal, setShowModal] = useState(false); const [stream, setStream] = useState(undefined); const [topic, setTopic] = useState(undefined); const [includeTopics, setIncludeTopics] = useState(false); const [isLoading, setIsLoading] = useState(true); const [streams, setStreams] = useState([]); const [topics, setTopics] = useState([]); const api = useApi(); const { contains } = useFilter({ sensitivity: "base" }); const { collection: streamItemsCollection, filter: streamItemsFilter, set: streamItemsSet, } = useListCollection({ initialItems: [] as { label: string; value: string }[], filter: contains, }); const { collection: topicItemsCollection, filter: topicItemsFilter, set: topicItemsSet, } = useListCollection({ initialItems: [] as { label: string; value: string }[], filter: contains, }); useEffect(() => { const fetchZulipStreams = async () => { if (!api) return; try { const response = await api.v1ZulipGetStreams(); setStreams(response); streamItemsSet( response.map((stream) => ({ label: stream.name, value: stream.name, })), ); setIsLoading(false); } catch (error) { console.error("Error fetching Zulip streams:", error); } }; fetchZulipStreams(); }, [!api]); useEffect(() => { const fetchZulipTopics = async () => { if (!api || !stream) return; try { const selectedStream = streams.find((s) => s.name === stream); if (selectedStream) { const response = await api.v1ZulipGetTopics({ streamId: selectedStream.stream_id, }); setTopics(response); topicItemsSet( response.map((topic) => ({ label: topic.name, value: topic.name, })), ); } else { topicItemsSet([]); } } catch (error) { console.error("Error fetching Zulip topics:", error); } }; fetchZulipTopics(); }, [stream, streams, api]); const handleSendToZulip = async () => { if (!api || !props.transcriptResponse) return; if (stream && topic) { try { await api.v1TranscriptPostToZulip({ transcriptId: props.transcriptResponse.id, stream, topic, includeTopics, }); setShowModal(false); } catch (error) { console.log(error); } } }; if (!featureEnabled("sendToZulip")) return null; return ( <> setShowModal(e.open)} size="md" > Send to Zulip {isLoading ? ( ) : ( <> setIncludeTopics(!!e.checked)} > Include topics # { setTopic(undefined); setStream(e.value[0]); }} onInputValueChange={(e) => streamItemsFilter(e.inputValue) } openOnClick={true} positioning={{ strategy: "fixed", hideWhenDetached: true, }} > No streams found {streamItemsCollection.items.map((item) => ( {item.label} ))} {stream && ( # setTopic(e.value[0])} onInputValueChange={(e) => topicItemsFilter(e.inputValue) } openOnClick selectionBehavior="replace" skipAnimationOnMount={true} closeOnSelect={true} positioning={{ strategy: "fixed", hideWhenDetached: true, }} > No topics found {topicItemsCollection.items.map((item) => ( {item.label} ))} )} )} ); }