UNPKG

@replyke/core

Version:

Replyke: Build interactive apps with social features like comments, votes, feeds, user lists, notifications, and more.

101 lines 5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const react_1 = require("react"); const hooks_1 = require("../../../store/hooks"); const chatSlice_1 = require("../../../store/slices/chatSlice"); const useAxiosPrivate_1 = __importDefault(require("../../../config/useAxiosPrivate")); const useProject_1 = __importDefault(require("../../projects/useProject")); const handleError_1 = require("../../../utils/handleError"); function useConversations({ types, } = {}) { const dispatch = (0, hooks_1.useReplykeDispatch)(); const { projectId } = (0, useProject_1.default)(); const axios = (0, useAxiosPrivate_1.default)(); const conversations = (0, hooks_1.useReplykeSelector)(chatSlice_1.selectConversationList); const loading = (0, hooks_1.useReplykeSelector)(chatSlice_1.selectConversationListLoading); const hasMore = (0, hooks_1.useReplykeSelector)(chatSlice_1.selectConversationListHasMore); const typesKey = types ? [...types].sort().join(",") : ""; // Keep fresh refs to avoid stale closures in useCallback const conversationsRef = (0, react_1.useRef)(conversations); conversationsRef.current = conversations; // Local two-cursor ref — NOT stored in Redux to avoid schema changes const cursorRef = (0, react_1.useRef)({ cursor: null, cursorCreatedAt: null }); const fetchPage = (0, react_1.useCallback)(async (cursors, isRefresh) => { if (!projectId) return; dispatch((0, chatSlice_1.setConversationListLoading)(true)); try { const params = { limit: "20" }; if (types && types.length > 0) params.types = types.join(","); if (cursors?.cursor) params.cursor = cursors.cursor; if (cursors?.cursorCreatedAt) params.cursorCreatedAt = cursors.cursorCreatedAt; const response = await axios.get(`/${projectId}/chat/conversations`, { params, }); const { conversations: items, hasMore: more } = response.data; // Derive the next cursor from the last item in the response if (items.length > 0) { const last = items[items.length - 1]; cursorRef.current = { cursor: last.lastMessageAt ? new Date(last.lastMessageAt).toISOString() : null, cursorCreatedAt: new Date(last.createdAt).toISOString(), }; } else if (isRefresh) { cursorRef.current = { cursor: null, cursorCreatedAt: null }; } if (isRefresh) { dispatch((0, chatSlice_1.setConversationList)(items)); } else { // Append to existing list, deduplicating by id const current = conversationsRef.current; dispatch((0, chatSlice_1.setConversationList)(current.concat(items.filter((item) => !current.some((c) => c.id === item.id))))); } dispatch((0, chatSlice_1.setConversationListHasMore)(more)); } catch (err) { (0, handleError_1.handleError)(err, "Failed to load conversations"); } finally { dispatch((0, chatSlice_1.setConversationListLoading)(false)); } }, // eslint-disable-next-line react-hooks/exhaustive-deps [projectId, typesKey]); // Initial fetch on mount (or when types/projectId changes) (0, react_1.useEffect)(() => { if (!projectId) return; cursorRef.current = { cursor: null, cursorCreatedAt: null }; fetchPage(null, true); // eslint-disable-next-line react-hooks/exhaustive-deps }, [projectId, typesKey]); const loadMore = (0, react_1.useCallback)(async () => { if (loading || !hasMore) return; await fetchPage(cursorRef.current, false); }, [loading, hasMore, fetchPage]); const refresh = (0, react_1.useCallback)(async () => { cursorRef.current = { cursor: null, cursorCreatedAt: null }; await fetchPage(null, true); }, [fetchPage]); const createGroup = (0, react_1.useCallback)(async (params) => { if (!projectId) throw new Error("No project ID"); const response = await axios.post(`/${projectId}/chat/conversations`, { type: "group", ...params }); const conversation = response.data; // Prepend to the current list so it appears immediately const current = conversationsRef.current; dispatch((0, chatSlice_1.setConversationList)([conversation, ...current])); return conversation; }, [projectId, axios, dispatch]); return { conversations, loading, hasMore, loadMore, refresh, createGroup }; } exports.default = useConversations; //# sourceMappingURL=useConversations.js.map