UNPKG

@trycourier/courier-react

Version:

The React components for the Courier web UI

396 lines (395 loc) 13.2 kB
import { jsx, Fragment } from "react/jsx-runtime"; import React, { createContext, forwardRef, useContext, useRef, useEffect, useState } from "react"; import { Courier } from "@trycourier/courier-js"; import { CourierInboxDatastore, CourierInboxDataStoreListener } from "@trycourier/courier-ui-inbox"; import { archiveMessage, clickMessage, defaultDarkTheme, defaultLightTheme, markAsRead, markAsUnread, mergeTheme, openMessage } from "@trycourier/courier-ui-inbox"; import { flushSync } from "react-dom"; import { createRoot } from "react-dom/client"; const useCourier = () => { const signIn = (props) => Courier.shared.signIn(props); const signOut = () => Courier.shared.signOut(); const loadInbox = (props) => CourierInboxDatastore.shared.load(props); const fetchNextPageOfMessages = (props) => CourierInboxDatastore.shared.fetchNextPageOfMessages(props); const setPaginationLimit = (limit) => Courier.shared.paginationLimit = limit; const readMessage = (message) => CourierInboxDatastore.shared.readMessage({ message }); const unreadMessage = (message) => CourierInboxDatastore.shared.unreadMessage({ message }); const clickMessage2 = (message) => CourierInboxDatastore.shared.clickMessage({ message }); const archiveMessage2 = (message) => CourierInboxDatastore.shared.archiveMessage({ message }); const openMessage2 = (message) => CourierInboxDatastore.shared.openMessage({ message }); const unarchiveMessage = (message) => CourierInboxDatastore.shared.unarchiveMessage({ message }); const readAllMessages = () => CourierInboxDatastore.shared.readAllMessages(); const [auth, setAuth] = React.useState({ userId: void 0, signIn, signOut }); const [inbox, setInbox] = React.useState({ load: loadInbox, fetchNextPageOfMessages, setPaginationLimit, readMessage, unreadMessage, clickMessage: clickMessage2, archiveMessage: archiveMessage2, openMessage: openMessage2, unarchiveMessage, readAllMessages }); React.useEffect(() => { const listener = Courier.shared.addAuthenticationListener(() => refreshAuth()); const inboxListener = new CourierInboxDataStoreListener({ onError: (error) => refreshInbox(error), onDataSetChange: () => refreshInbox(), onPageAdded: () => refreshInbox(), onMessageAdd: () => refreshInbox(), onMessageRemove: () => refreshInbox(), onMessageUpdate: () => refreshInbox(), onUnreadCountChange: () => refreshInbox() }); CourierInboxDatastore.shared.addDataStoreListener(inboxListener); refreshAuth(); refreshInbox(); return () => { listener.remove(); inboxListener.remove(); }; }, []); const refreshAuth = () => { var _a; const options = (_a = Courier.shared.client) == null ? void 0 : _a.options; setAuth({ userId: options == null ? void 0 : options.userId, signIn, signOut }); }; const refreshInbox = (error) => { const datastore = CourierInboxDatastore.shared; setInbox({ load: loadInbox, fetchNextPageOfMessages, setPaginationLimit, readMessage, unreadMessage, clickMessage: clickMessage2, archiveMessage: archiveMessage2, openMessage: openMessage2, unarchiveMessage, readAllMessages, inbox: datastore.inboxDataSet, archive: datastore.archiveDataSet, unreadCount: datastore.unreadCount, error }); }; return { shared: Courier.shared, auth, inbox }; }; const CourierClientComponent = ({ children }) => { const [isMounted, setIsMounted] = useState(false); useEffect(() => { setIsMounted(true); }, []); if (typeof window === "undefined") { return null; } if (!isMounted) { return null; } return /* @__PURE__ */ jsx(Fragment, { children }); }; const CourierRenderContext = createContext(null); const CourierInboxComponent = forwardRef((props, ref) => { const render = useContext(CourierRenderContext); if (!render) { throw new Error("RenderContext not found. Ensure CourierInbox is wrapped in a CourierRenderContext."); } const inboxRef = useRef(null); function handleRef(el) { if (ref) { if (typeof ref === "function") { ref(el); } else { ref.current = el; } } inboxRef.current = el; } function getEl() { return inboxRef.current; } useEffect(() => { const inbox = getEl(); if (!inbox) return; inbox.onMessageClick(props.onMessageClick); }, [props.onMessageClick]); useEffect(() => { const inbox = getEl(); if (!inbox) return; inbox.onMessageActionClick(props.onMessageActionClick); }, [props.onMessageActionClick]); useEffect(() => { const inbox = getEl(); if (!inbox) return; inbox.onMessageLongPress(props.onMessageLongPress); }, [props.onMessageLongPress]); useEffect(() => { const inbox = getEl(); if (!inbox || !props.renderHeader) return; queueMicrotask(() => { inbox.setHeader((headerProps) => { const reactNode = props.renderHeader(headerProps); return render(reactNode); }); }); }, [props.renderHeader]); useEffect(() => { const inbox = getEl(); if (!inbox || !props.renderListItem) return; queueMicrotask(() => { inbox.setListItem((itemProps) => { const reactNode = props.renderListItem(itemProps); return render(reactNode); }); }); }, [props.renderListItem]); useEffect(() => { const inbox = getEl(); if (!inbox || !props.renderEmptyState) return; queueMicrotask(() => { inbox.setEmptyState((emptyStateProps) => { const reactNode = props.renderEmptyState(emptyStateProps); return render(reactNode); }); }); }, [props.renderEmptyState]); useEffect(() => { const inbox = getEl(); if (!inbox || !props.renderLoadingState) return; queueMicrotask(() => { inbox.setLoadingState((loadingStateProps) => { const reactNode = props.renderLoadingState(loadingStateProps); return render(reactNode); }); }); }, [props.renderLoadingState]); useEffect(() => { const inbox = getEl(); if (!inbox || !props.renderErrorState) return; queueMicrotask(() => { inbox.setErrorState((errorStateProps) => { const reactNode = props.renderErrorState(errorStateProps); return render(reactNode); }); }); }, [props.renderErrorState]); useEffect(() => { const inbox = getEl(); if (!inbox || !props.renderPaginationItem) return; queueMicrotask(() => { inbox.setPaginationItem((paginationProps) => { const reactNode = props.renderPaginationItem(paginationProps); return render(reactNode); }); }); }, [props.renderPaginationItem]); useEffect(() => { const inbox = getEl(); if (!inbox) return; queueMicrotask(() => { inbox.setFeedType(props.feedType || "inbox"); }); }, [props.feedType]); const children = ( /* @ts-ignore */ /* @__PURE__ */ jsx( "courier-inbox", { ref: handleRef, height: props.height, "light-theme": props.lightTheme ? JSON.stringify(props.lightTheme) : void 0, "dark-theme": props.darkTheme ? JSON.stringify(props.darkTheme) : void 0, mode: props.mode } ) ); return /* @__PURE__ */ jsx(CourierClientComponent, { children }); }); const CourierInboxPopupMenuComponent = forwardRef( (props, ref) => { const render = useContext(CourierRenderContext); if (!render) { throw new Error("RenderContext not found. Ensure CourierInboxPopupMenu is wrapped in a CourierRenderContext."); } const inboxRef = useRef(null); function handleRef(el) { if (ref) { if (typeof ref === "function") { ref(el); } else { ref.current = el; } } inboxRef.current = el; } function getEl() { return inboxRef.current; } const lastFeedTypeRef = useRef(void 0); useEffect(() => { const menu = getEl(); if (!menu) return; if (props.feedType !== lastFeedTypeRef.current) { lastFeedTypeRef.current = props.feedType; queueMicrotask(() => { var _a; (_a = menu.setFeedType) == null ? void 0 : _a.call(menu, props.feedType ?? "inbox"); }); } }, [props.feedType]); useEffect(() => { const menu = getEl(); if (!menu) return; menu.onMessageClick(props.onMessageClick); }, [props.onMessageClick]); useEffect(() => { const menu = getEl(); if (!menu) return; menu.onMessageActionClick(props.onMessageActionClick); }, [props.onMessageActionClick]); useEffect(() => { const menu = getEl(); if (!menu) return; menu.onMessageLongPress(props.onMessageLongPress); }, [props.onMessageLongPress]); useEffect(() => { const menu = getEl(); if (!menu || !props.renderHeader) return; queueMicrotask(() => { menu.setHeader((headerProps) => { const reactNode = props.renderHeader(headerProps); return render(reactNode); }); }); }, [props.renderHeader]); useEffect(() => { const menu = getEl(); if (!menu || !props.renderListItem) return; queueMicrotask(() => { menu.setListItem((itemProps) => { const reactNode = props.renderListItem(itemProps); return render(reactNode); }); }); }, [props.renderListItem]); useEffect(() => { const menu = getEl(); if (!menu || !props.renderEmptyState) return; queueMicrotask(() => { menu.setEmptyState((emptyStateProps) => { const reactNode = props.renderEmptyState(emptyStateProps); return render(reactNode); }); }); }, [props.renderEmptyState]); useEffect(() => { const menu = getEl(); if (!menu || !props.renderLoadingState) return; queueMicrotask(() => { menu.setLoadingState((loadingStateProps) => { const reactNode = props.renderLoadingState(loadingStateProps); return render(reactNode); }); }); }, [props.renderLoadingState]); useEffect(() => { const menu = getEl(); if (!menu || !props.renderErrorState) return; queueMicrotask(() => { menu.setErrorState((errorStateProps) => { const reactNode = props.renderErrorState(errorStateProps); return render(reactNode); }); }); }, [props.renderErrorState]); useEffect(() => { const menu = getEl(); if (!menu || !props.renderPaginationItem) return; queueMicrotask(() => { menu.setPaginationItem((paginationProps) => { const reactNode = props.renderPaginationItem(paginationProps); return render(reactNode); }); }); }, [props.renderPaginationItem]); useEffect(() => { const menu = getEl(); if (!menu || !props.renderMenuButton) return; queueMicrotask(() => { menu.setMenuButton((buttonProps) => { const reactNode = props.renderMenuButton(buttonProps); return render(reactNode); }); }); }, [props.renderMenuButton]); const children = ( /* @ts-ignore */ /* @__PURE__ */ jsx( "courier-inbox-popup-menu", { ref: handleRef, "popup-alignment": props.popupAlignment, "popup-width": props.popupWidth, "popup-height": props.popupHeight, left: props.left, top: props.top, right: props.right, bottom: props.bottom, "light-theme": props.lightTheme ? JSON.stringify(props.lightTheme) : void 0, "dark-theme": props.darkTheme ? JSON.stringify(props.darkTheme) : void 0, mode: props.mode } ) ); return /* @__PURE__ */ jsx(CourierClientComponent, { children }); } ); function reactNodeToHTMLElement(node) { const container = document.createElement("div"); const root = createRoot(container); flushSync(() => { root.render(node); }); const element = container.firstElementChild; if (!(element instanceof HTMLElement)) { throw new Error( "renderListItem must return a single JSX element that renders to an HTMLElement (e.g., <div>)" ); } return element; } const CourierInbox = forwardRef((props, ref) => { return /* @__PURE__ */ jsx(CourierRenderContext.Provider, { value: reactNodeToHTMLElement, children: /* @__PURE__ */ jsx(CourierInboxComponent, { ...props, ref }) }); }); CourierInbox.displayName = "CourierInbox"; const CourierInboxPopupMenu = forwardRef((props, ref) => { return /* @__PURE__ */ jsx(CourierRenderContext.Provider, { value: reactNodeToHTMLElement, children: /* @__PURE__ */ jsx(CourierInboxPopupMenuComponent, { ...props, ref }) }); }); CourierInboxPopupMenu.displayName = "CourierInboxPopupMenu"; export { CourierInbox, CourierInboxPopupMenu, archiveMessage, clickMessage, defaultDarkTheme, defaultLightTheme, markAsRead, markAsUnread, mergeTheme, openMessage, useCourier }; //# sourceMappingURL=index.mjs.map