refactor: add typescript support to project

This commit is contained in:
HD
2022-06-21 15:08:35 +08:00
parent 88ec2b742a
commit bd799ebea8
259 changed files with 1042 additions and 458 deletions
@@ -3,11 +3,10 @@ import { useDispatch } from "react-redux";
import styled from "styled-components";
import Tippy from "@tippyjs/react";
import { hideAll } from "tippy.js";
import toast from "react-hot-toast";
import { updateSelectMessages } from "../../../app/slices/ui";
// import StyledMenu from "../styled/Menu";
import ContextMenu from "../ContextMenu";
import Tooltip from "../../component/Tooltip";
import Tooltip from "../Tooltip";
import useFavMessage from "../../hook/useFavMessage";
import useSendMessage from "../../hook/useSendMessage";
import ReactionPicker from "./ReactionPicker";
@@ -20,8 +19,8 @@ import IconForward from "../../../assets/icons/forward.svg";
import IconSelect from "../../../assets/icons/select.svg";
import IconDelete from "../../../assets/icons/delete.svg";
import moreIcon from "../../../assets/icons/more.svg?url";
import toast from "react-hot-toast";
import useMessageOperation from "./useMessageOperation";
const StyledCmds = styled.ul`
z-index: 999;
position: absolute;
@@ -62,6 +61,7 @@ const StyledCmds = styled.ul`
transform: translateX(-100%);
}
`;
export default function Commands({ context = "user", contextId = 0, mid = 0, toggleEditMessage }) {
const {
canDelete,
@@ -1,4 +1,3 @@
// import { useState } from "react";
import Tippy from "@tippyjs/react";
import { useDispatch } from "react-redux";
import ContextMenu from "../ContextMenu";
@@ -2,9 +2,10 @@ import { useState, useRef, useEffect } from "react";
import styled from "styled-components";
import TextareaAutosize from "react-textarea-autosize";
import { useKey } from "rooks";
import { useEditMessageMutation } from "../../../app/services/message";
import { useSelector } from "react-redux";
import { useEditMessageMutation } from "../../../app/services/message";
import { ContentTypes } from "../../../app/config";
const StyledWrapper = styled.div`
width: 100%;
.input {
@@ -45,8 +46,9 @@ const StyledWrapper = styled.div`
}
}
`;
export default function EditMessage({ mid, cancelEdit }) {
const inputRef = useRef();
const inputRef = useRef<HTMLTextAreaElement>(null);
const msg = useSelector((store) => store.message[mid] || {});
const [shift, setShift] = useState(false);
const [enter, setEnter] = useState(false);
@@ -95,6 +97,7 @@ export default function EditMessage({ mid, cancelEdit }) {
});
};
if (!msg) return null;
return (
<StyledWrapper>
<div className="input">
@@ -1,17 +1,17 @@
import { useEffect, useState } from "react";
// import dayjs from "dayjs";
import styled from "styled-components";
import StyledMsg from "./styled";
import renderContent from "./renderContent";
import Avatar from "../Avatar";
import useFavMessage from "../../hook/useFavMessage";
const StyledFav = styled.div`
display: flex;
flex-direction: column;
border-radius: var(--br);
background-color: #f4f4f5;
`;
const FavoritedMessage = ({ id }) => {
const { favorites } = useFavMessage({});
const [msgs, setMsgs] = useState(null);
@@ -5,6 +5,7 @@ import renderContent from "./renderContent";
import Avatar from "../Avatar";
import IconForward from "../../../assets/icons/forward.svg";
import useNormalizeMessage from "../../hook/useNormalizeMessage";
const StyledForward = styled.div`
display: flex;
flex-direction: column;
@@ -1,8 +1,9 @@
// import React from "react";
import { useSelector } from "react-redux";
import { FC } from "react";
import Tippy from "@tippyjs/react";
import Profile from "../Profile";
import styled from "styled-components";
import Profile from "../Profile";
import { useAppSelector } from "../../../app/store";
const Styled = styled.span`
padding: 0 2px;
color: #1fe1f9;
@@ -10,8 +11,16 @@ const Styled = styled.span`
cursor: pointer;
}
`;
export default function Mention({ uid, popover = true, cid, textOnly = false }) {
const contactsData = useSelector((store) => store.contacts.byId);
interface Props {
uid: number;
popover?: boolean;
cid: number;
textOnly?: boolean;
}
const Mention: FC<Props> = ({ uid, popover = true, cid, textOnly = false }) => {
const contactsData = useAppSelector((store) => store.contacts.byId);
const user = contactsData[uid];
if (!user) return null;
if (textOnly) return `@${user.name}`;
@@ -26,4 +35,6 @@ export default function Mention({ uid, popover = true, cid, textOnly = false })
<Styled className={popover ? "clickable" : ""}>{`@${user.name}`}</Styled>
</Tippy>
);
}
};
export default Mention;
@@ -1,6 +1,13 @@
// import React from "react";
import { FC } from "react";
import { useEffect } from "react";
import styled from "styled-components";
import toast from "react-hot-toast";
import usePinMessage from "../../hook/usePinMessage";
import StyledModal from "../styled/Modal";
import Button from "../styled/Button";
import Modal from "../Modal";
import PreviewMessage from "./PreviewMessage";
const StyledPinModal = styled(StyledModal)`
min-width: 406px;
.title,
@@ -15,24 +22,25 @@ const StyledPinModal = styled(StyledModal)`
overflow-x: hidden;
}
`;
import usePinMessage from "../../hook/usePinMessage";
import StyledModal from "../styled/Modal";
import Button from "../styled/Button";
import Modal from "../Modal";
import PreviewMessage from "./PreviewMessage";
import toast from "react-hot-toast";
export default function PinMessageModal({ closeModal, mid = 0, gid = 0 }) {
// const dispatch = useDispatch();
interface Props {
closeModal: () => void;
mid: number;
gid: number;
}
const PinMessageModal: FC<Props> = ({ closeModal, mid = 0, gid = 0 }) => {
const { channel, pinMessage, isPining, isSuccess } = usePinMessage(gid);
const handlePin = () => {
pinMessage(mid);
};
useEffect(() => {
if (isSuccess) {
closeModal();
toast.success("Pin Message Successfully");
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isSuccess]);
if (!mid) return null;
@@ -57,4 +65,6 @@ export default function PinMessageModal({ closeModal, mid = 0, gid = 0 }) {
</StyledPinModal>
</Modal>
);
}
};
export default PinMessageModal;
@@ -1,11 +1,11 @@
// import { useEffect, useRef, useState } from "react";
import dayjs from "dayjs";
import renderContent from "./renderContent";
import Avatar from "../Avatar";
import StyledWrapper from "./styled";
import { useSelector } from "react-redux";
import { useAppSelector } from "../../../app/store";
export default function PreviewMessage({ mid = 0 }) {
const { msg, contactsData } = useSelector((store) => {
const { msg, contactsData } = useAppSelector((store) => {
return { msg: store.message[mid], contactsData: store.contacts.byId };
});
if (!msg) return null;
@@ -1,4 +1,3 @@
// import { useState } from "react";
import { useSelector } from "react-redux";
import styled from "styled-components";
import { getEmojiDataFromNative } from "emoji-mart";
@@ -10,6 +9,7 @@ import ReactionPicker from "./ReactionPicker";
import Tooltip from "../Tooltip";
import { useReactMessageMutation } from "../../../app/services/message";
import addEmojiIcon from "../../../assets/icons/add.emoji.svg?url";
const StyledWrapper = styled.span`
position: relative;
margin-top: 8px;
@@ -1,9 +1,9 @@
import styled from "styled-components";
import { useSelector } from "react-redux";
import { useReactMessageMutation } from "../../../app/services/message";
import { Emojis } from "../../../app/config";
import Emoji from "../ReactionItem";
import { useAppSelector } from "../../../app/store";
const StyledPicker = styled.div`
background: none;
z-index: 999;
@@ -38,7 +38,7 @@ const StyledPicker = styled.div`
export default function ReactionPicker({ mid, hidePicker }) {
// const wrapperRef = useRef(null);
const [reactMessage, { isLoading }] = useReactMessageMutation();
const { reactionData, currUid } = useSelector((store) => {
const { reactionData, currUid } = useAppSelector((store) => {
return {
reactionData: store.reactionMessage[mid] || {},
currUid: store.authData.uid
@@ -1,6 +1,5 @@
import React from "react";
import React, { MouseEvent, FC } from "react";
import styled from "styled-components";
import { useSelector } from "react-redux";
import reactStringReplace from "react-string-replace";
import MrakdownRender from "../MrakdownRender";
import Mention from "./Mention";
@@ -8,6 +7,7 @@ import { ContentTypes } from "../../../app/config";
import { getFileIcon, isImage } from "../../utils";
import Avatar from "../Avatar";
import { useAppSelector } from "../../../app/store";
const Styled = styled.div`
display: flex;
align-items: flex-start;
@@ -16,19 +16,23 @@ const Styled = styled.div`
border-radius: var(--br);
gap: 8px;
margin-bottom: 4px;
&.clickable {
cursor: pointer;
}
.user {
display: flex;
align-items: center;
gap: 4px;
white-space: nowrap;
.avatar {
width: 16px;
height: 16px;
border-radius: 50%;
}
.name {
font-style: normal;
font-weight: 500;
@@ -37,6 +41,7 @@ const Styled = styled.div`
color: #06b6d4;
}
}
.content {
overflow: hidden;
font-weight: 500;
@@ -45,20 +50,22 @@ const Styled = styled.div`
color: #616161;
display: flex;
align-items: center;
.txt {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
text-overflow: ellipsis;
overflow: hidden;
-webkit-box-orient: vertical;
word-wrap: break-word;
word-break: break-all;
}
.md {
position: relative;
max-height: 152px;
overflow: hidden;
&:after {
position: absolute;
left: 0;
@@ -69,24 +76,29 @@ const Styled = styled.div`
background: linear-gradient(180deg, rgba(255, 255, 255, 0) 63.54%, #e5e7eb 93.09%);
}
}
.pic {
display: inherit;
width: 40px;
height: 40px;
object-fit: cover;
}
.icon {
width: 15px;
height: 20px;
}
.file_name {
margin-left: 5px;
font-size: 10px;
color: #555;
}
}
/* padding-left: 10px; */
`;
const renderContent = (data) => {
const { content_type, content, thumbnail, properties } = data;
let res = null;
@@ -136,13 +148,19 @@ const renderContent = (data) => {
}
return res;
};
const Reply = ({ mid, interactive = true }) => {
const { data, users } = useSelector((store) => {
interface ReplyProps {
mid: number;
interactive?: boolean;
}
const Reply: FC<ReplyProps> = ({ mid, interactive = true }) => {
const { data, users } = useAppSelector((store) => {
return { data: store.message[mid], users: store.contacts.byId };
});
const handleClick = (evt) => {
const handleClick = (evt: MouseEvent<HTMLDivElement>) => {
const { mid } = evt.currentTarget.dataset;
const msgEle = document.querySelector(`[data-msg-mid='${mid}']`);
const msgEle = document.querySelector<HTMLDivElement>(`[data-msg-mid='${mid}']`);
if (msgEle) {
msgEle.dataset.highlight = true;
msgEle.scrollIntoView({ behavior: "smooth", block: "center" });
@@ -1,7 +1,7 @@
import { useState, useEffect } from "react";
import styled from "styled-components";
import { useLazyGetOGInfoQuery } from "../../../app/services/message";
// import favUrl from "../../../assets/icons/favicon.default.svg?url";
const StyledCompact = styled.a`
background: #f3f4f6;
border: 1px solid #d4d4d4;
@@ -92,12 +92,13 @@ const StyledDetails = styled.a`
}
}
`;
export default function URLPreview({ url = "" }) {
const [favicon, setFavicon] = useState("");
const [getInfo] = useLazyGetOGInfoQuery();
const [data, setData] = useState(null);
useEffect(() => {
const getMetaData = async (url) => {
const getMetaData = async (url: string) => {
// todo
const { data } = await getInfo(url);
const title = data.title || data.site_name;
@@ -15,11 +15,13 @@ import EditMessage from "./EditMessage";
import renderContent from "./renderContent";
import Tooltip from "../Tooltip";
import ContextMenu from "./ContextMenu";
import useContextMenu from "../../hook/useContextMenu";
import usePinMessage from "../../hook/usePinMessage";
// todo: move to root file
dayjs.extend(isToday);
dayjs.extend(isYesterday);
function Message({
readOnly = false,
contextId = 0,
@@ -1,7 +1,7 @@
import React from "react";
import Linkit from "react-linkify";
import dayjs from "dayjs";
import reactStringReplace from "react-string-replace";
import { ContentTypes } from "../../../app/config";
import Mention from "./Mention";
import ForwardedMessage from "./ForwardedMessage";
@@ -9,7 +9,6 @@ import MrakdownRender from "../MrakdownRender";
import FileMessage from "../FileMessage";
import URLPreview from "./URLPreview";
import reactStringReplace from "react-string-replace";
const renderContent = ({
context = null,
to = null,
@@ -1,4 +1,5 @@
import styled from "styled-components";
const StyledMsg = styled.div`
position: relative;
display: flex;
@@ -1,7 +1,7 @@
import { useRef, useEffect } from "react";
export default function useInView() {
const ref = useRef(undefined);
export default function useInView<T extends HTMLElement>() {
const ref = useRef<T>(null);
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
@@ -17,7 +17,7 @@ export default function useInView() {
{ threshold: 0 }
);
useEffect(() => {
const currEle = ref?.current;
const currEle = ref.current;
if (currEle) {
observer.observe(ref.current);
}
@@ -4,13 +4,19 @@ import DeleteMessageConfirm from "../DeleteMessageConfirm";
import ForwardModal from "../ForwardModal";
import PinMessageModal from "./PinMessageModal";
import { ContentTypes } from "../../../app/config";
import { useSelector } from "react-redux";
import useCopy from "../../hook/useCopy";
import usePinMessage from "../../hook/usePinMessage";
import { useAppSelector } from "../../../app/store";
export default function useMessageOperation({ mid, context, contextId }) {
interface Params {
mid: number;
context: string;
contextId: number;
}
export default function useMessageOperation({ mid, context, contextId }: Params) {
const { copy } = useCopy();
const { content_type, properties, currUid, from_uid, content } = useSelector((store) => {
const { content_type, properties, currUid, from_uid, content } = useAppSelector((store) => {
return {
content: store.message[mid]?.content,
from_uid: store.message[mid]?.from_uid,