Files
ColdBreeze-chat-web/src/routes/chat/utils.tsx
T
2023-05-19 16:31:28 +08:00

185 lines
5.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React from "react";
import { useDispatch } from "react-redux";
import dayjs from "dayjs";
import { ContentTypes } from "@/app/config";
import { updateSelectMessages } from "@/app/slices/ui";
import { useAppSelector } from "@/app/store";
import { ChatContext } from "@/types/common";
import Divider from "@/components/Divider";
import LinkifyText from "@/components/LinkifyText";
import Message from "@/components/Message";
import Checkbox from "@/components/styled/Checkbox";
import { isImage } from "@/utils";
import i18n from "../../i18n";
export function getUnreadCount({
mids = [],
messageData = {},
loginUid = 0,
readIndex = 0
}: {
mids?: number[];
messageData: object;
loginUid: number;
readIndex: number;
}) {
// console.log({ mids, loginUid, readIndex });
// 先过滤掉空信息和from自己的
const others = mids.filter((mid) => {
const { from_uid = 0 } = messageData[mid] || {};
return messageData[mid] && from_uid != loginUid;
});
if (others.length == 0) return { unreads: 0 };
if (readIndex == 0) return { unreads: others.length };
// 再过滤掉小于read-index
const final = others.filter((mid) => {
return mid > readIndex;
});
// 拿at数量
const tmps: number[] = [];
final.forEach((mid) => {
const msg = messageData[mid];
const { mentions = [] } = msg.properties || {};
mentions.forEach((id: number) => {
if (id == loginUid) {
tmps.push(mid);
}
});
});
// console.log("unreads", final.length, tmps);
return { unreads: final.length, mentions: tmps };
}
export const renderPreviewMessage = (message = null) => {
if (!message) return null;
const { content_type, content, properties = {} } = message;
let res = null;
switch (content_type) {
case ContentTypes.text:
{
res = <LinkifyText text={content} url={false} mentionTextOnly={true} />;
}
break;
case ContentTypes.audio:
{
res = `[${i18n.t("voice_message", { ns: "chat" })}]`;
}
break;
case ContentTypes.markdown:
{
res = `[markdown]`;
}
break;
case ContentTypes.archive:
{
res = `[${i18n.t("forward", { ns: "chat" })}]`;
}
break;
case ContentTypes.file:
{
const props = properties ?? {};
if (isImage(props.content_type, props.size)) {
res = `[${i18n.t("image", { ns: "chat" })}]`;
} else {
res = `[${i18n.t("file", { ns: "chat" })}]`;
}
}
break;
default:
break;
}
return res;
};
const MessageWrapper = ({ selectMode = false, context, id, mid, divider, children, ...rest }) => {
const dispatch = useDispatch();
const selects = useAppSelector((store) => store.ui.selectMessages[`${context}_${id}`]);
const selected = !!(selects && selects.find((s) => s == mid));
const toggleSelect = () => {
const operation = selected ? "remove" : "add";
dispatch(updateSelectMessages({ context, id, operation, data: mid }));
};
return (
<div className={`group flex flex-col items-start gap-2 relative w-full `} {...rest}>
{divider}
<div
className={`w-full flex items-center ${
selectMode ? "group-hover:bg-slate-100 dark:group-hover:bg-slate-900" : ""
}`}
>
{selectMode && <Checkbox className="!ml-2" checked={selected} />}
{children}
</div>
{selectMode && (
<div
className="absolute left-0 top-0 w-full h-full cursor-pointer"
onClick={selectMode ? toggleSelect : undefined}
></div>
)}
</div>
);
};
type Params = {
readonly?: boolean;
selectMode: boolean;
read?: boolean;
updateReadIndex?: (param: any) => void;
prev?: object | null;
curr: object | null;
contextId: number;
context: ChatContext;
};
export const renderMessageFragment = ({
readonly = false,
selectMode = false,
read = true,
updateReadIndex,
prev,
curr = null,
contextId = 0,
context = "dm"
}: Params) => {
if (!curr) return <div className="w-full h-[1px] invisible"></div>;
let { created_at, mid } = curr;
const local_id = curr.properties?.local_id;
let divider = null;
let time = dayjs(created_at).format("YYYY/MM/DD");
if (!prev && typeof prev !== "undefined") {
// 首条信息
divider = time;
} else if (prev) {
let { created_at: prev_created_at } = prev;
if (!dayjs(prev_created_at).isSame(created_at, "day")) {
divider = time;
}
}
const _key = local_id || mid;
return (
<MessageWrapper
key={_key}
data-key={_key}
context={context}
id={contextId}
mid={mid}
selectMode={selectMode}
divider={divider ? <Divider className="w-full" content={divider}></Divider> : null}
>
<Message
readOnly={selectMode || readonly}
updateReadIndex={updateReadIndex}
read={read}
context={context}
mid={mid}
key={_key}
contextId={contextId}
/>
</MessageWrapper>
);
};
export default getUnreadCount;