[Update] Main Page: Add feature that the sent message be editable and resend-able from logs.

This commit is contained in:
Sakamoto Shiina
2024-11-27 20:36:50 +09:00
parent 3a360fcbf0
commit 2d5d148f17
8 changed files with 209 additions and 22 deletions

View File

@@ -1,9 +1,42 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import clsx from "clsx";
import styles from "./MessageContainer.module.scss";
import { MessageSubMenuContainer } from "./message_sub_menu_container/MessageSubMenuContainer";
import { useMessage } from "@logics_common";
export const MessageContainer = ({ messages, status, category, created_at }) => {
const { t } = useTranslation();
const {
sendMessage,
updateMessageInputValue,
} = useMessage();
const [is_hovered, setIsHovered] = useState(false);
const [is_locked, setIsLocked] = useState(false);
const resendFunction = () => {
sendMessage(messages.original);
};
const editFunction = () => {
updateMessageInputValue(messages.original);
};
const handleMouseEnter = () => {
if (!is_locked) {
setIsHovered(true);
}
};
const handleMouseLeave = () => {
setIsHovered(false);
setIsLocked(false);
};
const lockHoverState = () => {
setIsHovered(false);
setIsLocked(true);
};
const is_translated_exist = messages.translated.length >= 1;
const is_pending = status === "pending";
@@ -16,18 +49,31 @@ export const MessageContainer = ({ messages, status, category, created_at }) =>
});
return (
<div className={clsx(styles.container, message_type_class_name)}>
<div className={clsx(styles.info_box, message_type_class_name)}>
<p className={styles.time}>{created_at}</p>
<p className={clsx(styles.category, message_type_class_name)}>{category_text}</p>
{is_sent_message && is_pending && <span className={styles.loader}></span>}
</div>
<div className={clsx(styles.message_box, message_type_class_name)}>
{is_translated_exist
? <WithTranslatedMessages messages={messages} />
: <p className={styles.message_main}>{messages.original}</p>
}
<div
className={clsx(styles.container, message_type_class_name)}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<div className={clsx(styles.message_wrapper, message_type_class_name)}>
<div className={clsx(styles.info_box, message_type_class_name)}>
<p className={styles.time}>{created_at}</p>
<p className={clsx(styles.category, message_type_class_name)}>{category_text}</p>
{is_sent_message && is_pending && <span className={styles.loader}></span>}
</div>
<div className={clsx(styles.message_box, message_type_class_name)}>
{is_translated_exist
? <WithTranslatedMessages messages={messages} />
: <p className={styles.message_main}>{messages.original}</p>
}
</div>
</div>
{is_sent_message && is_hovered ? (
<MessageSubMenuContainer
setIsHovered={lockHoverState}
resendFunction={resendFunction}
editFunction={editFunction}
/>
) : null}
</div>
);
};

View File

