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) [Server Screenshot](data/server.png)
## Build / Run ## Build
Install Node Dependencies Install Node Dependencies

View File

@ -51,7 +51,7 @@ create-example-roles:
node ./dist/server/scripts/example-roles.js node ./dist/server/scripts/example-roles.js
create-memes-messages: 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 full-reset: clean build move reset-server create-invite

View File

@ -72,6 +72,22 @@ $borderRadius: 8px;
padding: 4px 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> { export interface InfiniteScrollRecoilProps<T, E> {
infiniteScrollRef: MutableRefObject<HTMLDivElement | null>; infiniteScrollRef: MutableRefObject<HTMLDivElement | null>;
scrollable: LoadableValueScrolling<T, E>; scrollable: LoadableValueScrolling<T, E>;
topElement: ReactNode;
initialErrorMessage: string; // for if there was a problem loading the initial messages 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 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 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 { const {
infiniteScrollRef, infiniteScrollRef,
scrollable, scrollable,
topElement,
initialErrorMessage, initialErrorMessage,
aboveErrorMessage, aboveErrorMessage,
belowErrorMessage, belowErrorMessage,
@ -56,6 +58,7 @@ function InfiniteScrollRecoil<T>(props: InfiniteScrollRecoilProps<T[], T>) {
<div> <div>
<div ref={infiniteScrollRef} className="infinite-scroll-scroll-base" onScroll={onScrollCallable}> <div ref={infiniteScrollRef} className="infinite-scroll-scroll-base" onScroll={onScrollCallable}>
<div className="infinite-scroll-elements"> <div className="infinite-scroll-elements">
{scrollable.above?.hasMore === false && topElement}
<Retry error={scrollable.above?.error} text={aboveErrorMessage} retryFunc={fetchAboveCallable} /> <Retry error={scrollable.above?.error} text={aboveErrorMessage} retryFunc={fetchAboveCallable} />
{children} {children}
<Retry error={scrollable.below?.error} text={belowErrorMessage} retryFunc={fetchBelowCallable} /> <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 React, { FC, useEffect, useMemo, useRef } from 'react';
import { Message } from '../../data-types'; import { Message } from '../../data-types';
import MessageElement from './components/message-element'; 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 { useRecoilValue } from 'recoil';
import { isLoaded } from '../require/loadables'; import { isLoaded } from '../require/loadables';
import InfiniteScrollRecoil from '../components/infinite-scroll'; import InfiniteScrollRecoil from '../components/infinite-scroll';
@ -15,25 +20,13 @@ const MessageList: FC = () => {
const infiniteScrollElementRef = useRef<HTMLDivElement>(null); const infiniteScrollElementRef = useRef<HTMLDivElement>(null);
const guild = useRecoilValue(currGuildState); const guild = useRecoilValue(currGuildState);
const channel = useRecoilValue(currGuildActiveChannelState);
const messages = useRecoilValue(currGuildActiveChannelMessagesState); const messages = useRecoilValue(currGuildActiveChannelMessagesState);
const selfMember = useRecoilValue(currGuildSelfMemberState); const selfMember = useRecoilValue(currGuildSelfMemberState);
// TODO: Show loading indicators if above/below are pending // TODO: Show loading indicators if above/below are pending
// TODO: Show nicer retry buttons (and test the retry buttons) // 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(() => { useEffect(() => {
if (guild === null) return; if (guild === null) return;
const onMessages = (messages: Message[]) => { const onMessages = (messages: Message[]) => {
@ -71,11 +64,22 @@ const MessageList: FC = () => {
return result; return result;
}, [guild, messages]); }, [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 ( return (
<div className="message-list"> <div className="message-list">
<InfiniteScrollRecoil <InfiniteScrollRecoil
infiniteScrollRef={infiniteScrollElementRef} infiniteScrollRef={infiniteScrollElementRef}
scrollable={messages} scrollable={messages}
topElement={topOfFeedElement}
initialErrorMessage="Unable to retrieve recent messages" initialErrorMessage="Unable to retrieve recent messages"
aboveErrorMessage="Unable to retrieve messages above" aboveErrorMessage="Unable to retrieve messages above"
belowErrorMessage="Unable to retrieve messages below" belowErrorMessage="Unable to retrieve messages below"

View File

@ -22,7 +22,7 @@ process.on('unhandledRejection', async (reason, _promise) => {
const channels = await DB.getChannels(targetGuild.id); const channels = await DB.getChannels(targetGuild.id);
const targetChannel = channels.find(channel => channel.name === 'memes'); const targetChannel = channels.find(channel => channel.name === 'memes');
LOG.debug('inserting testing messages...'); 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); await DB.insertMessage(targetGuild.id, targetChannel.id, targetMember.id, 'Test Message #' + i);
} }
LOG.info('inserted testing messages'); LOG.info('inserted testing messages');