paginated unified messages

mail@pastecode.io avatar
unknown
typescript
a month ago
5.0 kB
2
Indexable
Never
import { useState, useEffect, useCallback, useMemo } from "react"
import { SubChannel } from "@/convex/tlc/types"
import { InboxMessage } from "@/convex/types"
import { useWorkspacePaginatedQuery } from "@/hooks/usingWorkspace"
import { api } from "@/convex/_generated/api"
import { InboxTLCMap } from "@/convex/tlc/clientHandler"

type ChannelStatus =
    | "LoadingFirstPage"
    | "CanLoadMore"
    | "LoadingMore"
    | "Exhausted"

type ChannelData = {
    results: InboxMessage[]
    isLoading: boolean
    status: ChannelStatus
    loadMore: (numItems: number) => void
}

function useChannelMessages(
    inboxTLCMap: InboxTLCMap | undefined,
    type: SubChannel
): ChannelData {
    const { results, isLoading, status, loadMore } =
        useWorkspacePaginatedQuery(
            api.tlc.clientHandler.paginateInboxMessagesByInboxTLCMap,
            { inboxTLCMap },
            { initialNumItems: 5 }
        )

    return { results, isLoading, status, loadMore }
}

export function useUnifiedMessages(inboxTLCMaps: InboxTLCMap[]) {
    const emailMessages = useChannelMessages(
        inboxTLCMaps.find(
            (tlcMap) => tlcMap.tlcMap.type === SubChannel.EMAIL
        ),
        SubChannel.EMAIL
    )
    const smsMessages = useChannelMessages(
        inboxTLCMaps.find(
            (tlcMap) => tlcMap.tlcMap.type === SubChannel.SMS
        ),
        SubChannel.SMS
    )
    const whatsappMessages = useChannelMessages(
        inboxTLCMaps.find(
            (tlcMap) => tlcMap.tlcMap.type === SubChannel.WHATSAPP
        ),
        SubChannel.WHATSAPP
    )
    const pmsMessages = useChannelMessages(
        inboxTLCMaps.find(
            (tlcMap) => tlcMap.tlcMap.type === SubChannel.PMS
        ),
        SubChannel.PMS
    )
    const airbnbMessages = useChannelMessages(
        inboxTLCMaps.find(
            (tlcMap) => tlcMap.tlcMap.type === SubChannel.AIRBNB
        ),
        SubChannel.AIRBNB
    )

    const channelData = useMemo(
        () => ({
            email: emailMessages,
            sms: smsMessages,
            whatsapp: whatsappMessages,
            pms: pmsMessages,
            airbnb: airbnbMessages,
        }),
        [
            emailMessages,
            smsMessages,
            whatsappMessages,
            pmsMessages,
            airbnbMessages,
        ]
    )

    const [unifiedMessages, setUnifiedMessages] = useState<
        InboxMessage[]
    >([])
    const [isLoading, setIsLoading] = useState(true)

    useEffect(() => {
        const allMessages = Object.values(channelData).flatMap(
            (channel) => channel.results
        )
        const sortedMessages = allMessages.sort(
            (a, b) => a.timestamp - b.timestamp
        )
        setUnifiedMessages(sortedMessages)
        setIsLoading(
            Object.values(channelData).some(
                (channel) => channel.isLoading
            )
        )

        console.log("paginated unifiedMessages", unifiedMessages)
    }, [channelData])

    const loadMore = useCallback(
        (numItems: number = 10) => {
            const oldestTimestamp =
                unifiedMessages[0]?.timestamp ?? Infinity
            const channelToLoad = Object.entries(channelData).reduce(
                (acc, [key, channel]) => {
                    const oldestChannelMessage = channel.results[0]
                    if (
                        oldestChannelMessage &&
                        oldestChannelMessage.timestamp <
                            acc.timestamp &&
                        channel.status === "CanLoadMore"
                    ) {
                        return {
                            key,
                            timestamp: oldestChannelMessage.timestamp,
                        }
                    }
                    return acc
                },
                { key: "", timestamp: Infinity } as {
                    key: string
                    timestamp: number
                }
            )

            if (channelToLoad.key) {
                channelData[
                    channelToLoad.key as keyof typeof channelData
                ].loadMore(numItems)
            }
        },
        [unifiedMessages, channelData]
    )

    const overallStatus: ChannelStatus = useMemo(() => {
        if (
            Object.values(channelData).some(
                (channel) => channel.status === "LoadingFirstPage"
            )
        ) {
            return "LoadingFirstPage"
        }
        if (
            Object.values(channelData).some(
                (channel) => channel.status === "LoadingMore"
            )
        ) {
            return "LoadingMore"
        }
        if (
            Object.values(channelData).some(
                (channel) => channel.status === "CanLoadMore"
            )
        ) {
            return "CanLoadMore"
        }
        return "Exhausted"
    }, [channelData])

    return {
        messages: unifiedMessages,
        isLoading,
        loadMore,
        status: overallStatus,
    }
}
Leave a Comment