@replyke/core
Version:
Replyke: Build interactive apps with social features like comments, votes, feeds, user lists, notifications, and more.
214 lines • 9.46 kB
JavaScript
;
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.selectSpaceListConfig = exports.selectSpaceListFilters = exports.selectSpaceListHasMore = exports.selectSpaceListLoading = exports.selectSpaceListSpaces = exports.selectSpaceList = exports.cleanupOldLists = exports.cleanupList = exports.updateSpace = exports.removeSpace = exports.addSpace = exports.setSpaceListError = exports.setSpaceListHasMore = exports.incrementPage = exports.setSpaceListSpaces = exports.setSpaceListLoading = exports.updateFilters = exports.initializeList = exports.spaceListsSlice = void 0;
const toolkit_1 = require("@reduxjs/toolkit");
// Default state for a new space list
const createDefaultSpaceListState = () => ({
spaces: [],
page: 1,
loading: true,
hasMore: true,
error: null,
lastFetched: null,
// Default configuration
limit: 20,
// Default filters (user-controlled only)
sortBy: "newest",
searchSlug: null,
searchName: null,
searchDescription: null,
searchAny: null,
readingPermission: null,
memberOf: false,
parentSpaceId: undefined, // Will be set when fetchSpaces is called
});
// Initial state
const initialState = {
lists: {},
};
// Create the slice
exports.spaceListsSlice = (0, toolkit_1.createSlice)({
name: "spaceLists",
initialState,
reducers: {
// Initialize or get existing list
initializeList: (state, action) => {
const { listId } = action.payload;
if (!state.lists[listId]) {
state.lists[listId] = createDefaultSpaceListState();
}
},
// Update filters and sort (unified function)
updateFilters: (state, action) => {
const { listId, filters, options } = action.payload;
// Ensure list exists
if (!state.lists[listId]) {
state.lists[listId] = createDefaultSpaceListState();
}
const list = state.lists[listId];
// If resetUnspecified is true, reset to defaults first
if (options?.resetUnspecified) {
const defaultState = createDefaultSpaceListState();
// Reset all filter properties to defaults
list.sortBy = defaultState.sortBy;
list.searchSlug = defaultState.searchSlug;
list.searchName = defaultState.searchName;
list.searchDescription = defaultState.searchDescription;
list.searchAny = defaultState.searchAny;
list.readingPermission = defaultState.readingPermission;
list.memberOf = defaultState.memberOf;
list.parentSpaceId = defaultState.parentSpaceId;
}
// Update specified filters
Object.keys(filters).forEach((key) => {
if (filters[key] !== undefined) {
list[key] = filters[key];
}
});
// Update config if provided
if (action.payload.config) {
if (action.payload.config.limit !== undefined) {
list.limit = action.payload.config.limit;
}
}
// Reset pagination when filters change
list.page = 1;
list.hasMore = true;
list.error = null;
},
// Set loading state for space list
setSpaceListLoading: (state, action) => {
const { listId, loading } = action.payload;
if (state.lists[listId]) {
state.lists[listId].loading = loading;
}
},
// Set spaces for space list
setSpaceListSpaces: (state, action) => {
const { listId, spaces, append = false } = action.payload;
if (!state.lists[listId]) {
state.lists[listId] = createDefaultSpaceListState();
}
const list = state.lists[listId];
if (append) {
// Filter out duplicates when appending
const existingIds = new Set(list.spaces.map((s) => s.id));
const newSpaces = spaces.filter((s) => !existingIds.has(s.id));
list.spaces = [...list.spaces, ...newSpaces];
}
else {
list.spaces = spaces;
}
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 space list
setSpaceListHasMore: (state, action) => {
const { listId, hasMore } = action.payload;
if (state.lists[listId]) {
state.lists[listId].hasMore = hasMore;
}
},
// Set error for space list
setSpaceListError: (state, action) => {
const { listId, error } = action.payload;
if (state.lists[listId]) {
state.lists[listId].error = error;
state.lists[listId].loading = false;
}
},
// Add space
addSpace: (state, action) => {
const { listId, space, insertPosition = "first" } = action.payload;
if (!state.lists[listId])
return;
const list = state.lists[listId];
if (insertPosition === "last") {
list.spaces.push(space);
}
else {
list.spaces.unshift(space);
}
},
// Remove space
removeSpace: (state, action) => {
const { listId, spaceId } = action.payload;
if (!state.lists[listId])
return;
const list = state.lists[listId];
list.spaces = list.spaces.filter((s) => s.id !== spaceId);
},
// Update space
updateSpace: (state, action) => {
const { listId, spaceId, updates } = action.payload;
if (!state.lists[listId])
return;
const list = state.lists[listId];
const spaceIndex = list.spaces.findIndex((s) => s.id === spaceId);
if (spaceIndex !== -1) {
list.spaces[spaceIndex] = {
...list.spaces[spaceIndex],
...updates,
};
}
},
// 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.spaceListsSlice.actions, exports.initializeList = _a.initializeList, exports.updateFilters = _a.updateFilters, exports.setSpaceListLoading = _a.setSpaceListLoading, exports.setSpaceListSpaces = _a.setSpaceListSpaces, exports.incrementPage = _a.incrementPage, exports.setSpaceListHasMore = _a.setSpaceListHasMore, exports.setSpaceListError = _a.setSpaceListError, exports.addSpace = _a.addSpace, exports.removeSpace = _a.removeSpace, exports.updateSpace = _a.updateSpace, exports.cleanupList = _a.cleanupList, exports.cleanupOldLists = _a.cleanupOldLists;
// Base selectors - use namespaced state for dual-mode support
const selectSpaceListsState = (state) => state.replyke.spaceLists;
const selectListId = (_, listId) => listId;
// Memoized selectors using createSelector
exports.selectSpaceList = (0, toolkit_1.createSelector)([selectSpaceListsState, selectListId], (spaceListsState, listId) => spaceListsState.lists[listId]);
exports.selectSpaceListSpaces = (0, toolkit_1.createSelector)([exports.selectSpaceList], (spaceList) => spaceList?.spaces || []);
exports.selectSpaceListLoading = (0, toolkit_1.createSelector)([exports.selectSpaceList], (spaceList) => spaceList?.loading || false);
exports.selectSpaceListHasMore = (0, toolkit_1.createSelector)([exports.selectSpaceList], (spaceList) => spaceList?.hasMore || false);
exports.selectSpaceListFilters = (0, toolkit_1.createSelector)([exports.selectSpaceList], (spaceList) => {
if (!spaceList)
return null;
return {
sortBy: spaceList.sortBy,
searchSlug: spaceList.searchSlug,
searchName: spaceList.searchName,
searchDescription: spaceList.searchDescription,
searchAny: spaceList.searchAny,
readingPermission: spaceList.readingPermission,
memberOf: spaceList.memberOf,
parentSpaceId: spaceList.parentSpaceId,
};
});
exports.selectSpaceListConfig = (0, toolkit_1.createSelector)([exports.selectSpaceList], (spaceList) => {
if (!spaceList)
return null;
return {
limit: spaceList.limit,
};
});
exports.default = exports.spaceListsSlice.reducer;
//# sourceMappingURL=spaceListsSlice.js.map