@replyke/core
Version:
Replyke: Build interactive apps with social features like comments, votes, feeds, user lists, notifications, and more.
84 lines • 3.52 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 useAddReaction_1 = __importDefault(require("./useAddReaction"));
const useRemoveReaction_1 = __importDefault(require("./useRemoveReaction"));
const handleError_1 = require("../../utils/handleError");
function useReactionToggle({ targetType, targetId, initialReaction, initialReactionCounts, }) {
const addReaction = (0, useAddReaction_1.default)();
const removeReaction = (0, useRemoveReaction_1.default)();
const [currentReaction, setCurrentReaction] = (0, react_1.useState)(initialReaction ?? null);
const [reactionCounts, setReactionCounts] = (0, react_1.useState)(initialReactionCounts ?? {});
const [loading, setLoading] = (0, react_1.useState)(false);
// Reset state when target changes
(0, react_1.useEffect)(() => {
setCurrentReaction(initialReaction ?? null);
setReactionCounts(initialReactionCounts ?? {});
}, [targetId, initialReaction, initialReactionCounts]);
const toggleReaction = (0, react_1.useCallback)(async (props) => {
const { reactionType } = props;
// Guard: prevent concurrent operations
if (loading)
return null;
if (!targetId)
return null;
// Store original for revert on error
const originalReaction = currentReaction;
const originalCounts = { ...reactionCounts };
// Determine new reaction (null if same, reactionType if different)
const newReaction = currentReaction === reactionType ? null : reactionType;
// OPTIMISTIC: Update UI immediately
setCurrentReaction(newReaction);
// OPTIMISTIC: Update counts
const updatedCounts = { ...reactionCounts };
if (currentReaction) {
// Decrement old reaction count
updatedCounts[currentReaction] = Math.max((updatedCounts[currentReaction] || 0) - 1, 0);
}
if (newReaction) {
// Increment new reaction count
updatedCounts[newReaction] = (updatedCounts[newReaction] || 0) + 1;
}
setReactionCounts(updatedCounts);
try {
setLoading(true);
// Call backend
const result = newReaction === null
? await removeReaction({ targetType, targetId })
: await addReaction({ targetType, targetId, reactionType });
// Update with server truth (may differ from optimistic)
setCurrentReaction(result.userReaction ?? null);
setReactionCounts(result.reactionCounts ? { ...result.reactionCounts } : {});
return result;
}
catch (err) {
// REVERT: Restore original on error
setCurrentReaction(originalReaction);
setReactionCounts(originalCounts);
(0, handleError_1.handleError)(err, "Failed to toggle reaction:");
return null;
}
finally {
setLoading(false);
}
}, [
loading,
currentReaction,
reactionCounts,
targetType,
targetId,
addReaction,
removeReaction,
]);
return {
currentReaction,
reactionCounts,
toggleReaction,
loading,
};
}
exports.default = useReactionToggle;
//# sourceMappingURL=useReactionToggle.js.map