forked from MarseyWorld/MarseyWorld
Don't allow multiple sets of actions open
parent
fbcd2e9f74
commit
249d510f23
|
@ -1,10 +1,11 @@
|
|||
{
|
||||
"name": "chat",
|
||||
"version": "0.0.24",
|
||||
"version": "0.1.0",
|
||||
"main": "./src/index.tsx",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/humanize-duration": "^3.27.1",
|
||||
"@types/lodash.clonedeep": "^4.5.7",
|
||||
"@types/lodash.debounce": "^4.0.7",
|
||||
"@types/lozad": "^1.16.1",
|
||||
"@types/react": "^18.0.20",
|
||||
|
@ -15,6 +16,7 @@
|
|||
"dotenv": "^16.0.2",
|
||||
"esbuild": "^0.15.7",
|
||||
"humanize-duration": "^3.27.3",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"lozad": "^1.16.0",
|
||||
"react": "^18.2.0",
|
||||
|
|
|
@ -18,14 +18,6 @@
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
.ChatMessage__showingUser:not(:first-child) {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.ChatMessage:not(.ChatMessage__showingUser) {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.ChatMessage .btn {
|
||||
border: none !important;
|
||||
}
|
||||
|
@ -102,4 +94,14 @@
|
|||
.ChatMessageList {
|
||||
flex: 1;
|
||||
padding-bottom: 2rem;
|
||||
}
|
||||
|
||||
.ChatMessageList-group {
|
||||
margin-bottom: 1rem;
|
||||
padding: 0.3rem;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.ChatMessageList-group:nth-child(even) {
|
||||
background: rgba(255, 255, 255, 0.025);
|
||||
}
|
|
@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useMemo, useState } from "react";
|
|||
import cx from "classnames";
|
||||
import key from "weak-key";
|
||||
import humanizeDuration from "humanize-duration";
|
||||
import cloneDeep from "lodash.clonedeep";
|
||||
import { Username } from "./Username";
|
||||
import { useChat, useRootContext } from "../../hooks";
|
||||
import { QuotedMessageLink } from "./QuotedMessageLink";
|
||||
|
@ -11,6 +12,8 @@ interface ChatMessageProps {
|
|||
message: IChatMessage;
|
||||
timestampUpdates: number;
|
||||
showUser?: boolean;
|
||||
actionsOpen: boolean;
|
||||
onToggleActions(messageId: string): void;
|
||||
}
|
||||
|
||||
const TIMESTAMP_UPDATE_INTERVAL = 20000;
|
||||
|
@ -19,6 +22,8 @@ export function ChatMessage({
|
|||
message,
|
||||
showUser = true,
|
||||
timestampUpdates,
|
||||
actionsOpen,
|
||||
onToggleActions
|
||||
}: ChatMessageProps) {
|
||||
const {
|
||||
id,
|
||||
|
@ -36,7 +41,6 @@ export function ChatMessage({
|
|||
const { messageLookup, deleteMessage, quoteMessage } = useChat();
|
||||
const quotedMessage = messageLookup[quotes];
|
||||
const content = censored ? text_censored : text_html;
|
||||
const [showingActions, setShowingActions] = useState(false);
|
||||
const [confirmedDelete, setConfirmedDelete] = useState(false);
|
||||
const timestamp = useMemo(
|
||||
() => formatTimeAgo(time),
|
||||
|
@ -49,20 +53,16 @@ export function ChatMessage({
|
|||
setConfirmedDelete(true);
|
||||
}
|
||||
}, [text, confirmedDelete]);
|
||||
const toggleMessageActions = useCallback(
|
||||
() => setShowingActions((prev) => !prev),
|
||||
[]
|
||||
);
|
||||
const handleQuoteMessage = useCallback(() => {
|
||||
quoteMessage(message);
|
||||
setShowingActions(false);
|
||||
}, [message]);
|
||||
onToggleActions(message.id);
|
||||
}, [message, onToggleActions]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!showingActions) {
|
||||
if (!actionsOpen) {
|
||||
setConfirmedDelete(false);
|
||||
}
|
||||
}, [showingActions]);
|
||||
}, [actionsOpen]);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
@ -71,15 +71,15 @@ export function ChatMessage({
|
|||
})}
|
||||
id={id}
|
||||
>
|
||||
{!showingActions && (
|
||||
{!actionsOpen && (
|
||||
<button
|
||||
className="btn btn-secondary ChatMessage-actions-button"
|
||||
onClick={toggleMessageActions}
|
||||
onClick={() => onToggleActions(id)}
|
||||
>
|
||||
...
|
||||
</button>
|
||||
)}
|
||||
{showingActions && (
|
||||
{actionsOpen && (
|
||||
<div className="ChatMessage-actions">
|
||||
<button
|
||||
className="btn btn-secondary ChatMessage-button"
|
||||
|
@ -100,7 +100,7 @@ export function ChatMessage({
|
|||
)}
|
||||
<button
|
||||
className="btn btn-secondary ChatMessage-button"
|
||||
onClick={toggleMessageActions}
|
||||
onClick={() => onToggleActions(id)}
|
||||
>
|
||||
<i>X</i> Close
|
||||
</button>
|
||||
|
@ -136,6 +136,17 @@ export function ChatMessage({
|
|||
export function ChatMessageList() {
|
||||
const { messages } = useChat();
|
||||
const [timestampUpdates, setTimestampUpdates] = useState(0);
|
||||
const groupedMessages = useMemo(() => groupMessages(messages), [messages]);
|
||||
const [actionsOpenForMessage, setActionsOpenForMessage] = useState<
|
||||
string | null
|
||||
>(null);
|
||||
const handleToggleActionsForMessage = useCallback(
|
||||
(messageId: string) =>
|
||||
setActionsOpenForMessage(
|
||||
messageId === actionsOpenForMessage ? null : messageId
|
||||
),
|
||||
[actionsOpenForMessage]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const updatingTimestamps = setInterval(
|
||||
|
@ -150,13 +161,19 @@ export function ChatMessageList() {
|
|||
|
||||
return (
|
||||
<div className="ChatMessageList">
|
||||
{messages.map((message, index) => (
|
||||
<ChatMessage
|
||||
key={key(message)}
|
||||
message={message}
|
||||
timestampUpdates={timestampUpdates}
|
||||
showUser={message.username !== messages[index - 1]?.username}
|
||||
/>
|
||||
{groupedMessages.map((group) => (
|
||||
<div key={key(group)} className="ChatMessageList-group">
|
||||
{group.map((message, index) => (
|
||||
<ChatMessage
|
||||
key={key(message)}
|
||||
message={message}
|
||||
timestampUpdates={timestampUpdates}
|
||||
showUser={index === 0}
|
||||
actionsOpen={actionsOpenForMessage === message.id}
|
||||
onToggleActions={handleToggleActionsForMessage}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
@ -188,3 +205,29 @@ function formatTimeAgo(time: number) {
|
|||
|
||||
return humanized === "0s ago" ? "just now" : humanized;
|
||||
}
|
||||
|
||||
function groupMessages(messages: IChatMessage[]) {
|
||||
const grouped: IChatMessage[][] = [];
|
||||
let lastUsername = "";
|
||||
let temp: IChatMessage[] = [];
|
||||
|
||||
for (const message of messages) {
|
||||
if (!lastUsername) {
|
||||
lastUsername = message.username;
|
||||
}
|
||||
|
||||
if (message.username === lastUsername) {
|
||||
temp.push(message);
|
||||
} else {
|
||||
grouped.push(cloneDeep(temp));
|
||||
lastUsername = message.username;
|
||||
temp = [message];
|
||||
}
|
||||
}
|
||||
|
||||
if (temp.length > 0) {
|
||||
grouped.push(cloneDeep(temp));
|
||||
}
|
||||
|
||||
return grouped;
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ export function QuotedMessageLink({ message }: { message: IChatMessage }) {
|
|||
|
||||
return (
|
||||
<a className="QuotedMessageLink" href="#" onClick={handleLinkClick}>
|
||||
Replying to @{message.username}:{" "}
|
||||
<i className="fas fa-reply" /> @{message.username}:{" "}
|
||||
<em>"{replyText}"</em>
|
||||
</a>
|
||||
);
|
||||
|
|
|
@ -39,6 +39,13 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/humanize-duration/-/humanize-duration-3.27.1.tgz#f14740d1f585a0a8e3f46359b62fda8b0eaa31e7"
|
||||
integrity sha512-K3e+NZlpCKd6Bd/EIdqjFJRFHbrq5TzPPLwREk5Iv/YoIjQrs6ljdAUCo+Lb2xFlGNOjGSE0dqsVD19cZL137w==
|
||||
|
||||
"@types/lodash.clonedeep@^4.5.7":
|
||||
version "4.5.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash.clonedeep/-/lodash.clonedeep-4.5.7.tgz#0e119f582ed6f9e6b373c04a644651763214f197"
|
||||
integrity sha512-ccNqkPptFIXrpVqUECi60/DFxjNKsfoQxSQsgcBJCX/fuX1wgyQieojkcWH/KpE3xzLoWN/2k+ZeGqIN3paSvw==
|
||||
dependencies:
|
||||
"@types/lodash" "*"
|
||||
|
||||
"@types/lodash.debounce@^4.0.7":
|
||||
version "4.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash.debounce/-/lodash.debounce-4.0.7.tgz#0285879defb7cdb156ae633cecd62d5680eded9f"
|
||||
|
@ -390,6 +397,11 @@ inherits@2:
|
|||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
|
||||
|
||||
lodash.clonedeep@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
|
||||
integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==
|
||||
|
||||
lodash.debounce@^4.0.8:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
|
||||
|
|
Loading…
Reference in New Issue