UNPKG

@replyke/core

Version:

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

313 lines 13.7 kB
"use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.selectEntityListConfig = exports.selectEntityListFilters = exports.selectEntityListSort = exports.selectEntityListHasMore = exports.selectEntityListLoading = exports.selectEntityListEntities = exports.selectEntityList = exports.cleanupOldLists = exports.cleanupList = exports.updateKeywordsFilters = exports.removeEntity = exports.addEntity = exports.setEntityListError = exports.setEntityListHasMore = exports.incrementPage = exports.setEntityListEntities = exports.setEntityListLoading = exports.updateFiltersAndSortConfig = exports.initializeList = exports.entityListsSlice = void 0; const toolkit_1 = require("@reduxjs/toolkit"); // Default state for a new entity list const createDefaultEntityListState = () => ({ entities: [], page: 1, loading: true, hasMore: true, error: null, lastFetched: null, // Default configuration sourceId: null, spaceId: null, limit: 10, include: null, // Default filters (user-controlled only) sortBy: "hot", sortByReaction: "upvote", sortDir: null, sortType: "auto", timeFrame: null, userId: null, followedOnly: false, keywordsFilters: null, titleFilters: null, contentFilters: null, attachmentsFilters: null, locationFilters: null, metadataFilters: null, }); // Initial state const initialState = { lists: {}, }; // Create the slice exports.entityListsSlice = (0, toolkit_1.createSlice)({ name: "entityLists", initialState, reducers: { // Initialize or get existing list initializeList: (state, action) => { const { listId } = action.payload; if (!state.lists[listId]) { state.lists[listId] = createDefaultEntityListState(); } }, // Update filters and sort configuration updateFiltersAndSortConfig: (state, action) => { const { listId, filters, sort, config, options } = action.payload; // Ensure list exists if (!state.lists[listId]) { state.lists[listId] = createDefaultEntityListState(); } const list = state.lists[listId]; // Handle resetFilters flag - reset only filter properties if (options?.resetFilters) { const defaultState = createDefaultEntityListState(); list.timeFrame = defaultState.timeFrame; list.userId = defaultState.userId; list.followedOnly = defaultState.followedOnly; list.keywordsFilters = defaultState.keywordsFilters; list.titleFilters = defaultState.titleFilters; list.contentFilters = defaultState.contentFilters; list.attachmentsFilters = defaultState.attachmentsFilters; list.locationFilters = defaultState.locationFilters; list.metadataFilters = defaultState.metadataFilters; } // Handle resetSort flag - reset only sort properties if (options?.resetSort) { const defaultState = createDefaultEntityListState(); list.sortBy = defaultState.sortBy; list.sortByReaction = defaultState.sortByReaction; list.sortDir = defaultState.sortDir; list.sortType = defaultState.sortType; } // Apply specified filters Object.keys(filters).forEach((key) => { if (filters[key] !== undefined) { list[key] = filters[key]; } }); // Apply specified sort configuration if (sort) { if (sort.sortBy !== undefined) list.sortBy = sort.sortBy; if (sort.sortByReaction !== undefined) list.sortByReaction = sort.sortByReaction; if (sort.sortDir !== undefined) list.sortDir = sort.sortDir; if (sort.sortType !== undefined) list.sortType = sort.sortType; } // Update config if provided if (config) { if (config.sourceId !== undefined) { list.sourceId = config.sourceId; } if (config.spaceId !== undefined) { list.spaceId = config.spaceId; } if (config.limit !== undefined) { list.limit = config.limit; } if (config.include !== undefined) { list.include = config.include; } } // Reset pagination when filters or sort changes list.page = 1; list.hasMore = true; list.error = null; }, // Set loading state for entity list setEntityListLoading: (state, action) => { const { listId, loading } = action.payload; if (state.lists[listId]) { state.lists[listId].loading = loading; } }, // Set entities for entity list setEntityListEntities: (state, action) => { const { listId, entities, append = false } = action.payload; if (!state.lists[listId]) { state.lists[listId] = createDefaultEntityListState(); } const list = state.lists[listId]; if (append) { // Filter out duplicates when appending const existingIds = new Set(list.entities.map((e) => e.id)); const newEntities = entities.filter((e) => !existingIds.has(e.id)); list.entities = [...list.entities, ...newEntities]; } else { list.entities = entities; } list.loading = false; list.lastFetched = Date.now(); // Note: hasMore is set explicitly by the caller based on limit from hook props }, // Increment page for load more incrementPage: (state, action) => { const listId = action.payload; if (state.lists[listId]) { state.lists[listId].page += 1; } }, // Set hasMore for entity list setEntityListHasMore: (state, action) => { const { listId, hasMore } = action.payload; if (state.lists[listId]) { state.lists[listId].hasMore = hasMore; } }, // Set error for entity list setEntityListError: (state, action) => { const { listId, error } = action.payload; if (state.lists[listId]) { state.lists[listId].error = error; state.lists[listId].loading = false; } }, // Add entity addEntity: (state, action) => { const { listId, entity, insertPosition = "first" } = action.payload; if (!state.lists[listId]) return; const list = state.lists[listId]; if (insertPosition === "last") { list.entities.push(entity); } else { list.entities.unshift(entity); } }, // Remove entity removeEntity: (state, action) => { const { listId, entityId } = action.payload; if (!state.lists[listId]) return; const list = state.lists[listId]; list.entities = list.entities.filter((e) => e.id !== entityId); }, // Update keywords filters (special case due to complexity) updateKeywordsFilters: (state, action) => { const { listId, type, key, value } = action.payload; if (!state.lists[listId]) { state.lists[listId] = createDefaultEntityListState(); } const list = state.lists[listId]; const items = Array.isArray(value) ? value : value ? [value] : []; let newFilters = list.keywordsFilters || {}; switch (type) { case "add": { if (key === "both") break; // Invalid to add to both newFilters = { ...newFilters, [key]: Array.from(new Set([...(newFilters[key] || []), ...items])), }; break; } case "remove": { if (key === "both") { newFilters = { includes: (newFilters.includes || []).filter((item) => !items.includes(item)), doesNotInclude: (newFilters.doesNotInclude || []).filter((item) => !items.includes(item)), }; } else { newFilters = { ...newFilters, [key]: (newFilters[key] || []).filter((item) => !items.includes(item)), }; } break; } case "reset": { if (key === "both") { newFilters = {}; } else { newFilters = { ...newFilters, [key]: undefined, }; } break; } case "replace": { if (key === "both") break; // Replace does not apply to both newFilters = { ...newFilters, [key]: items, }; break; } } list.keywordsFilters = Object.keys(newFilters).length > 0 ? newFilters : null; // Reset pagination when filters change list.page = 1; list.hasMore = true; list.error = null; }, // Clean up unused lists (for memory management) cleanupList: (state, action) => { const listId = action.payload; delete state.lists[listId]; }, // Clean up old lists (older than TTL) cleanupOldLists: (state, action) => { const ttl = action.payload; // TTL in milliseconds const now = Date.now(); Object.keys(state.lists).forEach((listId) => { const list = state.lists[listId]; if (list.lastFetched && now - list.lastFetched > ttl) { delete state.lists[listId]; } }); }, }, }); // Export actions _a = exports.entityListsSlice.actions, exports.initializeList = _a.initializeList, exports.updateFiltersAndSortConfig = _a.updateFiltersAndSortConfig, exports.setEntityListLoading = _a.setEntityListLoading, exports.setEntityListEntities = _a.setEntityListEntities, exports.incrementPage = _a.incrementPage, exports.setEntityListHasMore = _a.setEntityListHasMore, exports.setEntityListError = _a.setEntityListError, exports.addEntity = _a.addEntity, exports.removeEntity = _a.removeEntity, exports.updateKeywordsFilters = _a.updateKeywordsFilters, exports.cleanupList = _a.cleanupList, exports.cleanupOldLists = _a.cleanupOldLists; // Base selectors - use namespaced state for dual-mode support const selectEntityListsState = (state) => state.replyke.entityLists; const selectListId = (_, listId) => listId; // Memoized selectors using createSelector exports.selectEntityList = (0, toolkit_1.createSelector)([selectEntityListsState, selectListId], (entityListsState, listId) => entityListsState.lists[listId]); exports.selectEntityListEntities = (0, toolkit_1.createSelector)([exports.selectEntityList], (entityList) => entityList?.entities || []); exports.selectEntityListLoading = (0, toolkit_1.createSelector)([exports.selectEntityList], (entityList) => entityList?.loading || false); exports.selectEntityListHasMore = (0, toolkit_1.createSelector)([exports.selectEntityList], (entityList) => entityList?.hasMore || false); exports.selectEntityListSort = (0, toolkit_1.createSelector)([exports.selectEntityList], (entityList) => { if (!entityList) return null; return { sortBy: entityList.sortBy, sortByReaction: entityList.sortByReaction, sortDir: entityList.sortDir, sortType: entityList.sortType, }; }); exports.selectEntityListFilters = (0, toolkit_1.createSelector)([exports.selectEntityList], (entityList) => { if (!entityList) return null; return { timeFrame: entityList.timeFrame, userId: entityList.userId, followedOnly: entityList.followedOnly, keywordsFilters: entityList.keywordsFilters, titleFilters: entityList.titleFilters, contentFilters: entityList.contentFilters, attachmentsFilters: entityList.attachmentsFilters, locationFilters: entityList.locationFilters, metadataFilters: entityList.metadataFilters, }; }); exports.selectEntityListConfig = (0, toolkit_1.createSelector)([exports.selectEntityList], (entityList) => { if (!entityList) return null; return { sourceId: entityList.sourceId, spaceId: entityList.spaceId, limit: entityList.limit, include: entityList.include, }; }); exports.default = exports.entityListsSlice.reducer; //# sourceMappingURL=entityListsSlice.js.map