UNPKG

@churchapps/apphelper

Version:

Library of helper functions for React and NextJS ChurchApps

158 lines 7.2 kB
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; import React from "react"; import { Note } from "./Note"; import { AddNote } from "./AddNote"; import { DisplayBox, Loading } from "../"; import { ApiHelper, ArrayHelper, Locale } from "../../helpers"; export function Notes(props) { const [messages, setMessages] = React.useState(null); const [editMessageId, setEditMessageId] = React.useState(null); const [isInitialLoad, setIsInitialLoad] = React.useState(true); const [previousMessageCount, setPreviousMessageCount] = React.useState(0); // Add CSS for custom scrollbar styling React.useEffect(() => { const styleId = 'notes-scrollbar-styles'; if (!document.getElementById(styleId)) { const style = document.createElement('style'); style.id = styleId; style.textContent = ` .notes-scroll-container { scrollbar-width: thin; scrollbar-color: rgba(0, 0, 0, 0.3) rgba(0, 0, 0, 0.1); } .notes-scroll-container::-webkit-scrollbar { width: 12px; background: transparent; } .notes-scroll-container::-webkit-scrollbar-track { background: rgba(0, 0, 0, 0.1); border-radius: 6px; margin: 4px; } .notes-scroll-container::-webkit-scrollbar-thumb { background: rgba(0, 0, 0, 0.3); border-radius: 6px; border: 2px solid transparent; background-clip: content-box; } .notes-scroll-container::-webkit-scrollbar-thumb:hover { background: rgba(0, 0, 0, 0.5); background-clip: content-box; } .notes-scroll-container::-webkit-scrollbar-corner { background: transparent; } `; document.head.appendChild(style); } }, []); const loadNotes = async () => { try { const messages = (props.conversationId) ? await ApiHelper.get("/messages/conversation/" + props.conversationId, "MessagingApi") : []; if (messages.length > 0) { const peopleIds = ArrayHelper.getIds(messages, "personId"); const people = await ApiHelper.get("/people/basic?ids=" + peopleIds.join(","), "MembershipApi"); messages.forEach(n => { n.person = ArrayHelper.getOne(people, "id", n.personId); }); } setMessages(messages); setEditMessageId(null); // Mark as no longer initial load after first load if (isInitialLoad) { setIsInitialLoad(false); } } catch (error) { console.error("❌ Failed to load messages for conversation:", props.conversationId, error); // Don't clear messages on error - keep showing existing messages // Only set isInitialLoad to false if this was the first load attempt if (isInitialLoad) { setIsInitialLoad(false); } } }; const getNotes = () => { if (!messages) return _jsx(Loading, {}); if (messages.length === 0) return _jsx(_Fragment, {}); else { let noteArray = []; for (let i = 0; i < messages.length; i++) noteArray.push(_jsx(Note, { message: messages[i], showEditNote: setEditMessageId, context: props.context }, messages[i].id)); return noteArray; } }; const getNotesWrapper = () => { const notes = getNotes(); if (props.maxHeight) { return (_jsx("div", { id: "notesScroll", style: { flex: 1, minHeight: 0, overflowY: "auto", overflowX: "hidden", padding: "8px 12px", scrollBehavior: "smooth", height: "100%" }, className: "notes-scroll-container", "data-testid": "message-scroll-area", children: _jsx("div", { style: { display: "flex", flexDirection: "column", gap: "8px", minHeight: "min-content" }, children: notes }) })); } else return notes; }; React.useEffect(() => { loadNotes(); }, [props.conversationId, props.refreshKey]); //eslint-disable-line // Simply reload notes when refreshKey changes // This is triggered by the parent component when WebSocket messages arrive // Auto-scroll to bottom only when new messages are added (not on initial load) React.useEffect(() => { if (props.maxHeight && messages?.length > 0 && !isInitialLoad) { const currentMessageCount = messages.length; // Only auto-scroll if messages were added if (currentMessageCount > previousMessageCount) { // Use requestAnimationFrame for smoother scrolling requestAnimationFrame(() => { const element = window?.document?.getElementById("notesScroll"); if (element) { element.scrollTop = element.scrollHeight; } }); } setPreviousMessageCount(currentMessageCount); } else if (messages?.length > 0 && isInitialLoad) { // On initial load, just set the previous count without scrolling setPreviousMessageCount(messages.length); } }, [messages, props.maxHeight, isInitialLoad, previousMessageCount]); let result = props.maxHeight ? (_jsxs("div", { style: { height: "100%", display: "flex", flexDirection: "column", overflow: "hidden", minHeight: 0 }, children: [_jsx("div", { style: { flex: 1, minHeight: 0, display: "flex", flexDirection: "column", overflow: "hidden" }, children: getNotesWrapper() }), messages && (_jsx("div", { style: { flexShrink: 0, borderTop: "1px solid #e0e0e0", backgroundColor: "#fafafa", padding: "12px", minHeight: "auto", maxHeight: "200px" }, children: _jsx(AddNote, { context: props.context, conversationId: props.conversationId, onUpdate: loadNotes, createConversation: props.createConversation, messageId: editMessageId }) }))] })) : (_jsxs(_Fragment, { children: [getNotesWrapper(), messages && (_jsx(AddNote, { context: props.context, conversationId: props.conversationId, onUpdate: loadNotes, createConversation: props.createConversation, messageId: editMessageId }))] })); if (props.noDisplayBox) return result; else return (_jsx(DisplayBox, { id: "notesBox", "data-testid": "notes-box", headerIcon: "sticky_note_2", headerText: Locale.label("notes.notes", "Notes"), children: result })); } ; //# sourceMappingURL=Notes.js.map