@replyke/core
Version:
Replyke: Build interactive apps with social features like comments, votes, feeds, user lists, notifications, and more.
243 lines • 9.53 kB
JavaScript
"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 useFetchSpace_1 = __importDefault(require("./useFetchSpace"));
const useFetchSpaceByShortId_1 = __importDefault(require("./useFetchSpaceByShortId"));
const useFetchSpaceBySlug_1 = __importDefault(require("./useFetchSpaceBySlug"));
const useFetchSpaceBreadcrumb_1 = __importDefault(require("./useFetchSpaceBreadcrumb"));
const useUpdateSpace_1 = __importDefault(require("./useUpdateSpace"));
const useDeleteSpace_1 = __importDefault(require("./useDeleteSpace"));
const useJoinSpace_1 = __importDefault(require("./useJoinSpace"));
const useLeaveSpace_1 = __importDefault(require("./useLeaveSpace"));
const useSpacePermissions_1 = __importDefault(require("./useSpacePermissions"));
const handleError_1 = require("../../utils/handleError");
function useSpaceData({ spaceId, shortId, slug, space: spaceProp, include, }) {
const [space, setSpace] = (0, react_1.useState)(spaceProp);
const [loading, setLoading] = (0, react_1.useState)(false);
const [error, setError] = (0, react_1.useState)(null);
const [breadcrumb, setBreadcrumb] = (0, react_1.useState)([]);
// Cache to store fetched spaces keyed by unique identifier
const spaceCache = (0, react_1.useRef)({});
// Fetch hooks
const fetchSpace = (0, useFetchSpace_1.default)();
const fetchSpaceByShortId = (0, useFetchSpaceByShortId_1.default)();
const fetchSpaceBySlug = (0, useFetchSpaceBySlug_1.default)();
const fetchSpaceBreadcrumb = (0, useFetchSpaceBreadcrumb_1.default)();
// Operation hooks
const updateSpaceHook = (0, useUpdateSpace_1.default)();
const deleteSpaceHook = (0, useDeleteSpace_1.default)();
const joinSpaceHook = (0, useJoinSpace_1.default)();
const leaveSpaceHook = (0, useLeaveSpace_1.default)();
// Stabilize include param to prevent infinite loops when passed as inline array
const stableInclude = (0, react_1.useMemo)(() => include,
// eslint-disable-next-line react-hooks/exhaustive-deps
[JSON.stringify(include)]);
// Compute permissions
const permissions = (0, useSpacePermissions_1.default)({
memberPermissions: space?.memberPermissions,
postingPermission: space?.postingPermission || "members",
readingPermission: space?.readingPermission || "anyone",
});
// Handle space update
const handleUpdateSpace = (0, react_1.useCallback)(async ({ update }) => {
if (!space)
return;
try {
const newSpace = await updateSpaceHook({
spaceId: space.id,
update,
});
if (newSpace)
setSpace(newSpace);
return newSpace;
}
catch (err) {
(0, handleError_1.handleError)(err, "Failed to update space");
setError("Failed to update space");
}
}, [space, updateSpaceHook]);
// Handle space delete
const handleDeleteSpace = (0, react_1.useCallback)(async () => {
if (!space)
return;
try {
await deleteSpaceHook({ spaceId: space.id });
setSpace(undefined);
}
catch (err) {
(0, handleError_1.handleError)(err, "Failed to delete space");
setError("Failed to delete space");
}
}, [space, deleteSpaceHook]);
// Handle join space
const handleJoinSpace = (0, react_1.useCallback)(async () => {
if (!space)
return;
try {
const response = await joinSpaceHook({ spaceId: space.id });
const member = response.membership;
// Update space with new memberPermissions and member count
// Note: When joining, role is always "member", status is "pending" or "active"
setSpace((prev) => {
if (!prev)
return prev;
return {
...prev,
membersCount: prev.membersCount + 1,
memberPermissions: {
isAdmin: false,
isModerator: false,
isMember: member.status === "active",
status: member.status,
canPost: member.status === "active",
canModerate: false,
canRead: true,
},
};
});
}
catch (err) {
(0, handleError_1.handleError)(err, "Failed to join space");
setError("Failed to join space");
}
}, [space, joinSpaceHook]);
// Handle leave space
const handleLeaveSpace = (0, react_1.useCallback)(async () => {
if (!space)
return;
try {
await leaveSpaceHook({ spaceId: space.id });
// Update space to remove memberPermissions and decrement member count
setSpace((prev) => {
if (!prev)
return prev;
return {
...prev,
membersCount: Math.max(0, prev.membersCount - 1),
memberPermissions: null,
};
});
}
catch (err) {
(0, handleError_1.handleError)(err, "Failed to leave space");
setError("Failed to leave space");
}
}, [space, leaveSpaceHook]);
// Fetch space effect
(0, react_1.useEffect)(() => {
const handleFetchSpace = async () => {
if (!spaceId && !shortId && !slug)
return;
// If space is already loaded with matching ID, skip fetch
if (space && spaceId && space.id === spaceId)
return;
if (space && shortId && space.shortId === shortId)
return;
if (space && slug && space.slug === slug)
return;
const uniqueKey = `${spaceId ?? ""}-${shortId ?? ""}-${slug ?? ""}`;
// If we have a cached space, update the state and exit
if (spaceCache.current[uniqueKey]) {
setSpace(spaceCache.current[uniqueKey]);
return;
}
setLoading(true);
setError(null);
try {
let fetchedSpace = null;
if (spaceId) {
fetchedSpace = await fetchSpace({ spaceId, include: stableInclude });
}
else if (shortId) {
fetchedSpace = await fetchSpaceByShortId({ shortId, include: stableInclude });
}
else if (slug) {
fetchedSpace = await fetchSpaceBySlug({ slug, include: stableInclude });
}
if (fetchedSpace) {
// Store the fetched space in cache
spaceCache.current[uniqueKey] = fetchedSpace;
setSpace(fetchedSpace);
}
else {
setSpace(null);
}
}
catch (err) {
(0, handleError_1.handleError)(err, "Failed to fetch space");
setError("Failed to fetch space");
setSpace(null);
}
finally {
setLoading(false);
}
};
handleFetchSpace();
}, [
fetchSpace,
fetchSpaceByShortId,
fetchSpaceBySlug,
spaceId,
shortId,
slug,
space,
stableInclude,
]);
// Fetch breadcrumb effect
(0, react_1.useEffect)(() => {
const handleFetchBreadcrumb = async () => {
if (!space?.id) {
setBreadcrumb([]);
return;
}
try {
const breadcrumbData = await fetchSpaceBreadcrumb({
spaceId: space.id,
});
setBreadcrumb(breadcrumbData.breadcrumb);
}
catch (err) {
// Breadcrumb is not critical, just log the error
(0, handleError_1.handleError)(err, "Failed to fetch space breadcrumb");
setBreadcrumb([]);
}
};
handleFetchBreadcrumb();
}, [space?.id, fetchSpaceBreadcrumb]);
// Update space when prop changes
(0, react_1.useEffect)(() => {
if (spaceProp)
setSpace(spaceProp);
}, [spaceProp]);
return {
space,
setSpace,
// Permissions
isMember: permissions.isMember,
isAdmin: permissions.isAdmin,
isModerator: permissions.isModerator,
canPost: permissions.canPost,
canModerate: permissions.canModerate,
canRead: permissions.canRead,
membershipStatus: space?.memberPermissions?.status || null,
isPending: permissions.isPending,
isBanned: permissions.isBanned,
// Hierarchy
breadcrumb,
parentSpace: space?.parentSpace || null,
childSpaces: space?.childSpaces || [],
// Operations
updateSpace: handleUpdateSpace,
deleteSpace: handleDeleteSpace,
joinSpace: handleJoinSpace,
leaveSpace: handleLeaveSpace,
// State
loading,
error,
};
}
exports.default = useSpaceData;
//# sourceMappingURL=useSpaceData.js.map