export default function ChatFlow()

in projects/deliberation_at_scale/packages/frontend/components/ChatFlow/index.tsx [34:157]


export default function ChatFlow(props: Props) {
    const { _ } = useLingui();
    const defaultBotMessageTemplate: MessageTemplate = useMemo(() => {
        return {
            name: _(msg`AI Moderator`),
            nameIcon: aiSolid,
            highlighted: true,
        } satisfies MessageTemplate;
    }, [_]);
    const { flow } = props;
    const {
        id: flowId,
        steps: unfilteredSteps,
        userMessageTemplate = defaultUserMessageTemplate,
        botMessageTemplate = defaultBotMessageTemplate,
    } = flow;
    const steps = unfilteredSteps.filter((step) => {
        return step.active ?? true;
    });
    const { push } = useLocalizedPush();
    const searchParams = useSearchParams();
    const params = useParams();
    const mediaContext = useLocalMedia({ redirect: false, request: false });
    const isVideoEnabled = mediaContext?.state?.isVideoEnabled ?? false;
    const isAudioEnabled = mediaContext?.state?.isAudioEnabled ?? false;
    const flowStateEntries = useAppSelector((state) => state.flow.flowStateLookup[flowId]);
    const positionIndex = useAppSelector((state) => state.flow.flowPositionLookup[flowId] ?? 0);
    const [lastHandledPositionIndex, setLastHandledPositionIndex] = useState<number>(-1);
    const roomState = useAppSelector((state) => state.room);
    const dispatch = useAppDispatch();
    const { flowMessages } = useChatFlowMessages({
        flowId,
    });
    const [inputDisabled, setInputDisabled] = useState(false);
    const currentStep = steps?.[positionIndex] as (FlowStep | undefined);
    const { hideInput = false, quickReplies = [], onTimeout } = currentStep ?? {};
    const hasQuickReplies = !isEmpty(quickReplies);
    const isTextInputDisabled = useMemo(() => {
        const { onInput, hideInput } = currentStep ?? {};
        return inputDisabled || !onInput || hideInput;
    }, [inputDisabled, currentStep]);
    const inputPlaceholder = useMemo(() => {
        if (isTextInputDisabled) {
            return hasQuickReplies ? _(msg`Select a button above...`) : _(msg`Waiting...`);
        }

        return undefined;
    }, [hasQuickReplies, isTextInputDisabled, _]);
    const { nickName } = useProfile();
    const replaceMessageVariables = useCallback((text: string) => {
        return replaceTextVariables(text, {
            nickName,
        });
    }, [nickName]);

    /** State helpers */
    const reset = useCallback(() => {
        dispatch(resetFlowPosition({
            flowId,
        }));
        dispatch(resetFlowMessages({
            flowId,
        }));
    }, [dispatch, flowId]);
    const setFlowStateEntry = useCallback((key: string, value: any) => {
        dispatch(setFlowStateEntryAction({
            flowId,
            key,
            value,
        }));
    }, [dispatch, flowId]);

    /* Navigation helpers */
    const goTo = useCallback((deltaPosition: number) => {
        dispatch(setFlowPosition({
            flowId,
            deltaPosition,
            maxPosition: (flow.steps.length - 1) ?? 0,
        }));
    }, [dispatch, flow.steps.length, flowId]);
    const goToNext = useCallback(() => {
        goTo(1);
    }, [goTo]);
    const goToPrevious = useCallback(() => {
        goTo(-1);
    }, [goTo]);
    const goToPage = useCallback((path: string) => {
        push(path);
    }, [push]);

    /* This will advance to a subflow of choice */
    const goToName = useCallback((name: string) => {
        const index = flow.steps.findIndex((step) => {
            return step?.name === name;
        });
        const deltaIndex = index - positionIndex;

        goTo(deltaIndex);
    }, [flow, goTo, positionIndex]);

    /* This will add a message to the log */
    const postMessages = useCallback((messages: Message[]) => {

        // Append the messages to the array
        dispatch(addFlowMessages({
            flowId,
            messages,
        }));
    }, [dispatch, flowId]);
    const getMessageFromTemplate = useCallback((messagesOptions: MessagesOptions, messageTemplate: MessageTemplate) => {
        const selectedMessages = draw(messagesOptions) ?? [];
        const messages = selectedMessages.map((message) => {
            const messageId = `${message}-${currentStep?.name ?? uuid()}}`;

            return {
                id: messageId,
                ...messageTemplate,
                content: message,
                date: dayjs().toISOString(),
            } satisfies Message;
        });

        return messages;
    }, [currentStep]);