refactor: add typescript support to project
This commit is contained in:
@@ -10,10 +10,8 @@ import InviteModal from "../../../common/component/InviteModal";
|
||||
import Tooltip from "../../../common/component/Tooltip";
|
||||
import IconSetting from "../../../assets/icons/setting.svg";
|
||||
import IconInvite from "../../../assets/icons/invite.from.channel.svg";
|
||||
// import { useDebounce} from "rooks";
|
||||
import { useReadMessageMutation } from "../../../app/services/message";
|
||||
import { useUpdateMuteSettingMutation } from "../../../app/services/contact";
|
||||
|
||||
import StyledLink from "./styled";
|
||||
import ChannelIcon from "../../../common/component/ChannelIcon";
|
||||
import { getUnreadCount } from "../utils";
|
||||
@@ -1,12 +1,11 @@
|
||||
import { useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
import DeleteConfirmModal from "../../settingChannel/DeleteConfirmModal";
|
||||
import NavItem from "./NavItem";
|
||||
import { useAppSelector } from "../../../app/store";
|
||||
|
||||
export default function ChannelList({ setDropFiles }) {
|
||||
const [currId, setCurrId] = useState(null);
|
||||
const { channelIds } = useSelector((store) => {
|
||||
const { channelIds } = useAppSelector((store) => {
|
||||
return { channelIds: store.channels.ids };
|
||||
});
|
||||
|
||||
@@ -82,4 +82,5 @@ const Styled = styled(NavLink)`
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default Styled;
|
||||
@@ -3,7 +3,6 @@ import { useSelector } from "react-redux";
|
||||
import { useDebounce } from "rooks";
|
||||
import Tippy from "@tippyjs/react";
|
||||
import FavList from "../FavList";
|
||||
|
||||
import Tooltip from "../../../common/component/Tooltip";
|
||||
import FavIcon from "../../../assets/icons/bookmark.svg";
|
||||
// import searchIcon from "../../../assets/icons/search.svg?url";
|
||||
@@ -16,6 +15,7 @@ import { StyledHeader, StyledDMChat } from "./styled";
|
||||
import LoadMore from "../LoadMore";
|
||||
import { renderMessageFragment } from "../utils";
|
||||
import useMessageFeed from "../../../common/hook/useMessageFeed";
|
||||
|
||||
export default function DMChat({ uid = "", dropFiles = [] }) {
|
||||
const {
|
||||
list: msgIds,
|
||||
@@ -1,11 +1,15 @@
|
||||
// import React from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
import { FC } from "react";
|
||||
import { getUnreadCount } from "../utils";
|
||||
|
||||
import NavItem from "./NavItem";
|
||||
export default function DMList({ uids, setDropFiles }) {
|
||||
const { userMessage, messageData, readUsers, loginUid } = useSelector((store) => {
|
||||
import { useAppSelector } from "../../../app/store";
|
||||
|
||||
interface Props {
|
||||
uids: number[];
|
||||
setDropFiles: () => void;
|
||||
}
|
||||
|
||||
const DMList: FC<Props> = ({ uids, setDropFiles }) => {
|
||||
const { userMessage, messageData, readUsers, loginUid } = useAppSelector((store) => {
|
||||
return {
|
||||
loginUid: store.authData.uid,
|
||||
readUsers: store.footprint.readUsers,
|
||||
@@ -31,14 +35,20 @@ export default function DMList({ uids, setDropFiles }) {
|
||||
return { lastMid, unreads, uid };
|
||||
});
|
||||
// console.log("temp uids", sessions);
|
||||
return sessions
|
||||
.sort((s1, s2) => {
|
||||
if (!s1.lastMid) return s2.lastMid - Infinity;
|
||||
return s2.lastMid - s1.lastMid;
|
||||
})
|
||||
.map(({ lastMid, uid, unreads }) => {
|
||||
return (
|
||||
<NavItem key={uid} uid={uid} mid={lastMid} unreads={unreads} setFiles={setDropFiles} />
|
||||
);
|
||||
});
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{sessions
|
||||
.sort((s1, s2) => {
|
||||
if (!s1.lastMid) return s2.lastMid - Infinity;
|
||||
return s2.lastMid - s1.lastMid;
|
||||
})
|
||||
.map(({ lastMid, uid, unreads }) => {
|
||||
return (
|
||||
<NavItem key={uid} uid={uid} mid={lastMid} unreads={unreads} setFiles={setDropFiles} />
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DMList;
|
||||
@@ -6,6 +6,7 @@ import IconSurprise from "../../assets/icons/emoji.suprise.svg";
|
||||
// import IconForward from "../../../assets/icons/forward.svg";
|
||||
import IconRemove from "../../assets/icons/close.svg";
|
||||
import useFavMessage from "../../common/hook/useFavMessage";
|
||||
|
||||
const Styled = styled.div`
|
||||
padding: 16px;
|
||||
background: #f9fafb;
|
||||
@@ -83,6 +84,7 @@ const Styled = styled.div`
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default function FavList({ cid = null, uid = null }) {
|
||||
const { favorites, removeFavorite } = useFavMessage({ cid, uid });
|
||||
const handleRemove = (evt) => {
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState } from "react";
|
||||
import styled from "styled-components";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { useKey } from "rooks";
|
||||
import toast from "react-hot-toast";
|
||||
import useDeleteMessage from "../../../common/hook/useDeleteMessage";
|
||||
import useFavMessage from "../../../common/hook/useFavMessage";
|
||||
import { updateSelectMessages } from "../../../app/slices/ui";
|
||||
@@ -10,8 +10,9 @@ import IconBookmark from "../../../assets/icons/bookmark.svg";
|
||||
import IconDelete from "../../../assets/icons/delete.svg";
|
||||
import IconClose from "../../../assets/icons/close.circle.svg";
|
||||
import ForwardModal from "../../../common/component/ForwardModal";
|
||||
import toast from "react-hot-toast";
|
||||
import DeleteMessageConfirmModal from "../../../common/component/DeleteMessageConfirm";
|
||||
import { useAppDispatch, useAppSelector } from "../../../app/store";
|
||||
|
||||
const Styled = styled.div`
|
||||
position: relative;
|
||||
padding: 16px;
|
||||
@@ -40,16 +41,19 @@ const Styled = styled.div`
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
`;
|
||||
|
||||
export default function Operations({ context, id }) {
|
||||
const [deleteModalVisible, setDeleteModalVisible] = useState(false);
|
||||
const { canDelete } = useDeleteMessage();
|
||||
const { addFavorite } = useFavMessage({});
|
||||
const mids = useSelector((store) => store.ui.selectMessages[`${context}_${id}`]);
|
||||
const mids = useAppSelector((store) => store.ui.selectMessages[`${context}_${id}`]);
|
||||
const [forwardModalVisible, setForwardModalVisible] = useState(false);
|
||||
const dispatch = useDispatch();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const handleClose = () => {
|
||||
dispatch(updateSelectMessages({ context, id, operation: "reset" }));
|
||||
};
|
||||
|
||||
const handleFav = async () => {
|
||||
const added = await addFavorite(mids);
|
||||
if (added) {
|
||||
@@ -60,6 +64,7 @@ export default function Operations({ context, id }) {
|
||||
toast.error("Operation Failed!");
|
||||
}
|
||||
};
|
||||
|
||||
const toggleDeleteModal = (isSuccess = false) => {
|
||||
setDeleteModalVisible((prev) => !prev);
|
||||
if (isSuccess) {
|
||||
@@ -67,14 +72,17 @@ export default function Operations({ context, id }) {
|
||||
toast.success("Messages Deleted!");
|
||||
}
|
||||
};
|
||||
|
||||
const toggleForwardModal = () => {
|
||||
setForwardModalVisible((prev) => !prev);
|
||||
};
|
||||
|
||||
useKey("Escape", (evt) => {
|
||||
console.log("Escape keypress", evt);
|
||||
dispatch(updateSelectMessages({ context, id, operation: "reset" }));
|
||||
});
|
||||
const canDel = canDelete(mids);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Styled>
|
||||
@@ -1,7 +1,5 @@
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import { useState, useRef, useEffect, FC, ReactElement } from "react";
|
||||
import { useDrop } from "react-dnd";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
import { NativeTypes } from "react-dnd-html5-backend";
|
||||
import ImagePreviewModal from "../../../common/component/ImagePreviewModal";
|
||||
import Send from "../../../common/component/Send";
|
||||
@@ -9,8 +7,19 @@ import Styled from "./styled";
|
||||
import Operations from "./Operations";
|
||||
import useUploadFile from "../../../common/hook/useUploadFile";
|
||||
import { ChatPrefixs } from "../../../app/config";
|
||||
import { useAppSelector } from "../../../app/store";
|
||||
|
||||
export default function Layout({
|
||||
interface Props {
|
||||
children: ReactElement;
|
||||
header: ReactElement;
|
||||
aside: ReactElement | null;
|
||||
contacts: ReactElement | null;
|
||||
dropFiles: [];
|
||||
context: string;
|
||||
to: number | null;
|
||||
}
|
||||
|
||||
const Layout: FC<Props> = ({
|
||||
children,
|
||||
header,
|
||||
aside = null,
|
||||
@@ -18,11 +27,11 @@ export default function Layout({
|
||||
dropFiles = [],
|
||||
context = "channel",
|
||||
to = null
|
||||
}) {
|
||||
}) => {
|
||||
const { addStageFile } = useUploadFile({ context, id: to });
|
||||
const messagesContainer = useRef(undefined);
|
||||
const messagesContainer = useRef<HTMLDivElement>(null);
|
||||
const [previewImage, setPreviewImage] = useState(null);
|
||||
const { selects, channelsData, contactsData } = useSelector((store) => {
|
||||
const { selects, channelsData, contactsData } = useAppSelector((store) => {
|
||||
return {
|
||||
selects: store.ui.selectMessages[`${context}_${to}`],
|
||||
channelsData: store.channels.byId,
|
||||
@@ -49,6 +58,7 @@ export default function Layout({
|
||||
}),
|
||||
[context, to]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (dropFiles?.length) {
|
||||
const filesData = dropFiles.map((file) => {
|
||||
@@ -63,6 +73,7 @@ export default function Layout({
|
||||
const closePreviewModal = () => {
|
||||
setPreviewImage(null);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const container = messagesContainer?.current;
|
||||
if (container) {
|
||||
@@ -85,6 +96,7 @@ export default function Layout({
|
||||
}
|
||||
}, []);
|
||||
const name = context == "channel" ? channelsData[to]?.name : contactsData[to]?.name;
|
||||
|
||||
return (
|
||||
<>
|
||||
{previewImage && <ImagePreviewModal data={previewImage} closeModal={closePreviewModal} />}
|
||||
@@ -112,4 +124,6 @@ export default function Layout({
|
||||
</Styled>
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default Layout;
|
||||
+5
-1
@@ -1,4 +1,3 @@
|
||||
// import React from 'react'
|
||||
import Tippy from "@tippyjs/react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { useNavigate, useLocation, useMatch } from "react-router-dom";
|
||||
@@ -30,9 +29,11 @@ export default function SessionContextMenu({
|
||||
channelMuted: context == "channel" ? store.footprint.muteChannels[id] : false
|
||||
};
|
||||
});
|
||||
|
||||
const handleChannelSetting = () => {
|
||||
navigateTo(`/setting/channel/${id}?f=${pathname}`);
|
||||
};
|
||||
|
||||
const handleReadAll = () => {
|
||||
// console.log("last mid", mids, lastMid);
|
||||
if (mid) {
|
||||
@@ -41,16 +42,19 @@ export default function SessionContextMenu({
|
||||
updateReadIndex(param);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemoveSession = () => {
|
||||
dispatch(removeUserSession(id));
|
||||
if (pathMatched) {
|
||||
navigateTo("/chat");
|
||||
}
|
||||
};
|
||||
|
||||
const handleChannelMute = () => {
|
||||
const data = channelMuted ? { remove_groups: [id] } : { add_groups: [{ gid: id }] };
|
||||
muteChannel(data);
|
||||
};
|
||||
|
||||
const items =
|
||||
context == "user"
|
||||
? [
|
||||
@@ -13,7 +13,10 @@ import IconLock from "../../../assets/icons/lock.svg";
|
||||
import useContextMenu from "../../../common/hook/useContextMenu";
|
||||
import { useNavigate, NavLink } from "react-router-dom";
|
||||
import useUploadFile from "../../../common/hook/useUploadFile";
|
||||
|
||||
// todo: move to root file
|
||||
dayjs.extend(relativeTime);
|
||||
|
||||
export default function Session({
|
||||
type = "user",
|
||||
id,
|
||||
@@ -23,6 +26,7 @@ export default function Session({
|
||||
}) {
|
||||
const navigate = useNavigate();
|
||||
const { addStageFile } = useUploadFile({ context: type, id });
|
||||
|
||||
const [{ isActive }, drop] = useDrop(
|
||||
() => ({
|
||||
accept: [NativeTypes.FILE],
|
||||
@@ -44,6 +48,7 @@ export default function Session({
|
||||
}),
|
||||
[type, id]
|
||||
);
|
||||
|
||||
const { visible: contextMenuVisible, handleContextMenuEvent, hideContextMenu } = useContextMenu();
|
||||
const [data, setData] = useState(null);
|
||||
const { messageData, contactData, channelData, readIndex, loginUid, mids, muted } = useSelector(
|
||||
@@ -60,10 +65,12 @@ export default function Session({
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
const handleImageError = (evt) => {
|
||||
evt.target.classList.add("channel_default");
|
||||
evt.target.src = iconChannel;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const tmp = type == "user" ? contactData[id] : channelData[id];
|
||||
if (!tmp) return;
|
||||
@@ -81,6 +88,7 @@ export default function Session({
|
||||
messageData,
|
||||
loginUid
|
||||
});
|
||||
|
||||
return (
|
||||
<li className="session">
|
||||
<ContextMenu
|
||||
@@ -1,15 +1,16 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import Styled from "./styled";
|
||||
import Session from "./Session";
|
||||
import DeleteChannelConfirmModal from "../../settingChannel/DeleteConfirmModal";
|
||||
import InviteModal from "../../../common/component/InviteModal";
|
||||
import { useAppSelector } from "../../../app/store";
|
||||
|
||||
export default function SessionList({ tempSession = null }) {
|
||||
const [deleteId, setDeleteId] = useState(null);
|
||||
const [inviteChannelId, setInviteChannelId] = useState(null);
|
||||
const [sessions, setSessions] = useState([]);
|
||||
const { channelIDs, DMs, readChannels, readUsers, channelMessage, userMessage, loginUid } =
|
||||
useSelector((store) => {
|
||||
useAppSelector((store) => {
|
||||
return {
|
||||
loginUid: store.authData.uid,
|
||||
channelIDs: store.channels.ids,
|
||||
@@ -20,6 +21,7 @@ export default function SessionList({ tempSession = null }) {
|
||||
readUsers: store.footprint.readUsers
|
||||
};
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const cSessions = channelIDs.map((id) => {
|
||||
const mids = channelMessage[id];
|
||||
@@ -51,6 +53,7 @@ export default function SessionList({ tempSession = null }) {
|
||||
userMessage,
|
||||
tempSession
|
||||
]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Styled>
|
||||
@@ -1,14 +1,14 @@
|
||||
import { useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
// import { useUpdateChannelMutation } from "../../app/services/channel";
|
||||
import { useUpdateMuteSettingMutation } from "../../app/services/contact";
|
||||
import { useReadMessageMutation } from "../../app/services/message";
|
||||
import { useAppSelector } from "../../app/store";
|
||||
|
||||
export default function useSession({ type, id }) {
|
||||
const [inviteModalVisible, setInviteModalVisible] = useState(false);
|
||||
const [muteChannel] = useUpdateMuteSettingMutation();
|
||||
const [updateReadIndex] = useReadMessageMutation();
|
||||
const { messageData, contactData, channelData } = useSelector((store) => {
|
||||
const { messageData, contactData, channelData } = useAppSelector((store) => {
|
||||
return {
|
||||
messageData: store.message,
|
||||
contactData: store.contacts.byId,
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import dayjs from "dayjs";
|
||||
import styled from "styled-components";
|
||||
import reactStringReplace from "react-string-replace";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { isImage } from "../../common/utils";
|
||||
import { ContentTypes } from "../../app/config";
|
||||
@@ -9,7 +10,7 @@ import Divider from "../../common/component/Divider";
|
||||
import Message from "../../common/component/Message";
|
||||
import { updateSelectMessages } from "../../app/slices/ui";
|
||||
import Mention from "../../common/component/Message/Mention";
|
||||
import reactStringReplace from "react-string-replace";
|
||||
|
||||
// function debounce(callback, wait = 2000, immediate = false) {
|
||||
// let timeout = null;
|
||||
// return function () {
|
||||
@@ -22,6 +23,7 @@ import reactStringReplace from "react-string-replace";
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
|
||||
export function getUnreadCount({ mids = [], messageData = {}, loginUid = 0, readIndex = 0 }) {
|
||||
// console.log({ mids, loginUid, readIndex });
|
||||
// 先过滤掉空信息和from自己的
|
||||
@@ -124,6 +126,7 @@ const StyledWrapper = styled.div`
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const MessageWrapper = ({ selectMode = false, context, id, mid, children, ...rest }) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
@@ -142,6 +145,7 @@ const MessageWrapper = ({ selectMode = false, context, id, mid, children, ...res
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export const renderMessageFragment = ({
|
||||
selectMode = false,
|
||||
isFirst = false,
|
||||
Reference in New Issue
Block a user