add top-of-channel message

This commit is contained in:
Michael Peters 2023-01-14 15:03:16 -08:00
parent ce13fe1c80
commit 72b0b0004d
6 changed files with 43 additions and 20 deletions

View File

@ -6,7 +6,7 @@ CorDis is a text and voice chat client with UI based on Discord.
[Server Screenshot](data/server.png)
## Build / Run
## Build
Install Node Dependencies

View File

@ -51,7 +51,7 @@ create-example-roles:
node ./dist/server/scripts/example-roles.js
create-memes-messages:
node ./dist/server/scripts/insert-2000-memes-messages.js
node ./dist/server/scripts/insert-500-memes-messages.js
full-reset: clean build move reset-server create-invite

View File

@ -72,6 +72,22 @@ $borderRadius: 8px;
padding: 4px 8px;
}
}
.top-of-feed {
margin: 8px 16px;
text-align: center;
.welcome {
color: theme.$header-primary;
font-size: 1.4em;
font-weight: 600;
}
.start {
color: theme.$header-secondary;
font-size: 0.9em;
}
}
}
}
}

View File

@ -7,6 +7,7 @@ import Retry from './retry';
export interface InfiniteScrollRecoilProps<T, E> {
infiniteScrollRef: MutableRefObject<HTMLDivElement | null>;
scrollable: LoadableValueScrolling<T, E>;
topElement: ReactNode;
initialErrorMessage: string; // for if there was a problem loading the initial messages
aboveErrorMessage: string; // for if there was a problem loading messages above the list
belowErrorMessage: string; // for if there was a problem loading messages below the list
@ -17,6 +18,7 @@ function InfiniteScrollRecoil<T>(props: InfiniteScrollRecoilProps<T[], T>) {
const {
infiniteScrollRef,
scrollable,
topElement,
initialErrorMessage,
aboveErrorMessage,
belowErrorMessage,
@ -56,6 +58,7 @@ function InfiniteScrollRecoil<T>(props: InfiniteScrollRecoilProps<T[], T>) {
<div>
<div ref={infiniteScrollRef} className="infinite-scroll-scroll-base" onScroll={onScrollCallable}>
<div className="infinite-scroll-elements">
{scrollable.above?.hasMore === false && topElement}
<Retry error={scrollable.above?.error} text={aboveErrorMessage} retryFunc={fetchAboveCallable} />
{children}
<Retry error={scrollable.below?.error} text={belowErrorMessage} retryFunc={fetchBelowCallable} />

View File

@ -6,7 +6,12 @@ const LOG = Logger.create(__filename, electronConsole);
import React, { FC, useEffect, useMemo, useRef } from 'react';
import { Message } from '../../data-types';
import MessageElement from './components/message-element';
import { currGuildActiveChannelMessagesState, currGuildSelfMemberState, currGuildState } from '../require/atoms';
import {
currGuildActiveChannelMessagesState,
currGuildActiveChannelState,
currGuildSelfMemberState,
currGuildState,
} from '../require/atoms';
import { useRecoilValue } from 'recoil';
import { isLoaded } from '../require/loadables';
import InfiniteScrollRecoil from '../components/infinite-scroll';
@ -15,25 +20,13 @@ const MessageList: FC = () => {
const infiniteScrollElementRef = useRef<HTMLDivElement>(null);
const guild = useRecoilValue(currGuildState);
const channel = useRecoilValue(currGuildActiveChannelState);
const messages = useRecoilValue(currGuildActiveChannelMessagesState);
const selfMember = useRecoilValue(currGuildSelfMemberState);
// TODO: Show loading indicators if above/below are pending
// TODO: Show nicer retry buttons (and test the retry buttons)
// leaving this in for debugging purposes
// useEffect(() => {
// if (isUnload(messages)) {
// lOG.debug('recoilMessages unloaded');
// } else if (isPended(messages)) {
// lOG.debug('recoilMessages pended');
// } else if (isLoaded(messages)) {
// lOG.debug('recoilMessages loaded. length: ' + messages.value.length);
// } else if (isFailed(messages)) {
// lOG.debug('recoilMessages failed');
// }
// }, [messages]);
useEffect(() => {
if (guild === null) return;
const onMessages = (messages: Message[]) => {
@ -71,11 +64,22 @@ const MessageList: FC = () => {
return result;
}, [guild, messages]);
const topOfFeedElement = useMemo(() => {
if (!isLoaded(channel)) return null; // TODO: placeholder/loading message instead
return (
<div className="top-of-feed">
<div className="welcome">Welcome to #{channel.value.name}</div>
<div className="start">This is the start of #{channel.value.name}</div>
</div>
);
}, [channel]);
return (
<div className="message-list">
<InfiniteScrollRecoil
infiniteScrollRef={infiniteScrollElementRef}
scrollable={messages}
topElement={topOfFeedElement}
initialErrorMessage="Unable to retrieve recent messages"
aboveErrorMessage="Unable to retrieve messages above"
belowErrorMessage="Unable to retrieve messages below"

View File

@ -16,13 +16,13 @@ process.on('unhandledRejection', async (reason, _promise) => {
const targetGuild = guilds.find(guild => guild.name === 'no chicoms');
const members = await DB.getMembers(targetGuild.id);
const targetMember = members.find(member => member.display_name === 'Elipzer');
if (targetMember === undefined) {
LOG.error('unable to find target member');
}
if (targetMember === undefined) {
LOG.error('unable to find target member');
}
const channels = await DB.getChannels(targetGuild.id);
const targetChannel = channels.find(channel => channel.name === 'memes');
LOG.debug('inserting testing messages...');
for (let i = 0; i < 2000; ++i) {
for (let i = 0; i < 500; ++i) {
await DB.insertMessage(targetGuild.id, targetChannel.id, targetMember.id, 'Test Message #' + i);
}
LOG.info('inserted testing messages');