Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/improsocial/impro
An extensible Bluesky client for web impro.social
Something went wrong. Try again.
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258import { pageEffect, bindPageTitle, onPageShow } from "/js/router.js";import { html, render } from "/js/lib/lit-html.js";import { headerTemplate } from "/js/templates/header.template.js";import { displayRelativeTime } from "/js/utils.js";import { getConvoPreviewText, getDisplayName, getGroupConvoDetails, getGroupConvoOwner, MISSING_HANDLE,} from "/js/dataHelpers.js";import { avatarTemplate } from "/js/templates/avatar.template.js";import { avatarGroupTemplate } from "/js/templates/avatarGroup.template.js";import { knownFollowersSummaryTemplate } from "/js/templates/knownFollowersSummary.template.js";import { showToast } from "/js/toasts.js";import "/js/components/container-link.js";import "/js/components/infinite-scroll-container.js";import { tryAgainButtonTemplate } from "/js/templates/tryAgainButton.template.js";
export default async function chatRequestsView({ root, router, layout, context: { auth, dataLayer },}) { await auth.requireAuth();
async function handleAccept(convo) { try { await dataLayer.mutations.acceptConvo(convo); // on accept, navigate to the chat detail page window.router.go(`/messages/${convo.id}`); } catch (error) { console.error(error); showToast("Failed to accept chat request", { style: "error" }); } }
async function handleReject(convo) { try { await dataLayer.mutations.rejectConvo(convo); } catch (error) { console.error(error); showToast("Failed to reject chat request", { style: "error" }); } }
function requestItemTemplate({ convo }) { const groupDetails = getGroupConvoDetails(convo); const currentUser = dataLayer.derived.$currentUser.get(); const lastMessage = convo.lastMessage; const otherMembers = convo.members.filter( (member) => member.did !== currentUser?.did, ); const otherMember = groupDetails ? null : otherMembers[0]; const timeAgo = lastMessage ? displayRelativeTime(lastMessage.sentAt) : ""; const messagePreview = lastMessage ? getConvoPreviewText(lastMessage, { currentUser, convo, profiles: dataLayer.derived.$convoProfiles.get(convo.id), }) : "No messages yet"; const canAccept = !groupDetails || groupDetails.lockStatus === "unlocked";
return html` <div class="chat-request-item" data-testid=${groupDetails ? "request-item-group" : "request-item-direct"} > <container-link class="chat-request-header" href=${`/messages/${convo.id}`} > <div class="convo-avatar"> ${(() => { if (groupDetails) { return avatarGroupTemplate({ authors: otherMembers }); } return otherMember ? avatarTemplate({ author: otherMember }) : html`<div class="avatar-placeholder"></div>`; })()} </div> <div class="convo-content"> <div class="convo-header"> <div class="convo-name"> ${groupDetails ? groupDetails.name : getDisplayName(otherMember)} </div> ${timeAgo ? html`<div class="convo-time">${timeAgo}</div>` : ""} </div> <div class="convo-handle"> ${!groupDetails && otherMember?.handle && otherMember?.handle !== MISSING_HANDLE ? `@${otherMember.handle}` : ""} </div> <div class="convo-preview">${messagePreview}</div> ${(() => { if (!groupDetails) { return html`<div class="chat-request-follow-status"> ${knownFollowersSummaryTemplate({ profile: otherMember, showPlaceholder: true, })} </div>`; } const groupOwner = getGroupConvoOwner(convo); return groupOwner ? html`<div class="chat-request-follow-status" data-testid="request-invited-by" > ${getDisplayName(groupOwner)} added you </div>` : ""; })()} </div> </container-link> <div class="chat-request-actions"> ${canAccept ? html`<button class="chat-request-button accept" @click=${(e) => { e.stopPropagation(); handleAccept(convo); }} > Accept </button>` : ""} <button class="chat-request-button reject" @click=${(e) => { e.stopPropagation(); handleReject(convo); }} > Reject </button> </div> </div> `; }
function requestSkeletonTemplate() { return html` ${Array.from({ length: 3 }).map( () => html` <div class="chat-request-item skeleton"> <div class="chat-request-header"> <div class="convo-avatar"> <div class="convo-skeleton-avatar skeleton-animate"></div> </div> <div class="convo-content"> <div class="convo-header"> <div class="convo-skeleton-name skeleton-animate"></div> <div class="convo-skeleton-time skeleton-animate"></div> </div> <div class="convo-skeleton-handle skeleton-animate"></div> <div class="convo-skeleton-preview skeleton-animate"></div> </div> </div> <div class="chat-request-actions"> <div class="chat-request-skeleton-button skeleton-animate"></div> <div class="chat-request-skeleton-button skeleton-animate"></div> </div> </div> `, )} `; }
function requestsTemplate({ requests, hasMore }) { if (requests.length === 0) { return html`<div class="feed-end-message"> <div>No chat requests</div> </div>`; }
return html` <infinite-scroll-container @load-more=${async (e) => { if (hasMore) { await dataLayer.requests.loadConvoRequestList(); e.detail.resume(); } }} > <div class="chat-requests-list"> ${requests.map((convo) => requestItemTemplate({ convo }))} ${hasMore ? requestSkeletonTemplate() : ""} </div> </infinite-scroll-container> `; }
function requestsErrorTemplate({ error }) { console.error(error); return html`<div class="error-state"> <div>There was an error loading chat requests.</div> ${tryAgainButtonTemplate()} </div>`; }
bindPageTitle(root, () => "Chat request inbox");
pageEffect(root, () => { const chatRequests = dataLayer.derived.$convoRequestList.get(); const requestsStatus = dataLayer.requests.statusStore.$statuses.get( "loadConvoRequestList", ); const cursor = dataLayer.derived.$convoRequestListCursor.get(); const hasMore = !!cursor;
render( html`<div id="chat-requests-view"> ${headerTemplate({ title: "Chat requests", showLoadingSpinner: requestsStatus.loading && !!chatRequests, backButtonFallbackRoute: "/messages", })} <main class="chat-requests-main"> ${(() => { if (requestsStatus.error) { return requestsErrorTemplate({ error: requestsStatus.error, }); } else if (chatRequests) { return requestsTemplate({ requests: chatRequests, hasMore, }); } else { return requestSkeletonTemplate(); } })()} </main> </div>`, root, ); });
function loadPageData() { dataLayer.requests.loadConvoRequestList({ reload: true }); }
onPageShow(root, ({ action }) => { if (action === "restore") return; loadPageData(); });}