feat: auto delete message logic

This commit is contained in:
Tristan Yang
2022-12-27 21:29:41 +08:00
parent 1e9665dab2
commit bd12aa0e4d
6 changed files with 105 additions and 19 deletions
@@ -0,0 +1,67 @@
import dayjs from 'dayjs';
import { FC, useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import { removeMessage } from '../../../app/slices/message';
import IconTimer from '../../../assets/icons/timer.svg';
type Props = {
mid: number;
expires_in: number;
create_at: number;
};
const ExpireTimer: FC<Props> = ({ mid, create_at, expires_in }) => {
const [countdown, setCountdown] = useState<number | undefined>();
const dispatch = useDispatch();
useEffect(() => {
if (expires_in > 0 && create_at > 0) {
const expire_time = create_at + expires_in * 1000;
if (dayjs().isAfter(new Date(expire_time))) {
// 已过期,立即删除
dispatch(removeMessage(mid));
// dispatch()
} else {
// 倒计时
setCountdown(Math.floor((expire_time - new Date().getTime()) / 1000));
}
}
}, [expires_in, create_at, mid]);
useEffect(() => {
let timer = 0;
if (typeof countdown !== "undefined") {
if (countdown > 0) {
timer = window.setTimeout(() => {
setCountdown(prev => {
const _prev = prev ?? 0;
return _prev - 1;
});
}, 1000);
} else {
// 倒计时结束
console.log("countdown over", mid, countdown);
dispatch(removeMessage(mid));
}
}
return () => {
if (typeof countdown !== "undefined") {
clearTimeout(timer);
}
};
}, [countdown, mid]);
if (!countdown) return null;
const duration = dayjs.duration(countdown * 1000);
const day = duration.days() !== 0 ? `${duration.days()} day` : "";
const hours = duration.hours() !== 0 ? `${duration.hours().toString().padStart(2, '0')}:` : "";
const minutes = duration.minutes() !== 0 ? `${duration.minutes().toString().padStart(2, '0')}:` : "";
const formatted_countdown = `${day} ${hours}${minutes}${duration.seconds().toString().padStart(2, '0')}`;
return (
<div className='absolute bottom-1 right-2 text-xs text-gray-400 flex items-center gap-1 font-mono'>
<IconTimer className="w-4 h-4 stroke-slate-400" />
{formatted_countdown}
</div>
);
};
export default ExpireTimer;
+28 -18
View File
@@ -16,6 +16,7 @@ import ContextMenu from "./ContextMenu";
import useContextMenu from "../../hook/useContextMenu";
import usePinMessage from "../../hook/usePinMessage";
import { useAppSelector } from "../../../app/store";
import ExpireTimer from "./ExpireTimer";
interface IProps {
readOnly?: boolean;
@@ -50,6 +51,19 @@ const Message: FC<IProps> = ({
setEdit((prev) => !prev);
};
useEffect(() => {
if (!read) {
// 标记已读
const data =
context == "user"
? { users: [{ uid: +contextId, mid }] }
: { groups: [{ gid: +contextId, mid }] };
if (updateReadIndex) {
updateReadIndex(data);
}
}
}, [mid, read]);
const {
reply_mid,
from_uid: fromUid,
@@ -60,20 +74,10 @@ const Message: FC<IProps> = ({
download,
content_type = "text/plain",
edited,
properties
properties,
expires_in = 0
} = message;
useEffect(() => {
if (!read) {
const data =
context == "user"
? { users: [{ uid: +contextId, mid }] }
: { groups: [{ gid: +contextId, mid }] };
if (updateReadIndex) {
updateReadIndex(data);
}
}
}, [mid, read]);
const reactions = reactionMessageData[mid];
const currUser = usersData[fromUid || 0];
@@ -85,15 +89,15 @@ const Message: FC<IProps> = ({
const pinInfo = getPinInfo(mid);
// return null;
const _key = properties?.local_id || mid;
const showExpire = (expires_in ?? 0) > 0;
return (
<StyledWrapper
key={_key}
onContextMenu={readOnly ? undefined : handleContextMenuEvent}
data-msg-mid={mid}
ref={inviewRef}
className={`message ${readOnly ? "readonly" : ""} ${pinInfo ? "pinned" : ""} ${
contextMenuVisible ? "contextVisible" : ""
} `}
className={`message ${readOnly ? "readonly" : ""} ${showExpire ? "auto_delete" : ""} ${pinInfo ? "pinned" : ""} ${contextMenuVisible ? "contextVisible" : ""
} `}
>
<Tippy
key={_key}
@@ -118,9 +122,8 @@ const Message: FC<IProps> = ({
>
<div
className="details"
data-pin-tip={`pinned by ${
pinInfo?.created_by ? usersData[pinInfo.created_by]?.name : ""
}`}
data-pin-tip={`pinned by ${pinInfo?.created_by ? usersData[pinInfo.created_by]?.name : ""
}`}
>
<div className="up">
<span className="name">{currUser?.name || "Deleted User"}</span>
@@ -160,6 +163,13 @@ const Message: FC<IProps> = ({
</div>
</ContextMenu>
{showExpire && (
<ExpireTimer
mid={message.mid}
expires_in={expires_in ?? 0}
create_at={time ?? 0}
/>
)}
{!edit && !readOnly && (
<Commands
context={context}
+3
View File
@@ -11,6 +11,9 @@ const StyledMsg = styled.div`
&[data-highlight="true"] {
background: #f5f6f7;
}
&.auto_delete {
background: #f1d1ca50;
}
&.pinned {
background: #ecfdff;
}