// import react import clsx from 'clsx'; import { Virtuoso } from 'react-virtuoso'; import ResizeObserver from 'resize-observer-polyfill'; import React, { useRef, useEffect, useState, useMemo } from 'react'; // locals import Item from './Item'; import Confirm from '../../../Confirm'; import ApiSignal from '../../../../signals/Api'; import { useSignal } from '../../../../signal'; import { useFrames } from '../../../../data/useFrame'; import { current as TeamSignal } from '../../../../signals/Teams'; // debounce load next let timeout = null; const debounceLoadNext = (loadNext, time = 500) => { // if timeout, return if (timeout) return; // create timeout timeout = setTimeout(() => { // clear timeout clearTimeout(timeout); // load next timeout = null; // load next loadNext(); }, time); }; /** * component chirps * * @param props */ const ComponentWorkflowChatList = (props = {}) => { // refs const virtuoso = useRef(null); // signals const [sApi] = useSignal(ApiSignal); const [team] = useSignal(TeamSignal); // state const [remove, setRemove] = useState(null); const [scrolled, setScrolled] = useState(false); const [workflow, setWorkflow] = useState(typeof props.workflow === 'object' ? props.workflow : null); const [removing, setRemoving] = useState(false); // items const { total, frames, loadMore, handleItem, handleRemove, } = useFrames({ full : true, team : team?.id, search : props.search, subject : props.subject, workflow : workflow?.id, }, { disable : !workflow?.id || (!team?.id && !sApi.options?.query?.token), sort : (a, b) => { return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(); }, filter : (frame) => { // return subject/workflow return (frame.workflow === workflow?.id) && (frame.subject === props.subject); }, }); /** * on delete * * @param message */ const onDelete = async (message) => { // check removing if (removing) return; // loading delete setRemoving(true); // try/catch try { // delete message await sApi.Workflow.Frame.delete(workflow, message); // remove from items handleRemove(message); } catch (e) { console.log(e); } finally { setRemove(null); setRemoving(false); } }; // use effect useEffect(() => { // check typeof if (typeof props.workflow !== 'string') return; // load workflow sApi.Workflow.get(props.workflow).then((gotWorkflow) => { // set workflow setWorkflow(gotWorkflow); }); }, [props.workflow]); useEffect(() => { // add listener handleItem(props.output); }, [JSON.stringify(props.output)]); useEffect(() => { // scroll element const scrollElement = document.body; // scroll timeout let scrollTimeout; // on window scroll up, set scrolled to true const onScroll = (e) => { // clear timeout clearTimeout(scrollTimeout); // check scrolled above bottom of window within 500 if (window.scrollY < (scrollElement.scrollHeight - window.innerHeight - 500)) { // set true setScrolled(true); } else { // set false setScrolled(false); } }; // on resize const onResize = () => { // scroll to bottom if (scrolled) return; // timeout clearTimeout(scrollTimeout); // scroll to bottom virtuoso.current?.scrollToIndex(999999); }; // on scroll window.addEventListener('scroll', onScroll); // create resize observer on window body const resizeObserver = new ResizeObserver(onResize); // observe body resizeObserver.observe(scrollElement); // return return () => { // clear timeout clearTimeout(scrollTimeout); // remove listener window.removeEventListener('scroll', onScroll); // remove resize observer resizeObserver.unobserve(scrollElement); // disconnect resizeObserver.disconnect(); }; }, [workflow?.id, props.selected?.id, virtuoso.current]); // reversed frames const reversedFrames = useMemo(() => { return [...frames].reverse(); }, [frames]); // return jsx return ( <>