From 96017c8fc6221b0985f2dbacf28fd64f175262a3 Mon Sep 17 00:00:00 2001 From: Tristan Yang Date: Fri, 29 Jul 2022 08:49:34 +0800 Subject: [PATCH] refactor: more TS code --- src/app/services/auth.ts | 2 +- src/app/slices/favorites.ts | 2 +- src/app/slices/message.ts | 14 +++++----- src/common/component/Message/ContextMenu.tsx | 19 +++++++++---- src/common/component/Message/EditMessage.tsx | 4 +-- .../component/Message/FavoredMessage.tsx | 4 +-- .../component/Message/ForwardedMessage.tsx | 22 +++++++-------- src/common/component/Message/Mention.tsx | 4 +-- .../component/Message/PreviewMessage.tsx | 2 +- src/common/component/Message/Reaction.tsx | 28 +++++++++++++++---- .../component/Message/ReactionPicker.tsx | 11 ++++++-- src/common/component/Message/Reply.tsx | 6 ++-- .../component/Message/renderContent.tsx | 25 ++++++++++++----- .../component/Message/useMessageOperation.tsx | 9 +++--- .../component/MixedInput/StyledCombobox.tsx | 10 ------- src/common/component/ReactionItem.tsx | 6 ++-- src/common/component/Send/Replying.tsx | 14 ++++++++-- src/common/component/Send/Toolbar.tsx | 18 ++++++++---- .../Send/UploadFileList/EditFileDetails.tsx | 14 ++++++++-- .../component/Send/UploadFileList/index.tsx | 22 +++++++++++---- src/common/hook/useFavMessage.ts | 4 +-- 21 files changed, 150 insertions(+), 90 deletions(-) delete mode 100644 src/common/component/MixedInput/StyledCombobox.tsx diff --git a/src/app/services/auth.ts b/src/app/services/auth.ts index 69aea5c2..09c8aea1 100644 --- a/src/app/services/auth.ts +++ b/src/app/services/auth.ts @@ -82,7 +82,7 @@ export const authApi = createApi({ } }), // 更新 device token - updateDeviceToken: builder.mutation({ + updateDeviceToken: builder.mutation({ query: (device_token) => ({ url: "/token/device_token", method: "PUT", diff --git a/src/app/slices/favorites.ts b/src/app/slices/favorites.ts index 6bfb4ada..af86ffe0 100644 --- a/src/app/slices/favorites.ts +++ b/src/app/slices/favorites.ts @@ -19,7 +19,7 @@ const favoritesSlice = createSlice({ addFavorite(state, action: PayloadAction) { state.push(action.payload); }, - deleteFavorite(state, action: PayloadAction) { + deleteFavorite(state, action: PayloadAction) { const id = action.payload; const idx = state.findIndex((f) => f.id == id); if (idx > -1) { diff --git a/src/app/slices/message.ts b/src/app/slices/message.ts index cd6cc661..99864929 100644 --- a/src/app/slices/message.ts +++ b/src/app/slices/message.ts @@ -1,13 +1,6 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import BASE_URL, { ContentTypes } from "../config"; import { isImage } from "../../common/utils"; - -export interface State { - [key: number]: object; - replying: { - [key: string | number]: number; - }; -} export interface MessagePayload { mid: number; sending: boolean; @@ -21,6 +14,13 @@ export interface MessagePayload { download?: string; thumbnail?: string; } +export interface State { + [key: number]: MessagePayload; + replying: { + [key: string | number]: number; + }; +} + const initialState: State = { replying: {} }; diff --git a/src/common/component/Message/ContextMenu.tsx b/src/common/component/Message/ContextMenu.tsx index fcfc4ed1..04f6928c 100644 --- a/src/common/component/Message/ContextMenu.tsx +++ b/src/common/component/Message/ContextMenu.tsx @@ -1,3 +1,4 @@ +import { FC, ReactElement, ReactNode } from "react"; import Tippy from "@tippyjs/react"; import { useDispatch } from "react-redux"; import ContextMenu from "../ContextMenu"; @@ -11,8 +12,16 @@ import IconSelect from "../../../assets/icons/select.svg"; import { updateSelectMessages } from "../../../app/slices/ui"; import useSendMessage from "../../hook/useSendMessage"; import useMessageOperation from "./useMessageOperation"; - -export default function MessageContextMenu({ +type Props = { + context: "user" | "channel"; + contextId: number; + mid: number; + visible: boolean; + hide: () => void; + editMessage: () => void; + children: ReactElement; +}; +const MessageContextMenu: FC = ({ context, contextId, mid, @@ -20,10 +29,9 @@ export default function MessageContextMenu({ hide, editMessage, children -}) { +}) => { const { copyContent, - // isMarkdown, canEdit, canPin, canDelete, @@ -109,4 +117,5 @@ export default function MessageContextMenu({ ); -} +}; +export default MessageContextMenu; diff --git a/src/common/component/Message/EditMessage.tsx b/src/common/component/Message/EditMessage.tsx index 9fef31e6..adf42988 100644 --- a/src/common/component/Message/EditMessage.tsx +++ b/src/common/component/Message/EditMessage.tsx @@ -52,10 +52,10 @@ type Props = { }; const EditMessage: FC = ({ mid, cancelEdit }) => { const inputRef = useRef(null); - const msg = useAppSelector((store) => store.message[mid] || {}); + const msg = useAppSelector((store) => store.message[mid]); const [shift, setShift] = useState(false); const [enter, setEnter] = useState(false); - const [currMsg, setCurrMsg] = useState(msg.content); + const [currMsg, setCurrMsg] = useState(msg?.content); const [edit, { isLoading: isEditing, isSuccess }] = useEditMessageMutation(); useEffect(() => { if (isSuccess) { diff --git a/src/common/component/Message/FavoredMessage.tsx b/src/common/component/Message/FavoredMessage.tsx index a5d87e47..56c272b6 100644 --- a/src/common/component/Message/FavoredMessage.tsx +++ b/src/common/component/Message/FavoredMessage.tsx @@ -12,9 +12,9 @@ const StyledFav = styled.div` background-color: #f4f4f5; `; type Props = { - id?: number; + id?: string; }; -const FavoredMessage: FC = ({ id }) => { +const FavoredMessage: FC = ({ id = "" }) => { const { favorites } = useFavMessage({}); const [msgs, setMsgs] = useState(null); diff --git a/src/common/component/Message/ForwardedMessage.tsx b/src/common/component/Message/ForwardedMessage.tsx index 16315af5..a8a310a8 100644 --- a/src/common/component/Message/ForwardedMessage.tsx +++ b/src/common/component/Message/ForwardedMessage.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect, useState, FC, ReactElement } from "react"; import styled from "styled-components"; import StyledMsg from "./styled"; import renderContent from "./renderContent"; @@ -29,9 +29,15 @@ const StyledForward = styled.div` color: #98a2b3; } `; -const ForwardedMessage = ({ context, to, from_uid, id }) => { +type Props = { + context: "user" | "channel"; + to: number; + from_uid: number; + id: string; +}; +const ForwardedMessage: FC = ({ context, to, from_uid, id }) => { const { normalizeMessage, messages } = useNormalizeMessage(); - const [forwards, setForwards] = useState(null); + const [forwards, setForwards] = useState(null); useEffect(() => { if (id) { normalizeMessage(id); @@ -50,15 +56,7 @@ const ForwardedMessage = ({ context, to, from_uid, id }) => {
{messages.map((msg, idx) => { - const { - user = {}, - // created_at, - download, - content, - content_type, - properties, - thumbnail - } = msg; + const { user = {}, download, content, content_type, properties, thumbnail } = msg; return ( {user && ( diff --git a/src/common/component/Message/Mention.tsx b/src/common/component/Message/Mention.tsx index 4cdabd58..2bc9535c 100644 --- a/src/common/component/Message/Mention.tsx +++ b/src/common/component/Message/Mention.tsx @@ -1,4 +1,4 @@ -import { FC, ReactNode } from "react"; +// import { FC, ReactNode } from "react"; import Tippy from "@tippyjs/react"; import styled from "styled-components"; import Profile from "../Profile"; @@ -19,7 +19,7 @@ interface Props { textOnly?: boolean; } -const Mention: FC = ({ uid, popover = true, cid, textOnly = false }) => { +const Mention = ({ uid, popover = true, cid, textOnly = false }: Props) => { const usersData = useAppSelector((store) => store.users.byId); const user = usersData[uid]; if (!user) return null; diff --git a/src/common/component/Message/PreviewMessage.tsx b/src/common/component/Message/PreviewMessage.tsx index 7593c037..b5b66d1b 100644 --- a/src/common/component/Message/PreviewMessage.tsx +++ b/src/common/component/Message/PreviewMessage.tsx @@ -14,7 +14,7 @@ const PreviewMessage: FC = ({ mid = 0 }) => { return { msg: store.message[mid], usersData: store.users.byId }; }); if (!msg) return null; - const { from_uid, created_at, content_type, content, thumbnail, properties } = msg; + const { from_uid, created_at, content_type, content, thumbnail = "", properties } = msg; const { name, avatar } = usersData[from_uid] || {}; return ( diff --git a/src/common/component/Message/Reaction.tsx b/src/common/component/Message/Reaction.tsx index 44703995..cce14e7c 100644 --- a/src/common/component/Message/Reaction.tsx +++ b/src/common/component/Message/Reaction.tsx @@ -1,9 +1,10 @@ +import { FC } from "react"; import styled from "styled-components"; import { getEmojiDataFromNative } from "emoji-mart"; import AppleEmojiData from "emoji-mart/data/apple.json"; import Tippy from "@tippyjs/react"; import { hideAll } from "tippy.js"; -import ReactionItem from "../ReactionItem"; +import ReactionItem, { Emojis } from "../ReactionItem"; import ReactionPicker from "./ReactionPicker"; import Tooltip from "../Tooltip"; import { useReactMessageMutation } from "../../../app/services/message"; @@ -104,12 +105,20 @@ const StyledDetails = styled.div` color: #1d2939; } `; -const ReactionDetails = ({ uids = [], emoji, index }) => { +const ReactionDetails = ({ + uids = [], + emoji, + index +}: { + uids: number[]; + emoji?: keyof Emojis; + index: number; +}) => { const usersData = useAppSelector((store) => store.users.byId); const names = uids.map((id) => { return usersData[id]?.name; }); - const emojiData = getEmojiDataFromNative(emoji, "apple", AppleEmojiData); + const emojiData = getEmojiDataFromNative(emoji || "", "apple", AppleEmojiData); const prefixDesc = names.length > 3 ? `${names.join(", ")} and ${names.length - 3} others reacted with` @@ -127,14 +136,20 @@ const ReactionDetails = ({ uids = [], emoji, index }) => { ); }; -export default function Reaction({ mid, reactions = null }) { +type Props = { + mid: number; + reactions?: { + [key in keyof Emojis]: number[]; + }; +}; +const Reaction: FC = ({ mid, reactions = null }) => { const [reactWithEmoji] = useReactMessageMutation(); const { currUid } = useAppSelector((store) => { return { currUid: store.authData.user?.uid }; }); - const handleReact = (emoji) => { + const handleReact = (emoji: string) => { reactWithEmoji({ mid, action: emoji }); }; console.log("curr reactions", reactions); @@ -178,4 +193,5 @@ export default function Reaction({ mid, reactions = null }) { ); -} +}; +export default Reaction; diff --git a/src/common/component/Message/ReactionPicker.tsx b/src/common/component/Message/ReactionPicker.tsx index 44d48013..a1fe26ae 100644 --- a/src/common/component/Message/ReactionPicker.tsx +++ b/src/common/component/Message/ReactionPicker.tsx @@ -1,3 +1,4 @@ +import { FC } from "react"; import styled from "styled-components"; import { useReactMessageMutation } from "../../../app/services/message"; import { Emojis } from "../../../app/config"; @@ -34,8 +35,11 @@ const StyledPicker = styled.div` } } `; - -export default function ReactionPicker({ mid, hidePicker }) { +type Props = { + mid: number; + hidePicker: () => void; +}; +const ReactionPicker: FC = ({ mid, hidePicker }) => { const [reactMessage, { isLoading }] = useReactMessageMutation(); const { reactionData, currUid } = useAppSelector((store) => { return { @@ -68,4 +72,5 @@ export default function ReactionPicker({ mid, hidePicker }) { ); -} +}; +export default ReactionPicker; diff --git a/src/common/component/Message/Reply.tsx b/src/common/component/Message/Reply.tsx index 1ff89d12..4bbcdcb6 100644 --- a/src/common/component/Message/Reply.tsx +++ b/src/common/component/Message/Reply.tsx @@ -95,8 +95,6 @@ const Styled = styled.div` color: #555; } } - - /* padding-left: 10px; */ `; const renderContent = (data) => { @@ -162,11 +160,11 @@ const Reply: FC = ({ mid, interactive = true }) => { const { mid } = evt.currentTarget.dataset; const msgEle = document.querySelector(`[data-msg-mid='${mid}']`); if (msgEle) { - msgEle.dataset.highlight = true; + msgEle.dataset.highlight = "true"; msgEle.scrollIntoView({ behavior: "smooth", block: "center" }); setTimeout(() => { console.log("scroll view", msgEle); - msgEle.dataset.highlight = false; + msgEle.dataset.highlight = "false"; }, 3000); } }; diff --git a/src/common/component/Message/renderContent.tsx b/src/common/component/Message/renderContent.tsx index bd34fdec..d46f017c 100644 --- a/src/common/component/Message/renderContent.tsx +++ b/src/common/component/Message/renderContent.tsx @@ -8,11 +8,22 @@ import ForwardedMessage from "./ForwardedMessage"; import MarkdownRender from "../MarkdownRender"; import FileMessage from "../FileMessage"; import URLPreview from "./URLPreview"; - +type Props = { + context: "user" | "channel"; + to?: number; + from_uid?: number; + created_at: number; + properties?: object; + content_type; + content: string; + download: string; + thumbnail: string; + edited?: boolean | number; +}; const renderContent = ({ - context = null, - to = null, - from_uid, + context, + to = 0, + from_uid = 0, created_at, properties, content_type, @@ -20,7 +31,7 @@ const renderContent = ({ download, thumbnail, edited = false -}) => { +}: Props) => { let ctn = null; switch (content_type) { case ContentTypes.text: @@ -39,13 +50,13 @@ const renderContent = ({ {reactStringReplace(content, /(\s{1}@[0-9]+\s{1})/g, (match, idx) => { console.log("match", match); const uid = match.trim().slice(1); - return ; + return ; })} {/* {content.replace(/\s{1}\@[1-9]+\s{1}/g,)} */} {/* {new RegExp(/\s{1}\@[1-9]+\s{1}/g).exec(content)} */} {edited && ( - + (edited) )} diff --git a/src/common/component/Message/useMessageOperation.tsx b/src/common/component/Message/useMessageOperation.tsx index 67f7b0ea..c1c09519 100644 --- a/src/common/component/Message/useMessageOperation.tsx +++ b/src/common/component/Message/useMessageOperation.tsx @@ -26,9 +26,9 @@ export default function useMessageOperation({ mid, context, contextId }: Params) }; }); const { canPin, pins, unpinMessage, isUnpinSuccess } = usePinMessage( - context == "channel" ? contextId : undefined + context == "channel" ? contextId : 0 ); - const [mids, setMids] = useState([]); + const [mids, setMids] = useState([]); const [pinModalVisible, setPinModalVisible] = useState(false); const [deleteModalVisible, setDeleteModalVisible] = useState(false); const [forwardModalVisible, setForwardModalVisible] = useState(false); @@ -53,10 +53,9 @@ export default function useMessageOperation({ mid, context, contextId }: Params) // forward message const forwardEle = document.querySelector( `[data-msg-mid='${mid}'] .down [data-forwarded-mids]` - ); + ) as HTMLDivElement; if (forwardEle) { - console.log("ddddd", mid, forwardEle.dataset); - const mids = forwardEle.dataset.forwardedMids.split(","); + const mids = forwardEle.dataset.forwardedMids?.split(",").map((m) => +m) || []; setMids(mids); } } else { diff --git a/src/common/component/MixedInput/StyledCombobox.tsx b/src/common/component/MixedInput/StyledCombobox.tsx deleted file mode 100644 index f7d83d9b..00000000 --- a/src/common/component/MixedInput/StyledCombobox.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import styled from "styled-components"; - -const Styled = styled.div` - display: flex; -`; - -export default function StyledCombobox({ store }) { - console.log("combox wtf", store.get.state()); - return StyledCombobox; -} diff --git a/src/common/component/ReactionItem.tsx b/src/common/component/ReactionItem.tsx index d3d33e02..36ae922b 100644 --- a/src/common/component/ReactionItem.tsx +++ b/src/common/component/ReactionItem.tsx @@ -8,7 +8,7 @@ import EmojiHeart from "../../assets/icons/emoji.heart.svg"; import EmojiRocket from "../../assets/icons/emoji.rocket.svg"; import EmojiLook from "../../assets/icons/emoji.look.svg"; -interface Emojis { +export interface Emojis { "👍": ReactElement; "👎": ReactElement; "😄": ReactElement; @@ -31,11 +31,11 @@ const emojis: Emojis = { }; interface Props { - native?: keyof Emojis; + native: keyof Emojis; } const ReactionItem: FC = ({ native }) => { - if (!native) return null; + // if (!native) return null; return emojis[native] ?? null; }; diff --git a/src/common/component/Send/Replying.tsx b/src/common/component/Send/Replying.tsx index b6b5c8ac..763aaa01 100644 --- a/src/common/component/Send/Replying.tsx +++ b/src/common/component/Send/Replying.tsx @@ -8,6 +8,7 @@ import pictureIcon from "../../../assets/icons/picture.svg?url"; import { getFileIcon, isImage } from "../../utils"; import useSendMessage from "../../hook/useSendMessage"; import { useAppSelector } from "../../../app/store"; +import { MessagePayload } from "../../../app/slices/message"; const Styled = styled.div` background-color: #f3f4f6; @@ -74,10 +75,9 @@ const Styled = styled.div` position: absolute; top: 16px; right: 16px; - /* transform: translateY(-50%); */ } `; -const renderContent = (data) => { +const renderContent = (data: MessagePayload) => { const { content_type, content, thumbnail = "", properties } = data; let res = null; switch (content_type) { @@ -120,7 +120,15 @@ const renderContent = (data) => { return res; }; -export default function Replying({ context, id, mid }) { +export default function Replying({ + context, + id, + mid +}: { + context: "user" | "channel"; + id: number; + mid: number; +}) { const { removeReplying } = useSendMessage({ to: id, context }); const { msg, usersData } = useAppSelector((store) => { return { usersData: store.users.byId, msg: store.message[mid] }; diff --git a/src/common/component/Send/Toolbar.tsx b/src/common/component/Send/Toolbar.tsx index 27cf11f8..83274566 100644 --- a/src/common/component/Send/Toolbar.tsx +++ b/src/common/component/Send/Toolbar.tsx @@ -1,4 +1,4 @@ -import { ChangeEvent, useRef } from "react"; +import { ChangeEvent, useRef, FC } from "react"; import styled from "styled-components"; import Tooltip from "../Tooltip"; import AddIcon from "../../../assets/icons/add.solid.svg"; @@ -42,15 +42,22 @@ const Styled = styled.div` } } `; - -export default function Toolbar({ +type Props = { + toggleMarkdownFullscreen: () => void; + fullscreen: boolean; + toggleMode: () => void; + mode: "markdown" | "text"; + to: number; + context: "user" | "channel"; +}; +const Toolbar: FC = ({ toggleMarkdownFullscreen, fullscreen, toggleMode, mode, to, context -}) { +}) => { const { addStageFile } = useUploadFile({ context, id: to }); const fileInputRef = useRef(null); const handleUpload = (evt: ChangeEvent) => { @@ -105,4 +112,5 @@ export default function Toolbar({ ); -} +}; +export default Toolbar; diff --git a/src/common/component/Send/UploadFileList/EditFileDetails.tsx b/src/common/component/Send/UploadFileList/EditFileDetails.tsx index ebd3610e..ae64dccd 100644 --- a/src/common/component/Send/UploadFileList/EditFileDetails.tsx +++ b/src/common/component/Send/UploadFileList/EditFileDetails.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { ChangeEvent, useState } from "react"; import styled from "styled-components"; import Modal from "../../Modal"; import Button from "../../styled/Button"; @@ -48,9 +48,17 @@ const StyledWrapper = styled.div` } `; -export default function EditFileDetails({ name, closeModal, updateName }) { +export default function EditFileDetails({ + name, + closeModal, + updateName +}: { + name: string; + closeModal: () => void; + updateName: (name: string) => void; +}) { const [fileName, setFileName] = useState(name); - const handleNameChange = (evt) => { + const handleNameChange = (evt: ChangeEvent) => { setFileName(evt.target.value); }; const handleUpdate = () => { diff --git a/src/common/component/Send/UploadFileList/index.tsx b/src/common/component/Send/UploadFileList/index.tsx index acc46bc7..f482a4c0 100644 --- a/src/common/component/Send/UploadFileList/index.tsx +++ b/src/common/component/Send/UploadFileList/index.tsx @@ -7,24 +7,34 @@ import useUploadFile from "../../../hook/useUploadFile"; import EditIcon from "../../../../assets/icons/edit.svg"; import DeleteIcon from "../../../../assets/icons/delete.svg"; -export default function UploadFileList({ context = "", id = null }) { +type EditProps = { + index: number; + name: string; +}; +export default function UploadFileList({ + context, + id +}: { + context: "user" | "channel"; + id: number; +}) { const eidtor = useMixedEditor(`${context}_${id}`); - const [editInfo, setEditInfo] = useState(null); + const [editInfo, setEditInfo] = useState(null); const { stageFiles, updateStageFile, removeStageFile } = useUploadFile({ context, id }); - const toggleModalVisible = (info) => { + const toggleModalVisible = (info: EditProps) => { setEditInfo((prev) => (prev ? null : info)); }; - const handleOpenEditModal = (idx) => { + const handleOpenEditModal = (idx: number) => { const info = stageFiles[idx]; if (!info) return; toggleModalVisible({ ...info, index: idx }); }; - const updateFileName = (name) => { - if (!name) return; + const updateFileName = (name: string) => { + if (!name || !editInfo) return; const { index } = editInfo; updateStageFile(index, { name }); }; diff --git a/src/common/hook/useFavMessage.ts b/src/common/hook/useFavMessage.ts index a7d21b49..e5e9603c 100644 --- a/src/common/hook/useFavMessage.ts +++ b/src/common/hook/useFavMessage.ts @@ -17,7 +17,7 @@ export default function useFavMessage({ return { favs: store.favorites }; }); - const addFavorite = async (mid = []) => { + const addFavorite = async (mid: number | number[]) => { const mids = Array.isArray(mid) ? mid.map((i) => +i) : [+mid]; if (mids.length == 0) return; const resp = await addFav(mids); @@ -29,7 +29,7 @@ export default function useFavMessage({ removeFav(id); }; - const isFavorited = (mid = null) => { + const isFavorited = (mid = 0) => { if (!mid) return false; let mids: number[] = []; favorites.forEach((f: Favorite) => {