@replyke/core
Version:
Replyke: Build interactive apps with social features like comments, votes, feeds, user lists, notifications, and more.
101 lines • 5 kB
JavaScript
;
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