@replyke/core
Version:
Replyke: Build interactive apps with social features like comments, votes, feeds, user lists, notifications, and more.
404 lines • 22.2 kB
JavaScript
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var react_1 = require("react");
var useCreateComment_1 = __importDefault(require("./useCreateComment"));
var handleError_1 = require("../../utils/handleError");
var useDeleteComment_1 = __importDefault(require("./useDeleteComment"));
var useUpdateComment_1 = __importDefault(require("./useUpdateComment"));
var useEntityComments_1 = __importDefault(require("./useEntityComments"));
var useFetchComment_1 = __importDefault(require("./useFetchComment"));
var useUser_1 = __importDefault(require("../users/useUser"));
var entities_1 = require("../entities");
var isUUID_1 = require("../../utils/isUUID");
function useCommentSectionData(props) {
var _this = this;
var entityProp = props.entity, entityId = props.entityId, foreignId = props.foreignId, shortId = props.shortId, createIfNotFound = props.createIfNotFound, _a = props.defaultSortBy, defaultSortBy = _a === void 0 ? "top" : _a, _b = props.limit, limit = _b === void 0 ? 15 : _b, _c = props.callbacks, callbacks = _c === void 0 ? {} : _c, highlightedCommentId = props.highlightedCommentId;
var setContextEntity = (0, entities_1.useEntity)().setEntity;
var _d = (0, react_1.useState)(entityProp), entity = _d[0], setEntity = _d[1];
var user = (0, useUser_1.default)().user;
var _e = (0, useEntityComments_1.default)({ entityId: entity === null || entity === void 0 ? void 0 : entity.id, defaultSortBy: defaultSortBy, limit: limit }), entityCommentsTree = _e.entityCommentsTree, comments = _e.comments, newComments = _e.newComments, loading = _e.loading, hasMore = _e.hasMore, sortBy = _e.sortBy, setSortBy = _e.setSortBy, loadMore = _e.loadMore, addCommentsToTree = _e.addCommentsToTree, removeCommentFromTree = _e.removeCommentFromTree;
var createComment = (0, useCreateComment_1.default)();
var deleteComment = (0, useDeleteComment_1.default)();
var updateComment = (0, useUpdateComment_1.default)();
var fetchComment = (0, useFetchComment_1.default)();
var fetchEntity = (0, entities_1.useFetchEntity)();
var fetchEntityByForeignId = (0, entities_1.useFetchEntityByForeignId)();
var fetchEntityByShortId = (0, entities_1.useFetchEntityByShortId)();
var _f = (0, react_1.useState)(null), highlightedComment = _f[0], setHighlightedComment = _f[1];
var fetchingCommentIdRef = (0, react_1.useRef)(null);
var fetchedStatus = (0, react_1.useRef)({}); // Track status by unique key
var submittingComment = (0, react_1.useRef)(false);
var _g = (0, react_1.useState)(false), submittingCommentState = _g[0], setSubmittingCommentState = _g[1]; // required to trigger rerenders
var _h = (0, react_1.useState)(null), pushMention = _h[0], setPushMention = _h[1];
// const previousPushMention = useRef<null | User>(null);
var _j = (0, react_1.useState)(null), repliedToComment = _j[0], setRepliedToComment = _j[1];
var _k = (0, react_1.useState)(false), showReplyBanner = _k[0], setShowReplyBanner = _k[1];
var _l = (0, react_1.useState)(null), selectedComment = _l[0], setSelectedComment = _l[1];
// const handleSetPushMention = (user: User | null) => {
// if(!user?.username)
// setPushMention((prevMention) => {
// if (JSON.stringify(prevMention) === JSON.stringify(user)) {
// return prevMention;
// }
// return user;
// });
// };
// For replies that appear as a child of the comment they are replying to.
var handleDeepReply = (0, react_1.useCallback)(function (comment) {
setRepliedToComment(comment);
setShowReplyBanner(true);
}, [setRepliedToComment]);
// For replies that appear at the same level as the comment they are replying to. Includes a mention (e.g. @username).
var handleShallowReply = (0, react_1.useCallback)(function (comment) {
var _a;
setRepliedToComment({ id: (_a = comment.parentId) !== null && _a !== void 0 ? _a : undefined });
setPushMention(comment.user);
}, [setRepliedToComment]);
var handleCreateComment = (0, react_1.useCallback)(function (props) { return __awaiter(_this, void 0, void 0, function () {
var parentId, content, gif, mentions, filteredMentions, TEMP_ID, tempNewComment, newCommentData, err_1;
var _a, _b, _c;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
parentId = props.parentId, content = props.content, gif = props.gif, mentions = props.mentions;
if (submittingComment.current)
return [2 /*return*/];
if (!entity) {
console.error("Invalid entity in useCommentSection");
return [2 /*return*/];
}
if (!user) {
(_a = callbacks === null || callbacks === void 0 ? void 0 : callbacks.loginRequiredCallback) === null || _a === void 0 ? void 0 : _a.call(callbacks);
return [2 /*return*/];
}
if ((callbacks === null || callbacks === void 0 ? void 0 : callbacks.usernameRequiredCallback) && !user.username) {
callbacks === null || callbacks === void 0 ? void 0 : callbacks.usernameRequiredCallback();
return [2 /*return*/];
}
if (!gif && (!content || content.length <= 1)) {
callbacks === null || callbacks === void 0 ? void 0 : callbacks.commentTooShortCallback();
return [2 /*return*/];
}
submittingComment.current = true;
setSubmittingCommentState(true);
filteredMentions = content
? (mentions || []).filter(function (mention) {
var mentionRegex = new RegExp("@".concat(mention.username, "\\b"), "g");
// const mentionRegex = new RegExp(
// `@(${mention.username}|${mention.name})\\b`,
// "g"
// );
return mentionRegex.test(content);
})
: [];
TEMP_ID = Math.random().toString(36).substring(2, 7);
tempNewComment = {
id: TEMP_ID,
foreignId: null,
projectId: "TEMP_PROJECT_ID",
userId: user.id,
parentId: (_b = parentId !== null && parentId !== void 0 ? parentId : repliedToComment === null || repliedToComment === void 0 ? void 0 : repliedToComment.id) !== null && _b !== void 0 ? _b : null,
entityId: entity.id,
content: content !== null && content !== void 0 ? content : null,
gif: gif !== null && gif !== void 0 ? gif : null,
mentions: filteredMentions,
user: __assign(__assign({}, user), { bio: null, birthdate: new Date(), location: null, createdAt: new Date() }),
upvotes: [],
downvotes: [],
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
parentDeletedAt: null,
repliesCount: 0,
};
setRepliedToComment(null);
setShowReplyBanner(false);
setPushMention(null);
_d.label = 1;
case 1:
_d.trys.push([1, 3, 4, 5]);
addCommentsToTree([tempNewComment], true);
return [4 /*yield*/, createComment({
entityId: entity.id,
parentCommentId: (_c = parentId !== null && parentId !== void 0 ? parentId : repliedToComment === null || repliedToComment === void 0 ? void 0 : repliedToComment.id) !== null && _c !== void 0 ? _c : null,
content: content,
gif: gif,
mentions: filteredMentions,
})];
case 2:
newCommentData = _d.sent();
if (newCommentData) {
removeCommentFromTree(TEMP_ID);
addCommentsToTree([newCommentData], true);
}
setContextEntity === null || setContextEntity === void 0 ? void 0 : setContextEntity(function (prevEntity) {
if (!prevEntity)
return prevEntity;
return __assign(__assign({}, prevEntity), { repliesCount: prevEntity.repliesCount + 1 });
});
return [3 /*break*/, 5];
case 3:
err_1 = _d.sent();
// TODO: currently we remove the temp comment from the tree but don't offer the user any option to retry. It's as if they've never sent anything and all they typed is gone. We need to add a flag for comment in the tree that says t failed so we can give he user a try again button
removeCommentFromTree(TEMP_ID);
(0, handleError_1.handleError)(err_1, "Failed to submit a new comment: ");
return [3 /*break*/, 5];
case 4:
submittingComment.current = false;
setSubmittingCommentState(false);
return [7 /*endfinally*/];
case 5: return [2 /*return*/];
}
});
}); }, [
user,
addCommentsToTree,
removeCommentFromTree,
entity,
createComment,
repliedToComment,
callbacks,
]);
var handleDeleteComment = (0, react_1.useCallback)(function (_a) { return __awaiter(_this, [_a], void 0, function (_b) {
var err_2;
var commentId = _b.commentId;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
if (!(0, isUUID_1.isUUID)(commentId))
return [2 /*return*/];
_c.label = 1;
case 1:
_c.trys.push([1, 3, , 4]);
removeCommentFromTree(commentId);
return [4 /*yield*/, deleteComment({ commentId: commentId })];
case 2:
_c.sent();
setContextEntity === null || setContextEntity === void 0 ? void 0 : setContextEntity(function (prevEntity) {
if (!prevEntity)
return prevEntity;
return __assign(__assign({}, prevEntity), { repliesCount: prevEntity.repliesCount - 1 });
});
return [3 /*break*/, 4];
case 3:
err_2 = _c.sent();
(0, handleError_1.handleError)(err_2, "Failed to delete comment");
return [3 /*break*/, 4];
case 4: return [2 /*return*/];
}
});
}); }, [deleteComment, removeCommentFromTree]);
var handleUpdateComment = (0, react_1.useCallback)(function (_a) { return __awaiter(_this, [_a], void 0, function (_b) {
var updatedComment, err_3;
var commentId = _b.commentId, content = _b.content;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
_c.trys.push([0, 2, , 3]);
return [4 /*yield*/, updateComment({ commentId: commentId, content: content })];
case 1:
updatedComment = _c.sent();
if (updatedComment) {
console.log("update comment in tree. Implement!");
}
return [3 /*break*/, 3];
case 2:
err_3 = _c.sent();
(0, handleError_1.handleError)(err_3, "Failed to update comment");
return [3 /*break*/, 3];
case 3: return [2 /*return*/];
}
});
}); }, [updateComment]);
(0, react_1.useEffect)(function () {
var handleFetchSingleComment = function () { return __awaiter(_this, void 0, void 0, function () {
var fetchedCommentData, targetComment, parentComment, err_4;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (fetchingCommentIdRef.current === highlightedCommentId) {
return [2 /*return*/]; // Skip if already fetching for this comment ID
}
fetchingCommentIdRef.current = highlightedCommentId;
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, fetchComment({
commentId: highlightedCommentId,
withParent: true,
})];
case 2:
fetchedCommentData = _a.sent();
if (!fetchedCommentData) {
console.error("Issue fetching single comment comment not found");
return [2 /*return*/];
}
if (!fetchedCommentData.comment) {
console.error("Highlighted comment not found");
}
setHighlightedComment(fetchedCommentData);
targetComment = fetchedCommentData.comment, parentComment = fetchedCommentData.parentComment;
addCommentsToTree === null || addCommentsToTree === void 0 ? void 0 : addCommentsToTree(parentComment ? [targetComment, parentComment] : [targetComment]);
return [3 /*break*/, 4];
case 3:
err_4 = _a.sent();
(0, handleError_1.handleError)(err_4, "Fetching single comment failed");
return [3 /*break*/, 4];
case 4: return [2 /*return*/];
}
});
}); };
if (highlightedCommentId) {
handleFetchSingleComment();
}
}, [highlightedCommentId, fetchComment, addCommentsToTree]);
(0, react_1.useEffect)(function () {
var handleFetchEntity = function () { return __awaiter(_this, void 0, void 0, function () {
var uniqueKey, fetchedEntity, err_5;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!foreignId && !entityId && !shortId)
return [2 /*return*/];
if (entity && entityId && entity.id === entityId)
return [2 /*return*/];
if (entity && foreignId && entity.foreignId === foreignId)
return [2 /*return*/];
if (entity && shortId && entity.shortId === shortId)
return [2 /*return*/];
uniqueKey = "".concat(entityId !== null && entityId !== void 0 ? entityId : "", "-").concat(foreignId !== null && foreignId !== void 0 ? foreignId : "", "-").concat(shortId !== null && shortId !== void 0 ? shortId : "");
if (fetchedStatus.current[uniqueKey])
return [2 /*return*/];
fetchedStatus.current[uniqueKey] = true;
_a.label = 1;
case 1:
_a.trys.push([1, 8, , 9]);
fetchedEntity = null;
if (!entityId) return [3 /*break*/, 3];
return [4 /*yield*/, fetchEntity({
entityId: entityId,
})];
case 2:
fetchedEntity = _a.sent();
return [3 /*break*/, 7];
case 3:
if (!foreignId) return [3 /*break*/, 5];
return [4 /*yield*/, fetchEntityByForeignId({
foreignId: foreignId,
createIfNotFound: createIfNotFound,
})];
case 4:
fetchedEntity = _a.sent();
return [3 /*break*/, 7];
case 5:
if (!shortId) return [3 /*break*/, 7];
return [4 /*yield*/, fetchEntityByShortId({
shortId: shortId,
})];
case 6:
fetchedEntity = _a.sent();
_a.label = 7;
case 7:
if (fetchedEntity)
setEntity(fetchedEntity);
return [3 /*break*/, 9];
case 8:
err_5 = _a.sent();
(0, handleError_1.handleError)(err_5, "Fetching entity failed");
return [3 /*break*/, 9];
case 9: return [2 /*return*/];
}
});
}); };
handleFetchEntity();
}, [
fetchEntity,
fetchEntityByForeignId,
fetchEntityByShortId,
entityId,
foreignId,
shortId,
entity,
createIfNotFound,
]);
return {
entity: entity,
callbacks: callbacks,
entityCommentsTree: entityCommentsTree,
comments: comments,
newComments: newComments,
highlightedComment: highlightedComment,
loading: loading,
hasMore: hasMore,
submittingComment: submittingCommentState,
loadMore: loadMore,
sortBy: sortBy,
setSortBy: setSortBy,
pushMention: pushMention,
selectedComment: selectedComment,
setSelectedComment: setSelectedComment,
repliedToComment: repliedToComment,
setRepliedToComment: setRepliedToComment,
showReplyBanner: showReplyBanner,
setShowReplyBanner: setShowReplyBanner,
addCommentsToTree: addCommentsToTree,
removeCommentFromTree: removeCommentFromTree,
handleShallowReply: handleShallowReply,
handleDeepReply: handleDeepReply,
createComment: handleCreateComment,
updateComment: handleUpdateComment,
deleteComment: handleDeleteComment,
};
}
exports.default = useCommentSectionData;
//# sourceMappingURL=useCommentSectionData.js.map