veza/apps/web/src/components/views/live-view/useLiveView.ts

76 lines
2.4 KiB
TypeScript

import { useState, useCallback, useEffect } from 'react';
import toast from '@/utils/toast';
import { FEATURED_STREAM, CHAT_MESSAGES } from './mockData';
import { liveService } from '@/services/liveService';
import type { LiveStream } from '@/types';
import type { LiveViewChatMessage } from './types';
export interface UseLiveViewOptions {
stream?: LiveStream | null;
streamId?: string | null;
chatMessages?: LiveViewChatMessage[];
onSendMessage?: (text: string) => void;
isLoading?: boolean;
error?: Error | null;
}
export function useLiveView(options: UseLiveViewOptions = {}) {
const [stream, setStream] = useState<LiveStream | null>(
options.stream ?? FEATURED_STREAM,
);
const [fetchLoading, setFetchLoading] = useState(false);
const [fetchError, setFetchError] = useState<Error | null>(null);
const chatMessages = options.chatMessages ?? CHAT_MESSAGES;
const [msgInput, setMsgInput] = useState('');
// When stream override is provided, use it (e.g. Storybook)
useEffect(() => {
if (options.stream !== undefined && options.stream !== null) {
setStream(options.stream);
setFetchLoading(false);
setFetchError(null);
return;
}
if (options.stream === null) {
setStream(FEATURED_STREAM);
return;
}
// Fetch from API: by streamId or list live streams
setFetchLoading(true);
setFetchError(null);
const promise = options.streamId
? liveService.getStream(options.streamId)
: liveService.listStreams(true).then((streams) => streams[0] ?? undefined);
promise
.then((s) => setStream(s ?? FEATURED_STREAM))
.catch((err) => {
setFetchError(err instanceof Error ? err : new Error(String(err)));
setStream(FEATURED_STREAM);
})
.finally(() => setFetchLoading(false));
}, [options.stream, options.streamId]);
const handleSend = useCallback(() => {
if (!msgInput.trim()) return;
if (options.onSendMessage) {
options.onSendMessage(msgInput);
} else {
toast.success('Message sent to chat');
}
setMsgInput('');
}, [msgInput, options.onSendMessage]);
const displayStream = stream ?? FEATURED_STREAM;
const isLoading = options.isLoading ?? fetchLoading;
const error = options.error ?? fetchError;
return {
stream: displayStream,
chatMessages,
msgInput,
setMsgInput,
handleSend,
isLoading,
error,
};
}