refactor: more TS code

This commit is contained in:
Tristan Yang
2022-07-29 08:49:34 +08:00
parent 43a13f8d08
commit 96017c8fc6
21 changed files with 150 additions and 90 deletions
+1 -1
View File
@@ -82,7 +82,7 @@ export const authApi = createApi({
}
}),
// 更新 device token
updateDeviceToken: builder.mutation<void, { device_token: string }>({
updateDeviceToken: builder.mutation<void, string>({
query: (device_token) => ({
url: "/token/device_token",
method: "PUT",
+1 -1
View File
@@ -19,7 +19,7 @@ const favoritesSlice = createSlice({
addFavorite(state, action: PayloadAction<Favorite>) {
state.push(action.payload);
},
deleteFavorite(state, action: PayloadAction<number>) {
deleteFavorite(state, action: PayloadAction<string>) {
const id = action.payload;
const idx = state.findIndex((f) => f.id == id);
if (idx > -1) {
+7 -7
View File
@@ -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: {}
};
+14 -5
View File
@@ -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<Props> = ({
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({
</Tippy>
</>
);
}
};
export default MessageContextMenu;
+2 -2
View File
@@ -52,10 +52,10 @@ type Props = {
};
const EditMessage: FC<Props> = ({ mid, cancelEdit }) => {
const inputRef = useRef<HTMLTextAreaElement>(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) {
@@ -12,9 +12,9 @@ const StyledFav = styled.div`
background-color: #f4f4f5;
`;
type Props = {
id?: number;
id?: string;
};
const FavoredMessage: FC<Props> = ({ id }) => {
const FavoredMessage: FC<Props> = ({ id = "" }) => {
const { favorites } = useFavMessage({});
const [msgs, setMsgs] = useState<ReactElement | null>(null);
@@ -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<Props> = ({ context, to, from_uid, id }) => {
const { normalizeMessage, messages } = useNormalizeMessage();
const [forwards, setForwards] = useState(null);
const [forwards, setForwards] = useState<ReactElement | null>(null);
useEffect(() => {
if (id) {
normalizeMessage(id);
@@ -50,15 +56,7 @@ const ForwardedMessage = ({ context, to, from_uid, id }) => {
</h4>
<div className="list">
{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 (
<StyledMsg className="archive" key={idx}>
{user && (
+2 -2
View File
@@ -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<Props> = ({ 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;
@@ -14,7 +14,7 @@ const PreviewMessage: FC<Props> = ({ 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 (
<StyledWrapper className={`preview`}>
+22 -6
View File
@@ -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 }) => {
</StyledDetails>
);
};
export default function Reaction({ mid, reactions = null }) {
type Props = {
mid: number;
reactions?: {
[key in keyof Emojis]: number[];
};
};
const Reaction: FC<Props> = ({ 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 }) {
</Tooltip>
</StyledWrapper>
);
}
};
export default Reaction;
@@ -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<Props> = ({ mid, hidePicker }) => {
const [reactMessage, { isLoading }] = useReactMessageMutation();
const { reactionData, currUid } = useAppSelector((store) => {
return {
@@ -68,4 +72,5 @@ export default function ReactionPicker({ mid, hidePicker }) {
</ul>
</StyledPicker>
);
}
};
export default ReactionPicker;
+2 -4
View File
@@ -95,8 +95,6 @@ const Styled = styled.div`
color: #555;
}
}
/* padding-left: 10px; */
`;
const renderContent = (data) => {
@@ -162,11 +160,11 @@ const Reply: FC<ReplyProps> = ({ mid, interactive = true }) => {
const { mid } = evt.currentTarget.dataset;
const msgEle = document.querySelector<HTMLDivElement>(`[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);
}
};
+18 -7
View File
@@ -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 <Mention key={idx} uid={uid} cid={to} />;
return <Mention key={idx} uid={+uid} cid={to} />;
})}
{/* {content.replace(/\s{1}\@[1-9]+\s{1}/g,)} */}
{/* {new RegExp(/\s{1}\@[1-9]+\s{1}/g).exec(content)} */}
</Linkit>
{edited && (
<span className="edited" title={dayjs(edited).format("YYYY-MM-DD h:mm:ss A")}>
<span className="edited" title={dayjs(+edited).format("YYYY-MM-DD h:mm:ss A")}>
(edited)
</span>
)}
@@ -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<number[]>([]);
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 {
@@ -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 <Styled>StyledCombobox</Styled>;
}
+3 -3
View File
@@ -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<Props> = ({ native }) => {
if (!native) return null;
// if (!native) return null;
return emojis[native] ?? null;
};
+11 -3
View File
@@ -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] };
+13 -5
View File
@@ -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<Props> = ({
toggleMarkdownFullscreen,
fullscreen,
toggleMode,
mode,
to,
context
}) {
}) => {
const { addStageFile } = useUploadFile({ context, id: to });
const fileInputRef = useRef<HTMLInputElement>(null);
const handleUpload = (evt: ChangeEvent<HTMLInputElement>) => {
@@ -105,4 +112,5 @@ export default function Toolbar({
</Tooltip>
</Styled>
);
}
};
export default Toolbar;
@@ -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<HTMLInputElement>) => {
setFileName(evt.target.value);
};
const handleUpdate = () => {
@@ -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<EditProps | null>(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 });
};
+2 -2
View File
@@ -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) => {