@@ -1,12 +1,26 @@
@import "@scss_mixins";
// ******************* *******************
// ******************* Express in "em" not "rem" *******************
// ******************* *******************
.container {
margin-bottom: 1em;
width: 100%;
display: flex;
user-select: text;
gap: 0.6rem;
&.sent_message:hover {
background-color: var(--dark_950_color);
}
}
.message_wrapper {
display: flex;
width: 100%;
flex-direction: column;
display: flex;
justify-content: center;
align-items: end;
user-select: text;
padding: 0.6em 0;
&.sent_message {
align-items: end;
}

View File

@@ -0,0 +1,71 @@
import React, { useState, useRef } from "react";
import Tooltip, { tooltipClasses } from '@mui/material/Tooltip';
import styles from "./MessageSubMenuContainer.module.scss";
import SendMessageSvg from "@images/send_message.svg?react";
import RefreshSvg from "@images/refresh_2.svg?react";
export const MessageSubMenuContainer = (props) => {
const [is_holding, setIsHolding] = useState(false);
const progressRef = useRef(null);
const holdTimeout = useRef(null);
const startHold = () => {
setIsHolding(true);
if (progressRef.current) {
progressRef.current.style.transition = "width 500ms linear";
progressRef.current.style.width = "100%";
}
holdTimeout.current = setTimeout(() => {
props.resendFunction();
props.setIsHovered(false);
}, 500);
};
const cancelHold = () => {
setIsHolding(false);
if (progressRef.current) {
progressRef.current.style.transition = "none";
progressRef.current.style.width = "0%";
}
clearTimeout(holdTimeout.current);
};
const onClickFunction = () => {
props.editFunction();
};
const offset = {
popper: {
sx: {
[`&.${tooltipClasses.popper}[data-popper-placement*="top"] .${tooltipClasses.tooltip}`]: { marginBottom: "0.2em" },
}
}
};
return (
<div className={styles.container}>
<Tooltip
title={<Title_p />}
placement="top"
slotProps={offset}
>
<button
className={styles.resend_button}
onMouseDown={startHold}
onMouseUp={cancelHold}
onMouseLeave={cancelHold}
onClick={onClickFunction}
>
<SendMessageSvg className={styles.send_message_svg} />
<RefreshSvg className={styles.refresh_svg} />
<div ref={progressRef} className={styles.hold_progress_bar}></div>
</button>
</Tooltip>
</div>
);
};
const Title_p = () => {
return <p className={styles.tooltip_title}>Press and hold to send</p>;
};

View File

@@ -0,0 +1,45 @@
// ******************* *******************
// ******************* Express in "em" not "rem" *******************
// ******************* *******************
.container {
}
.resend_button {
background-color: var(--dark_825_color);
position: relative;
height: 100%;
width: 3.8em;
}
.send_message_svg {
position: absolute;
top: 58%;
left: 50%;
transform: translate(-50%, -50%);
width: 2.2em;
color: var(--dark_400_color);
}
.refresh_svg {
position: absolute;
top: 36%;
left: 42%;
transform: translate(-50%, -50%);
width: 1.8em;
color: var(--sent_400_color);
filter: drop-shadow(0.2em 0.2em 0 var(--dark_825_color));
}
.tooltip_title {
font-size: 1.2rem;
color: var(--dark_basic_text_color);
}
.hold_progress_bar {
position: absolute;
top: 10%;
left: 50%;
transform: translate(-50%, -50%);
width: 0%;
height: 0.4em;
background-color: var(--sent_400_color);
transition: none;
}

View File

@@ -7,10 +7,14 @@ import { store } from "@store";
import { scrollToBottom } from "@utils";
export const MessageInputBox = () => {
const [input_value, setInputValue] = useState("");
const [message_history, setMessageHistory] = useState([]);
const [history_index, setHistoryIndex] = useState(-1);
const { sendMessage, currentMessageLogs } = useMessage();
const {
sendMessage,
currentMessageLogs,
currentMessageInputValue,
updateMessageInputValue,
} = useMessage();
const { currentEnableAutoClearMessageInputBox } = useEnableAutoClearMessageInputBox();
const { currentSendMessageButtonType } = useSendMessageButtonType();
@@ -27,11 +31,11 @@ export const MessageInputBox = () => {
const onSubmitFunction = (e) => {
e.preventDefault();
if (!input_value.trim()) return setInputValue("");
if (!currentMessageInputValue.data.trim()) return updateMessageInputValue("");
sendMessage(input_value);
sendMessage(currentMessageInputValue.data);
if (currentEnableAutoClearMessageInputBox.data) setInputValue("");
if (currentEnableAutoClearMessageInputBox.data) updateMessageInputValue("");
setTimeout(() => {
scrollToBottom(store.log_box_ref);
@@ -41,7 +45,7 @@ export const MessageInputBox = () => {
};
const onChangeFunction = (e) => {
setInputValue(e.currentTarget.value);
updateMessageInputValue(e.currentTarget.value);
};
const onKeyDownFunction = (e) => {
@@ -57,7 +61,7 @@ export const MessageInputBox = () => {
if (history_index + 1 < message_history.length) {
const new_index = history_index + 1;
setHistoryIndex(new_index);
setInputValue(message_history[message_history.length - 1 - new_index]);
updateMessageInputValue(message_history[message_history.length - 1 - new_index]);
}
}
@@ -83,7 +87,7 @@ export const MessageInputBox = () => {
className={styles.message_box_input_area}
onChange={onChangeFunction}
placeholder="Input Textfield"
value={input_value}
value={currentMessageInputValue.data}
onKeyDown={onKeyDownFunction}
/>
</div>