UNPKG

@replyke/core

Version:

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

84 lines 3.52 kB
"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 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