diff --git a/config/modules.js b/config/modules.js index c1709df5..de9b04a7 100644 --- a/config/modules.js +++ b/config/modules.js @@ -34,7 +34,7 @@ function getAdditionalModulePaths(options = {}) { // If the path is equal to the root directory we ignore it here. // We don't want to allow importing from the root directly as source files are // not transpiled outside of `src`. We do allow importing them with the - // absolute path (e.g. `src/Components/Button.js`) but we set that up with + // absolute path (e.g. `src/Components/Button.tsx`) but we set that up with // an alias. if (path.relative(paths.appPath, baseUrlResolved) === "") { return null; diff --git a/package.json b/package.json index 7c62223f..9e48f4d0 100644 --- a/package.json +++ b/package.json @@ -131,6 +131,9 @@ "@commitlint/cli": "^17.0.2", "@commitlint/config-conventional": "^17.0.2", "@types/emoji-mart": "^3.0.9", + "@types/masonry-layout": "^4.2.5", + "@types/react-helmet": "^6.1.5", + "@types/react-linkify": "^1.0.1", "@types/styled-components": "^5.1.25", "@typescript-eslint/eslint-plugin": "^5.10.1", "@typescript-eslint/parser": "^5.10.1", diff --git a/src/app/cache/index.js b/src/app/cache/index.ts similarity index 99% rename from src/app/cache/index.js rename to src/app/cache/index.ts index 93c4d703..b4a9fa4c 100644 --- a/src/app/cache/index.js +++ b/src/app/cache/index.ts @@ -1,6 +1,7 @@ import localforage from "localforage"; import useRehydrate from "./useRehydrate"; import { KEY_UID, CACHE_VERSION } from "../config"; + const tables = [ { storeName: "channels", diff --git a/src/app/cache/useRehydrate.js b/src/app/cache/useRehydrate.ts similarity index 99% rename from src/app/cache/useRehydrate.js rename to src/app/cache/useRehydrate.ts index 05f8fc07..38a9ad67 100644 --- a/src/app/cache/useRehydrate.js +++ b/src/app/cache/useRehydrate.ts @@ -1,5 +1,4 @@ import { useState } from "react"; - import { useDispatch, batch } from "react-redux"; import { fullfillReactionMessage } from "../slices/message.reaction"; import { fullfillServer } from "../slices/server"; @@ -11,6 +10,7 @@ import { fullfillContacts } from "../slices/contacts"; import { fullfillFootprint } from "../slices/footprint"; import { fullfillFileMessage } from "../slices/message.file"; import { fullfillUI } from "../slices/ui"; + const useRehydrate = () => { const [iterated, setIterated] = useState(false); const dispatch = useDispatch(); @@ -94,4 +94,5 @@ const useRehydrate = () => { }; return { rehydrate, rehydrated: iterated }; }; + export default useRehydrate; diff --git a/src/app/listener.middleware/clear.handler.js b/src/app/listener.middleware/clear.handler.ts similarity index 75% rename from src/app/listener.middleware/clear.handler.js rename to src/app/listener.middleware/clear.handler.ts index 347dc9f8..de4155fb 100644 --- a/src/app/listener.middleware/clear.handler.js +++ b/src/app/listener.middleware/clear.handler.ts @@ -1,4 +1,4 @@ -const clearTable = async (table) => { +const clearTable = async (table: string) => { const t = window.CACHE[table]; if (!t) return; @@ -6,4 +6,5 @@ const clearTable = async (table) => { t.removeItem(key); }); }; + export default clearTable; diff --git a/src/app/listener.middleware/handler.channel.msg.js b/src/app/listener.middleware/handler.channel.msg.ts similarity index 81% rename from src/app/listener.middleware/handler.channel.msg.js rename to src/app/listener.middleware/handler.channel.msg.ts index 34674741..bf789d95 100644 --- a/src/app/listener.middleware/handler.channel.msg.js +++ b/src/app/listener.middleware/handler.channel.msg.ts @@ -1,5 +1,15 @@ import clearTable from "./clear.handler"; -export default async function handler({ operation, data = {}, payload }) { + +// todo +export type BaseOperation = "add" | "remove" | "reset"; + +export interface Params { + operation: string; + data: {}; + payload: {}; +} + +export default async function handler({ operation, data = {}, payload }: Params) { const table = window.CACHE["messageChannel"]; if (operation.startsWith("reset")) { clearTable("messageChannel"); diff --git a/src/app/listener.middleware/handler.channels.js b/src/app/listener.middleware/handler.channels.ts similarity index 99% rename from src/app/listener.middleware/handler.channels.js rename to src/app/listener.middleware/handler.channels.ts index e076b707..ee4b0a9e 100644 --- a/src/app/listener.middleware/handler.channels.js +++ b/src/app/listener.middleware/handler.channels.ts @@ -1,4 +1,5 @@ import clearTable from "./clear.handler"; + export default async function handler({ operation, data, payload }) { const table = window.CACHE["channels"]; if (operation.startsWith("reset")) { diff --git a/src/app/listener.middleware/handler.contacts.js b/src/app/listener.middleware/handler.contacts.ts similarity index 99% rename from src/app/listener.middleware/handler.contacts.js rename to src/app/listener.middleware/handler.contacts.ts index 773777ad..78cd2b8e 100644 --- a/src/app/listener.middleware/handler.contacts.js +++ b/src/app/listener.middleware/handler.contacts.ts @@ -1,4 +1,5 @@ import clearTable from "./clear.handler"; + export default async function handler({ operation, data, payload }) { const table = window.CACHE["contacts"]; if (operation.startsWith("reset")) { diff --git a/src/app/listener.middleware/handler.dm.msg.js b/src/app/listener.middleware/handler.dm.msg.ts similarity index 99% rename from src/app/listener.middleware/handler.dm.msg.js rename to src/app/listener.middleware/handler.dm.msg.ts index aa4913fe..fcd5ac39 100644 --- a/src/app/listener.middleware/handler.dm.msg.js +++ b/src/app/listener.middleware/handler.dm.msg.ts @@ -1,4 +1,5 @@ import clearTable from "./clear.handler"; + export default async function handler({ operation, data = {}, payload }) { const table = window.CACHE["messageDM"]; if (operation.startsWith("reset")) { diff --git a/src/app/listener.middleware/handler.file.msg.js b/src/app/listener.middleware/handler.file.msg.ts similarity index 99% rename from src/app/listener.middleware/handler.file.msg.js rename to src/app/listener.middleware/handler.file.msg.ts index 60614e2e..f4371b19 100644 --- a/src/app/listener.middleware/handler.file.msg.js +++ b/src/app/listener.middleware/handler.file.msg.ts @@ -1,4 +1,5 @@ import clearTable from "./clear.handler"; + export default async function handler({ operation, data = {} }) { const table = window.CACHE["messageFile"]; if (operation.startsWith("reset")) { diff --git a/src/app/listener.middleware/handler.footprint.js b/src/app/listener.middleware/handler.footprint.ts similarity index 99% rename from src/app/listener.middleware/handler.footprint.js rename to src/app/listener.middleware/handler.footprint.ts index b6acbc6d..bde00158 100644 --- a/src/app/listener.middleware/handler.footprint.js +++ b/src/app/listener.middleware/handler.footprint.ts @@ -1,4 +1,5 @@ import clearTable from "./clear.handler"; + export default async function handler({ operation, data = {}, payload }) { const table = window.CACHE["footprint"]; if (operation.startsWith("reset")) { diff --git a/src/app/listener.middleware/handler.message.js b/src/app/listener.middleware/handler.message.ts similarity index 99% rename from src/app/listener.middleware/handler.message.js rename to src/app/listener.middleware/handler.message.ts index cc7f70df..8209ffa9 100644 --- a/src/app/listener.middleware/handler.message.js +++ b/src/app/listener.middleware/handler.message.ts @@ -1,4 +1,5 @@ import clearTable from "./clear.handler"; + export default async function handler({ operation, data = {}, payload }) { const table = window.CACHE["message"]; if (operation.startsWith("reset")) { diff --git a/src/app/listener.middleware/handler.reaction.js b/src/app/listener.middleware/handler.reaction.ts similarity index 99% rename from src/app/listener.middleware/handler.reaction.js rename to src/app/listener.middleware/handler.reaction.ts index 702075c5..ffed1b4d 100644 --- a/src/app/listener.middleware/handler.reaction.js +++ b/src/app/listener.middleware/handler.reaction.ts @@ -1,4 +1,5 @@ import clearTable from "./clear.handler"; + export default async function handler({ operation, data = {}, payload }) { const table = window.CACHE["messageReaction"]; if (operation.startsWith("reset")) { diff --git a/src/app/listener.middleware/handler.rtkq.js b/src/app/listener.middleware/handler.rtkq.ts similarity index 60% rename from src/app/listener.middleware/handler.rtkq.js rename to src/app/listener.middleware/handler.rtkq.ts index 8e55c04b..203f649c 100644 --- a/src/app/listener.middleware/handler.rtkq.js +++ b/src/app/listener.middleware/handler.rtkq.ts @@ -1,6 +1,12 @@ -// import clearTable from "./clear.handler"; import { updateOnline } from "../slices/ui"; -export default async function handler({ dispatch, operation }) { +import { AppDispatch } from "../store"; + +interface Params { + dispatch: AppDispatch; + operation: string; +} + +export default async function handler({ dispatch, operation }: Params) { switch (operation) { case "offline": { diff --git a/src/app/listener.middleware/handler.server.js b/src/app/listener.middleware/handler.server.ts similarity index 99% rename from src/app/listener.middleware/handler.server.js rename to src/app/listener.middleware/handler.server.ts index fb496748..a1c1d2cb 100644 --- a/src/app/listener.middleware/handler.server.js +++ b/src/app/listener.middleware/handler.server.ts @@ -1,4 +1,5 @@ import clearTable from "./clear.handler"; + export default async function handler({ operation, payload }) { const table = window.CACHE["server"]; if (operation.startsWith("reset")) { diff --git a/src/app/listener.middleware/handler.ui.js b/src/app/listener.middleware/handler.ui.ts similarity index 99% rename from src/app/listener.middleware/handler.ui.js rename to src/app/listener.middleware/handler.ui.ts index ca82489d..cc7933c2 100644 --- a/src/app/listener.middleware/handler.ui.js +++ b/src/app/listener.middleware/handler.ui.ts @@ -1,4 +1,5 @@ import clearTable from "./clear.handler"; + export default async function handler({ operation, data = {} }) { const table = window.CACHE["ui"]; if (operation.startsWith("reset")) { diff --git a/src/app/listener.middleware/index.js b/src/app/listener.middleware/index.ts similarity index 99% rename from src/app/listener.middleware/index.js rename to src/app/listener.middleware/index.ts index 38a98aef..92c0e625 100644 --- a/src/app/listener.middleware/index.js +++ b/src/app/listener.middleware/index.ts @@ -10,6 +10,7 @@ import fileMessageHandler from "./handler.file.msg"; import reactionHandler from "./handler.reaction"; import UIHandler from "./handler.ui"; import footprintHandler from "./handler.footprint"; + const operations = [ "__rtkq", "channels", diff --git a/src/app/services/handlers.js b/src/app/services/handlers.ts similarity index 99% rename from src/app/services/handlers.js rename to src/app/services/handlers.ts index 5bcaf509..0cf71a53 100644 --- a/src/app/services/handlers.js +++ b/src/app/services/handlers.ts @@ -4,6 +4,7 @@ import { ContentTypes } from "../config"; import { addChannelMsg, removeChannelMsg } from "../slices/message.channel"; import { addUserMsg, removeUserMsg } from "../slices/message.user"; import { addMessage, removeMessage } from "../slices/message"; + export const onMessageSendStarted = async ( { ignoreLocal = false, diff --git a/src/app/services/message.js b/src/app/services/message.ts similarity index 100% rename from src/app/services/message.js rename to src/app/services/message.ts diff --git a/src/app/services/server.js b/src/app/services/server.ts similarity index 99% rename from src/app/services/server.js rename to src/app/services/server.ts index 5f9f29ea..612e1572 100644 --- a/src/app/services/server.js +++ b/src/app/services/server.ts @@ -2,7 +2,9 @@ import { createApi } from "@reduxjs/toolkit/query/react"; import BASE_URL from "../config"; import { updateInfo } from "../slices/server"; import baseQuery from "./base.query"; + const defaultExpireDuration = 7 * 24 * 60 * 60; + export const serverApi = createApi({ reducerPath: "serverApi", baseQuery, diff --git a/src/common/component/AddEntriesMenu.js b/src/common/component/AddEntriesMenu.tsx similarity index 95% rename from src/common/component/AddEntriesMenu.js rename to src/common/component/AddEntriesMenu.tsx index 3a4f858b..60248cb8 100644 --- a/src/common/component/AddEntriesMenu.js +++ b/src/common/component/AddEntriesMenu.tsx @@ -1,5 +1,4 @@ import { useState } from "react"; -// import { useSelector } from "react-redux"; import styled from "styled-components"; import { hideAll } from "tippy.js"; import IconInvite from "../../assets/icons/add.person.svg"; @@ -12,7 +11,7 @@ import InviteModal from "./InviteModal"; const Styled = styled.ul` z-index: 999; user-select: none; - box-shadow: 0px 24px 48px -12px rgba(16, 24, 40, 0.18); + box-shadow: 0 24px 48px -12px rgba(16, 24, 40, 0.18); border-radius: 12px; color: #616161; background: #fff; @@ -64,7 +63,7 @@ export default function AddEntriesMenu() { return !prevVisible; }); }; - const handleOpenChannelModal = (isPrivate) => { + const handleOpenChannelModal = (isPrivate: boolean) => { setIsPrivate(isPrivate); setChannelModalVisible(true); hideAll(); diff --git a/src/common/component/Avatar.js b/src/common/component/Avatar.tsx similarity index 99% rename from src/common/component/Avatar.js rename to src/common/component/Avatar.tsx index 889715ac..7d663695 100644 --- a/src/common/component/Avatar.js +++ b/src/common/component/Avatar.tsx @@ -1,5 +1,6 @@ import { useState, useEffect, memo } from "react"; import { getInitials, getInitialsAvatar } from "../utils"; + const Avatar = ({ url = "", name = "unkonw name", type = "user", ...rest }) => { // console.log("avatar url", url); const [src, setSrc] = useState(""); diff --git a/src/common/component/AvatarUploader.js b/src/common/component/AvatarUploader.tsx similarity index 98% rename from src/common/component/AvatarUploader.js rename to src/common/component/AvatarUploader.tsx index 923691d5..8fd0492d 100644 --- a/src/common/component/AvatarUploader.js +++ b/src/common/component/AvatarUploader.tsx @@ -1,7 +1,8 @@ import { useState } from "react"; import styled from "styled-components"; -import Avatar from "../component/Avatar"; +import Avatar from "./Avatar"; import uploadIcon from "../../assets/icons/upload.image.svg?url"; + const StyledWrapper = styled.div` width: 96px; height: 96px; @@ -59,6 +60,7 @@ const StyledWrapper = styled.div` right: 0; } `; + export default function AvatarUploader({ url = "", name = "", diff --git a/src/common/component/BlankPlaceholder.js b/src/common/component/BlankPlaceholder.tsx similarity index 94% rename from src/common/component/BlankPlaceholder.js rename to src/common/component/BlankPlaceholder.tsx index cb92dbdc..305a3fb9 100644 --- a/src/common/component/BlankPlaceholder.js +++ b/src/common/component/BlankPlaceholder.tsx @@ -1,14 +1,15 @@ import { useState } from "react"; import styled from "styled-components"; -import ChannelModal from "../component/ChannelModal"; -import InviteModal from "../component/InviteModal"; +import { NavLink } from "react-router-dom"; +import ChannelModal from "./ChannelModal"; +import InviteModal from "./InviteModal"; import IconChat from "../../assets/icons/placeholder.chat.svg"; import IconAsk from "../../assets/icons/placeholder.question.svg"; import IconInvite from "../../assets/icons/placeholder.invite.svg"; import IconDownload from "../../assets/icons/placeholder.download.svg"; -import { NavLink } from "react-router-dom"; import ContactsModal from "./ContactsModal"; -import { useSelector } from "react-redux"; +import { useAppSelector } from "../../app/store"; + const Styled = styled.div` margin-top: -50px; display: flex; @@ -65,8 +66,9 @@ const Styled = styled.div` } } `; + export default function BlankPlaceholder({ type = "chat" }) { - const server = useSelector((store) => store.server); + const server = useAppSelector((store) => store.server); const [inviteModalVisible, setInviteModalVisible] = useState(false); const [createChannelVisible, setCreateChannelVisible] = useState(false); const [contactListVisible, setContactListVisible] = useState(false); diff --git a/src/common/component/Channel.js b/src/common/component/Channel.tsx similarity index 85% rename from src/common/component/Channel.js rename to src/common/component/Channel.tsx index 467c0402..4faf4167 100644 --- a/src/common/component/Channel.js +++ b/src/common/component/Channel.tsx @@ -1,8 +1,6 @@ -// import React from 'react'; import styled from "styled-components"; -import { useSelector } from "react-redux"; -// import { useNavigate } from "react-router-dom"; import Avatar from "./Avatar"; +import { useAppSelector } from "../../app/store"; const StyledWrapper = styled.div` display: flex; @@ -23,8 +21,8 @@ const StyledWrapper = styled.div` } .avatar { cursor: pointer; - width: ${({ size }) => `${size}px`}; - height: ${({ size }) => `${size}px`}; + width: ${({ size }: { size: number }) => `${size}px`}; + height: ${({ size }: { size: number }) => `${size}px`}; position: relative; img { border-radius: 50%; @@ -47,8 +45,9 @@ const StyledWrapper = styled.div` } } `; + export default function Channel({ interactive = true, id = "", compact = false, avatarSize = 32 }) { - const { channel, totalMemberCount } = useSelector((store) => { + const { channel, totalMemberCount } = useAppSelector((store) => { return { channel: store.channels.byId[id], totalMemberCount: store.contacts.ids.length diff --git a/src/common/component/ChannelIcon.js b/src/common/component/ChannelIcon.tsx similarity index 63% rename from src/common/component/ChannelIcon.js rename to src/common/component/ChannelIcon.tsx index fcb1b8d6..b469f1ec 100644 --- a/src/common/component/ChannelIcon.js +++ b/src/common/component/ChannelIcon.tsx @@ -1,17 +1,27 @@ -// import React from 'react'; +import { FC } from "react"; +import styled from "styled-components"; import HashIcon from "../../assets/icons/channel.svg"; import LockHashIcon from "../../assets/icons/channel.private.svg"; -import styled from "styled-components"; + +interface Props { + personal?: boolean; + muted?: boolean; + className: string; +} + const Styled = styled.div` display: flex; &.muted path { fill: #d0d5dd; } `; -export default function ChannelIcon({ personal = false, muted = false, className }) { + +const ChannelIcon: FC = ({ personal = false, muted = false, className }) => { return ( {personal ? : } ); -} +}; + +export default ChannelIcon; diff --git a/src/common/component/ChannelModal/index.js b/src/common/component/ChannelModal/index.tsx similarity index 96% rename from src/common/component/ChannelModal/index.js rename to src/common/component/ChannelModal/index.tsx index e9d22b13..cf61127b 100644 --- a/src/common/component/ChannelModal/index.js +++ b/src/common/component/ChannelModal/index.tsx @@ -1,20 +1,20 @@ import { useState, useEffect } from "react"; import toast from "react-hot-toast"; import { useNavigate } from "react-router-dom"; -import { useSelector } from "react-redux"; import Modal from "../Modal"; import Button from "../styled/Button"; import ChannelIcon from "../ChannelIcon"; import Contact from "../Contact"; import StyledWrapper from "./styled"; // import StyledToggle from "../../component/styled/Toggle"; -import StyledCheckbox from "../../component/styled/Checkbox"; +import StyledCheckbox from "../styled/Checkbox"; import useFilteredUsers from "../../hook/useFilteredUsers"; import { useCreateChannelMutation } from "../../../app/services/channel"; +import { useAppSelector } from "../../../app/store"; export default function ChannelModal({ personal = false, closeModal }) { - const { conactsData, loginUid } = useSelector((store) => { + const { conactsData, loginUid } = useAppSelector((store) => { return { conactsData: store.contacts.byId, loginUid: store.authData.uid }; }); const navigateTo = useNavigate(); diff --git a/src/common/component/ChannelModal/styled.js b/src/common/component/ChannelModal/styled.tsx similarity index 100% rename from src/common/component/ChannelModal/styled.js rename to src/common/component/ChannelModal/styled.tsx diff --git a/src/common/component/Contact/ContextMenu.js b/src/common/component/Contact/ContextMenu.tsx similarity index 94% rename from src/common/component/Contact/ContextMenu.js rename to src/common/component/Contact/ContextMenu.tsx index cd70ed15..f4401258 100644 --- a/src/common/component/Contact/ContextMenu.js +++ b/src/common/component/Contact/ContextMenu.tsx @@ -1,6 +1,4 @@ -// import { useState } from "react"; import Tippy from "@tippyjs/react"; -// import { useDispatch } from "react-redux"; import useContactOperation from "../../hook/useContactOperation"; import ContextMenu from "../ContextMenu"; diff --git a/src/common/component/Contact/index.js b/src/common/component/Contact/index.tsx similarity index 92% rename from src/common/component/Contact/index.js rename to src/common/component/Contact/index.tsx index 63c98f5b..0019ac4c 100644 --- a/src/common/component/Contact/index.js +++ b/src/common/component/Contact/index.tsx @@ -1,5 +1,3 @@ -// import React from "react"; -import { useSelector } from "react-redux"; import { useNavigate } from "react-router-dom"; import Tippy from "@tippyjs/react"; import IconOwner from "../../../assets/icons/owner.svg"; @@ -8,6 +6,8 @@ import Profile from "../Profile"; import ContextMenu from "./ContextMenu"; import StyledWrapper from "./styled"; import useContextMenu from "../../hook/useContextMenu"; +import { useAppSelector } from "../../../app/store"; + export default function Contact({ cid = null, owner = false, @@ -21,7 +21,7 @@ export default function Contact({ }) { const navigate = useNavigate(); const { visible: contextMenuVisible, handleContextMenuEvent, hideContextMenu } = useContextMenu(); - const curr = useSelector((store) => store.contacts.byId[uid]); + const curr = useAppSelector((store) => store.contacts.byId[uid]); const handleDoubleClick = () => { navigate(`/chat/dm/${uid}`); }; diff --git a/src/common/component/Contact/styled.js b/src/common/component/Contact/styled.tsx similarity index 90% rename from src/common/component/Contact/styled.js rename to src/common/component/Contact/styled.tsx index d6d9a975..1d7879b6 100644 --- a/src/common/component/Contact/styled.js +++ b/src/common/component/Contact/styled.tsx @@ -17,8 +17,8 @@ const StyledWrapper = styled.div` } .avatar { cursor: pointer; - width: ${({ size }) => `${size}px`}; - height: ${({ size }) => `${size}px`}; + width: ${({ size }: { size: number }) => `${size}px`}; + height: ${({ size }: { size: number }) => `${size}px`}; position: relative; img { object-fit: cover; @@ -62,4 +62,5 @@ const StyledWrapper = styled.div` } } `; + export default StyledWrapper; diff --git a/src/common/component/ContactsModal.js b/src/common/component/ContactsModal.tsx similarity index 82% rename from src/common/component/ContactsModal.js rename to src/common/component/ContactsModal.tsx index 85a064f7..74fec1cd 100644 --- a/src/common/component/ContactsModal.js +++ b/src/common/component/ContactsModal.tsx @@ -1,4 +1,4 @@ -import { useRef } from "react"; +import { ChangeEvent, useRef, FC } from "react"; import styled from "styled-components"; import { NavLink } from "react-router-dom"; import { useOutsideClick } from "rooks"; @@ -13,12 +13,12 @@ const StyledWrapper = styled.div` width: 440px; max-height: 402px; background: #fff; - box-shadow: 0px 25px 50px rgba(31, 41, 55, 0.25); + box-shadow: 0 25px 50px rgba(31, 41, 55, 0.25); border-radius: 8px; transition: all 0.5s ease; /* overflow-y: scroll; */ .search { - box-shadow: 0px 1px 0px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.1); padding: 8px; width: -webkit-fill-available; input { @@ -51,12 +51,17 @@ const StyledWrapper = styled.div` } } `; -export default function ContactsModal({ closeModal }) { - const wrapperRef = useRef(); + +interface Props { + closeModal: () => void; +} + +const ContactsModal: FC = ({ closeModal }) => { + const wrapperRef = useRef(null); const { contacts, updateInput, input } = useFilteredUsers(); useOutsideClick(wrapperRef, closeModal); - const handleSearch = (evt) => { - console.log("www"); + + const handleSearch = (evt: ChangeEvent) => { updateInput(evt.target.value); }; @@ -83,4 +88,6 @@ export default function ContactsModal({ closeModal }) { ); -} +}; + +export default ContactsModal; diff --git a/src/common/component/ContextMenu.js b/src/common/component/ContextMenu.tsx similarity index 72% rename from src/common/component/ContextMenu.js rename to src/common/component/ContextMenu.tsx index 279c26f2..ab20a953 100644 --- a/src/common/component/ContextMenu.js +++ b/src/common/component/ContextMenu.tsx @@ -1,7 +1,20 @@ -// import { useRef } from "react"; -// import styled from "styled-components"; +import { FC, MouseEvent } from "react"; import StyledMenu from "./styled/Menu"; -export default function ContextMenu({ items = [], hideMenu = null }) { + +interface Item { + title: string; + icon: string; + handler: (e: MouseEvent) => void; + underline?: boolean; + danger?: boolean; +} + +interface Props { + items: Item[]; + hideMenu?: () => void; +} + +const ContextMenu: FC = ({ items = [], hideMenu = null }) => { return ( {items.map((item) => { @@ -38,4 +51,6 @@ export default function ContextMenu({ items = [], hideMenu = null }) { })} ); -} +}; + +export default ContextMenu; diff --git a/src/common/component/CurrentUser.js b/src/common/component/CurrentUser.tsx similarity index 94% rename from src/common/component/CurrentUser.js rename to src/common/component/CurrentUser.tsx index c73add01..710b6c78 100644 --- a/src/common/component/CurrentUser.js +++ b/src/common/component/CurrentUser.tsx @@ -1,11 +1,11 @@ -// import { useEffect } from "react"; import styled from "styled-components"; import { useSelector } from "react-redux"; import soundIcon from "../../assets/icons/sound.on.svg?url"; import micIcon from "../../assets/icons/mic.on.svg?url"; import Avatar from "./Avatar"; import useConfig from "../hook/useConfig"; -// import UserGuide from "./UserGuide"; +import { useAppSelector } from "../../app/store"; + const StyledWrapper = styled.div` background-color: #f4f4f5; position: sticky; @@ -61,9 +61,10 @@ const StyledWrapper = styled.div` } } `; + export default function CurrentUser() { const { values: agoraConfig } = useConfig("agora"); - const currUser = useSelector((store) => { + const currUser = useAppSelector((store) => { return store.contacts.byId[store.authData.uid]; }); diff --git a/src/common/component/DeleteMessageConfirm.js b/src/common/component/DeleteMessageConfirm.tsx similarity index 83% rename from src/common/component/DeleteMessageConfirm.js rename to src/common/component/DeleteMessageConfirm.tsx index 37d7dae0..300c5399 100644 --- a/src/common/component/DeleteMessageConfirm.js +++ b/src/common/component/DeleteMessageConfirm.tsx @@ -1,11 +1,16 @@ -// import React from "react"; -import { useState } from "react"; +import { FC, useState } from "react"; import useDeleteMessage from "../hook/useDeleteMessage"; import StyledModal from "./styled/Modal"; import Button from "./styled/Button"; import Modal from "./Modal"; import PreviewMessage from "./Message/PreviewMessage"; -export default function DeleteMessageConfirmModal({ closeModal, mids = [] }) { + +interface Props { + closeModal: (b: boolean) => void; + mids?: number[] | number; +} + +const DeleteMessageConfirmModal: FC = ({ closeModal, mids = [] }) => { // const dispatch = useDispatch(); const mid_arr = mids ? (Array.isArray(mids) ? mids : [mids]) : []; const [ids] = useState(mid_arr); @@ -39,4 +44,6 @@ export default function DeleteMessageConfirmModal({ closeModal, mids = [] }) { ); -} +}; + +export default DeleteMessageConfirmModal; diff --git a/src/common/component/Divider.js b/src/common/component/Divider.tsx similarity index 80% rename from src/common/component/Divider.js rename to src/common/component/Divider.tsx index 954af990..ca1307ab 100644 --- a/src/common/component/Divider.js +++ b/src/common/component/Divider.tsx @@ -1,5 +1,6 @@ -// import React from "react"; import styled from "styled-components"; +import { FC } from "react"; + const StyledDivider = styled.hr` display: block; position: relative; @@ -21,7 +22,14 @@ const StyledDivider = styled.hr` color: #78787c; } `; -export default function Divider({ content }) { + +interface Props { + content: string; +} + +const Divider: FC = ({ content }) => { if (!content) return null; return ; -} +}; + +export default Divider; diff --git a/src/common/component/EmojiPicker.js b/src/common/component/EmojiPicker.tsx similarity index 80% rename from src/common/component/EmojiPicker.js rename to src/common/component/EmojiPicker.tsx index a0eb8b74..54e24555 100644 --- a/src/common/component/EmojiPicker.js +++ b/src/common/component/EmojiPicker.tsx @@ -1,9 +1,13 @@ -import { useState, useEffect } from "react"; -// import { NimblePicker } from "emoji-mart"; +import { useState, useEffect, FC } from "react"; +import { EmojiData } from "emoji-mart"; import "emoji-mart/css/emoji-mart.css"; import { Picker } from "emoji-mart"; -// import data from "emoji-mart/data/"; import styled from "styled-components"; + +interface Props { + onSelect: (emoji: EmojiData) => void; +} + const StyledWrapper = styled.div` filter: drop-shadow(0px 25px 50px rgba(31, 41, 55, 0.25)); border-radius: 12px; @@ -20,7 +24,8 @@ const StyledWrapper = styled.div` } } `; -export default function EmojiPicker({ onSelect, ...rest }) { + +const EmojiPicker: FC = ({ onSelect, ...rest }) => { const [visible, setVisible] = useState(false); useEffect(() => { const inter = setTimeout(() => { @@ -49,4 +54,6 @@ export default function EmojiPicker({ onSelect, ...rest }) { ) : null} ); -} +}; + +export default EmojiPicker; diff --git a/src/common/component/FAQ.js b/src/common/component/FAQ.tsx similarity index 95% rename from src/common/component/FAQ.js rename to src/common/component/FAQ.tsx index 941a569d..1cf26f7f 100644 --- a/src/common/component/FAQ.js +++ b/src/common/component/FAQ.tsx @@ -1,11 +1,12 @@ -// import React from "react"; import styled from "styled-components"; import { useGetServerVersionQuery } from "../../app/services/server"; + const Styled = styled.div` display: flex; flex-direction: column; gap: 12px; `; + export default function FAQ() { const { data: serverVersion } = useGetServerVersionQuery(); console.log("build time", serverVersion); diff --git a/src/common/component/FileBox/index.js b/src/common/component/FileBox/index.tsx similarity index 99% rename from src/common/component/FileBox/index.js rename to src/common/component/FileBox/index.tsx index 053cd4b0..0367d3f4 100644 --- a/src/common/component/FileBox/index.js +++ b/src/common/component/FileBox/index.tsx @@ -13,7 +13,10 @@ import { } from "./preview"; import { getFileIcon, formatBytes } from "../../utils"; import IconDownload from "../../../assets/icons/download.svg"; + +// todo dayjs.extend(relativeTime); + const renderPreview = (data) => { const { file_type, name, content } = data; let preview = null; diff --git a/src/common/component/FileBox/preview/Audio.js b/src/common/component/FileBox/preview/Audio.tsx similarity index 83% rename from src/common/component/FileBox/preview/Audio.js rename to src/common/component/FileBox/preview/Audio.tsx index 3373f4b0..5ca105c1 100644 --- a/src/common/component/FileBox/preview/Audio.js +++ b/src/common/component/FileBox/preview/Audio.tsx @@ -1,5 +1,6 @@ -import { useState } from "react"; +import { ReactEventHandler, useState } from "react"; import styled from "styled-components"; + const Styled = styled.div` height: 100%; display: flex; @@ -15,12 +16,15 @@ const Styled = styled.div` width: 100%; } `; + export default function Audio({ url = "" }) { const [err, setErr] = useState(false); - const handleError = (err) => { + + const handleError: ReactEventHandler = (err) => { console.log("audio err", err); setErr(true); }; + if (!url) return null; return ( diff --git a/src/common/component/FileBox/preview/Code.js b/src/common/component/FileBox/preview/Code.tsx similarity index 90% rename from src/common/component/FileBox/preview/Code.js rename to src/common/component/FileBox/preview/Code.tsx index 837f32f1..dcf4ccab 100644 --- a/src/common/component/FileBox/preview/Code.js +++ b/src/common/component/FileBox/preview/Code.tsx @@ -1,7 +1,7 @@ import { useState, useEffect } from "react"; import styled from "styled-components"; + const Styled = styled.div` - background-color: #fff; height: 218px; padding: 15px 15px 0 15px; line-height: 1.4; @@ -11,10 +11,11 @@ const Styled = styled.div` background-color: #000; color: #eee; `; + export default function Code({ url = "" }) { const [content, setContent] = useState(""); useEffect(() => { - const getContent = async (url) => { + const getContent = async (url: string) => { if (!url) return; const resp = await fetch(url); const txt = await resp.text(); diff --git a/src/common/component/FileBox/preview/Doc.js b/src/common/component/FileBox/preview/Doc.tsx similarity index 92% rename from src/common/component/FileBox/preview/Doc.js rename to src/common/component/FileBox/preview/Doc.tsx index 88bb3349..fa30be86 100644 --- a/src/common/component/FileBox/preview/Doc.js +++ b/src/common/component/FileBox/preview/Doc.tsx @@ -1,5 +1,6 @@ import { useState, useEffect } from "react"; import styled from "styled-components"; + const Styled = styled.div` background-color: #fff; height: 218px; @@ -9,10 +10,11 @@ const Styled = styled.div` white-space: pre-wrap; word-break: break-all; `; + export default function Doc({ url = "" }) { const [content, setContent] = useState(""); useEffect(() => { - const getContent = async (url) => { + const getContent = async (url: string) => { if (!url) return; const resp = await fetch(url); const txt = await resp.text(); diff --git a/src/common/component/FileBox/preview/Image.js b/src/common/component/FileBox/preview/Image.tsx similarity index 99% rename from src/common/component/FileBox/preview/Image.js rename to src/common/component/FileBox/preview/Image.tsx index 808ad53f..35eb5885 100644 --- a/src/common/component/FileBox/preview/Image.js +++ b/src/common/component/FileBox/preview/Image.tsx @@ -1,5 +1,6 @@ import React from "react"; import styled from "styled-components"; + const Styled = styled.div` height: 218px; overflow: hidden; @@ -9,6 +10,7 @@ const Styled = styled.div` object-fit: cover; } `; + export default function Image({ url = "" }) { if (!url) return null; return ( diff --git a/src/common/component/FileBox/preview/Pdf.js b/src/common/component/FileBox/preview/Pdf.tsx similarity index 88% rename from src/common/component/FileBox/preview/Pdf.js rename to src/common/component/FileBox/preview/Pdf.tsx index 4bba26c7..e4335b62 100644 --- a/src/common/component/FileBox/preview/Pdf.js +++ b/src/common/component/FileBox/preview/Pdf.tsx @@ -1,6 +1,5 @@ -// import { useState, useEffect } from "react"; import styled from "styled-components"; -// import { Document, Page } from "react-pdf"; + const Styled = styled.div` padding: 8px; /* height: 218px; */ @@ -10,6 +9,7 @@ const Styled = styled.div` height: 100%; } `; + export default function Pdf({ url = "" }) { // const [content, setContent] = useState(""); // const [pageNumber, setPageNumber] = useState(1); diff --git a/src/common/component/FileBox/preview/Video.js b/src/common/component/FileBox/preview/Video.tsx similarity index 99% rename from src/common/component/FileBox/preview/Video.js rename to src/common/component/FileBox/preview/Video.tsx index 7ef39c7e..c746c66e 100644 --- a/src/common/component/FileBox/preview/Video.js +++ b/src/common/component/FileBox/preview/Video.tsx @@ -1,5 +1,6 @@ import React from "react"; import styled from "styled-components"; + const Styled = styled.div` height: 218px; video { @@ -8,6 +9,7 @@ const Styled = styled.div` object-fit: cover; } `; + export default function Video({ url = "" }) { if (!url) return null; return ( diff --git a/src/common/component/FileBox/preview/index.js b/src/common/component/FileBox/preview/index.tsx similarity index 100% rename from src/common/component/FileBox/preview/index.js rename to src/common/component/FileBox/preview/index.tsx diff --git a/src/common/component/FileBox/styled.js b/src/common/component/FileBox/styled.tsx similarity index 99% rename from src/common/component/FileBox/styled.js rename to src/common/component/FileBox/styled.tsx index 6407a62f..2c52730b 100644 --- a/src/common/component/FileBox/styled.js +++ b/src/common/component/FileBox/styled.tsx @@ -1,4 +1,5 @@ import styled from "styled-components"; + const Styled = styled.div` background: #f3f4f6; border: 1px solid #d4d4d4; @@ -67,4 +68,5 @@ const Styled = styled.div` /* todo */ } `; + export default Styled; diff --git a/src/common/component/FileMessage/ImageMessage.js b/src/common/component/FileMessage/ImageMessage.tsx similarity index 99% rename from src/common/component/FileMessage/ImageMessage.js rename to src/common/component/FileMessage/ImageMessage.tsx index 120a49d6..c3c6e16b 100644 --- a/src/common/component/FileMessage/ImageMessage.js +++ b/src/common/component/FileMessage/ImageMessage.tsx @@ -2,6 +2,8 @@ import { useState, useEffect } from "react"; import styled from "styled-components"; import { CircularProgressbar, buildStyles } from "react-circular-progressbar"; import "react-circular-progressbar/dist/styles.css"; +import { getDefaultSize } from "../../utils"; + const Styled = styled.div` position: relative; width: fit-content; @@ -30,7 +32,7 @@ const Styled = styled.div` } } `; -import { getDefaultSize } from "../../utils"; + export default function ImageMessage({ uploading, progress, diff --git a/src/common/component/FileMessage/Progress.js b/src/common/component/FileMessage/Progress.tsx similarity index 69% rename from src/common/component/FileMessage/Progress.js rename to src/common/component/FileMessage/Progress.tsx index bc126cb2..019e391c 100644 --- a/src/common/component/FileMessage/Progress.js +++ b/src/common/component/FileMessage/Progress.tsx @@ -1,5 +1,6 @@ -// import React from 'react' +import { FC } from "react"; import styled from "styled-components"; + const Styled = styled.div` background: #ecfdff; border-radius: 4px; @@ -12,10 +13,18 @@ const Styled = styled.div` border-radius: 4px; } `; -export default function Progress({ value, width = "100%" }) { + +interface Props { + value: number; + width?: string; +} + +const Progress: FC = ({ value, width = "100%" }) => { return (
); -} +}; + +export default Progress; diff --git a/src/common/component/FileMessage/index.js b/src/common/component/FileMessage/index.tsx similarity index 94% rename from src/common/component/FileMessage/index.js rename to src/common/component/FileMessage/index.tsx index 79c319cd..ce80bdd7 100644 --- a/src/common/component/FileMessage/index.js +++ b/src/common/component/FileMessage/index.tsx @@ -9,12 +9,16 @@ import useUploadFile from "../../hook/useUploadFile"; import useSendMessage from "../../hook/useSendMessage"; import Progress from "./Progress"; import { getFileIcon, formatBytes, isImage, getImageSize } from "../../utils"; +// import { ReactComponent as IconDownload } from "../../../assets/icons/download.svg"; +// import { ReactComponent as IconClose } from "../../../assets/icons/close.circle.svg"; import IconDownload from "../../../assets/icons/download.svg"; import IconClose from "../../../assets/icons/close.circle.svg"; +// todo: move to root file dayjs.extend(relativeTime); -const isLocalFile = (content) => { - return content && typeof content == "string" && content.startsWith("blob:"); + +const isLocalFile = (content: string) => { + return content.startsWith("blob:"); }; export default function FileMessage({ diff --git a/src/common/component/FileMessage/styled.js b/src/common/component/FileMessage/styled.tsx similarity index 99% rename from src/common/component/FileMessage/styled.js rename to src/common/component/FileMessage/styled.tsx index 6b987328..043f38e8 100644 --- a/src/common/component/FileMessage/styled.js +++ b/src/common/component/FileMessage/styled.tsx @@ -1,4 +1,5 @@ import styled from "styled-components"; + const Styled = styled.div` background: #f3f4f6; border: 1px solid #d4d4d4; @@ -58,4 +59,5 @@ const Styled = styled.div` } } `; + export default Styled; diff --git a/src/common/component/ForwardModal/index.js b/src/common/component/ForwardModal/index.tsx similarity index 97% rename from src/common/component/ForwardModal/index.js rename to src/common/component/ForwardModal/index.tsx index 66f71559..9bb14657 100644 --- a/src/common/component/ForwardModal/index.js +++ b/src/common/component/ForwardModal/index.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useState, MouseEvent } from "react"; // import toast from "react-hot-toast"; import Modal from "../Modal"; import Button from "../styled/Button"; @@ -13,7 +13,7 @@ import useSendMessage from "../../hook/useSendMessage"; import useFilteredChannels from "../../hook/useFilteredChannels"; import useFilteredUsers from "../../hook/useFilteredUsers"; import CloseIcon from "../../../assets/icons/close.circle.svg"; -import StyledCheckbox from "../../component/styled/Checkbox"; +import StyledCheckbox from "../styled/Checkbox"; import toast from "react-hot-toast"; export default function ForwardModal({ mids, closeModal }) { @@ -31,7 +31,7 @@ export default function ForwardModal({ mids, closeModal }) { // const { conactsData, loginUid } = useSelector((store) => { // return { conactsData: store.contacts.byId, loginUid: store.authData.uid }; // }); - const toggleCheck = ({ currentTarget }) => { + const toggleCheck = ({ currentTarget }: MouseEvent) => { const { id, type = "user" } = currentTarget.dataset; const ids = type == "user" ? selectedMembers : selectedChannels; const updateState = type == "user" ? setSelectedMembers : setSelectedChannels; diff --git a/src/common/component/ForwardModal/styled.js b/src/common/component/ForwardModal/styled.tsx similarity index 100% rename from src/common/component/ForwardModal/styled.js rename to src/common/component/ForwardModal/styled.tsx diff --git a/src/common/component/GithubLoginButton.js b/src/common/component/GithubLoginButton.tsx similarity index 99% rename from src/common/component/GithubLoginButton.js rename to src/common/component/GithubLoginButton.tsx index a0288a3e..b27fe845 100644 --- a/src/common/component/GithubLoginButton.js +++ b/src/common/component/GithubLoginButton.tsx @@ -3,6 +3,7 @@ import IconGithub from "../../assets/icons/github.svg"; import styled from "styled-components"; import Button from "./styled/Button"; + const StyledSocialButton = styled(Button)` width: 100%; margin-bottom: 16px; @@ -18,6 +19,7 @@ const StyledSocialButton = styled(Button)` height: 24px; } `; + export default function GithubLoginButton({ config = {} }) { const { client_id } = config; const handleGithubLogin = () => { diff --git a/src/common/component/GoogleLoginButton.js b/src/common/component/GoogleLoginButton.tsx similarity index 89% rename from src/common/component/GoogleLoginButton.js rename to src/common/component/GoogleLoginButton.tsx index 90c1ba62..9e5fd5c6 100644 --- a/src/common/component/GoogleLoginButton.js +++ b/src/common/component/GoogleLoginButton.tsx @@ -1,11 +1,11 @@ -import { useEffect } from "react"; +import { FC, useEffect } from "react"; import { useGoogleLogin } from "react-google-login"; - -import googleSvg from "../../assets/icons/google.svg?url"; +import toast from "react-hot-toast"; import styled from "styled-components"; +import googleSvg from "../../assets/icons/google.svg?url"; import Button from "./styled/Button"; import { useLoginMutation } from "../../app/services/auth"; -import toast from "react-hot-toast"; + const StyledSocialButton = styled(Button)` width: 100%; margin-bottom: 16px; @@ -21,8 +21,14 @@ const StyledSocialButton = styled(Button)` height: 24px; } `; -export default function GoogleLoginButton({ clientId }) { + +interface Props { + clientId: string; +} + +const GoogleLoginButton: FC = ({ clientId }) => { const [login, { isSuccess, isLoading }] = useLoginMutation(); + const { signIn, loaded } = useGoogleLogin({ onScriptLoadFailure: (wtf) => { console.error("google login script load failure", wtf); @@ -39,6 +45,7 @@ export default function GoogleLoginButton({ clientId }) { console.error("google login failure", wtf); } }); + useEffect(() => { if (isSuccess) { toast.success("Login Successfully"); @@ -48,6 +55,7 @@ export default function GoogleLoginButton({ clientId }) { const handleGoogleLogin = () => { signIn(); }; + // console.log("google login ", loaded); return ( @@ -55,4 +63,6 @@ export default function GoogleLoginButton({ clientId }) { {loaded ? `Sign in with Google` : `Initailizing`} ); -} +}; + +export default GoogleLoginButton; diff --git a/src/common/component/ImagePreviewModal.js b/src/common/component/ImagePreviewModal.tsx similarity index 99% rename from src/common/component/ImagePreviewModal.js rename to src/common/component/ImagePreviewModal.tsx index 415ca87b..22c97db1 100644 --- a/src/common/component/ImagePreviewModal.js +++ b/src/common/component/ImagePreviewModal.tsx @@ -3,6 +3,7 @@ import styled, { keyframes } from "styled-components"; import { useOutsideClick, useKey } from "rooks"; import { Ring } from "@uiball/loaders"; import Modal from "./Modal"; + const AniFadeIn = keyframes` from{ background: transparent; @@ -11,6 +12,7 @@ to{ background: rgba(1, 1, 1, 0.9); } `; + const StyledWrapper = styled.div` /* todo */ transition: all 0.5s ease; @@ -58,6 +60,7 @@ const StyledWrapper = styled.div` } } `; + export default function ImagePreviewModal({ download = true, data, closeModal }) { const [url, setUrl] = useState(data?.thumbnail); const [loading, setLoading] = useState(true); diff --git a/src/common/component/InviteLink.js b/src/common/component/InviteLink.tsx similarity index 97% rename from src/common/component/InviteLink.js rename to src/common/component/InviteLink.tsx index bfe239d3..8dba8dbb 100644 --- a/src/common/component/InviteLink.js +++ b/src/common/component/InviteLink.tsx @@ -1,8 +1,8 @@ -// import { useEffect } from "react"; import styled from "styled-components"; import useInviteLink from "../hook/useInviteLink"; import Input from "./styled/Input"; import Button from "./styled/Button"; + const StyledWrapper = styled.div` display: flex; flex-direction: column; @@ -37,11 +37,13 @@ const StyledWrapper = styled.div` margin-bottom: 20px; } `; + export default function InviteLink() { const { generating, link, linkCopied, copyLink, generateNewLink } = useInviteLink(); const handleNewLink = () => { generateNewLink(); }; + return ( Share this link to invite people to this server. diff --git a/src/common/component/InviteModal/AddMembers.js b/src/common/component/InviteModal/AddMembers.tsx similarity index 98% rename from src/common/component/InviteModal/AddMembers.js rename to src/common/component/InviteModal/AddMembers.tsx index 1aab1359..82d0aa5b 100644 --- a/src/common/component/InviteModal/AddMembers.js +++ b/src/common/component/InviteModal/AddMembers.tsx @@ -1,14 +1,14 @@ import { useState, useEffect } from "react"; import styled from "styled-components"; import { useSelector } from "react-redux"; +import toast from "react-hot-toast"; import Button from "../styled/Button"; import Input from "../styled/Input"; import Contact from "../Contact"; import StyledCheckbox from "../styled/Checkbox"; import { useAddMembersMutation } from "../../../app/services/channel"; import CloseIcon from "../../../assets/icons/close.svg"; -import toast from "react-hot-toast"; -import useFilteredUsers from "../../../common/hook/useFilteredUsers"; +import useFilteredUsers from "../../hook/useFilteredUsers"; const Styled = styled.div` padding-top: 16px; diff --git a/src/common/component/InviteModal/InviteByEmail.js b/src/common/component/InviteModal/InviteByEmail.tsx similarity index 95% rename from src/common/component/InviteModal/InviteByEmail.js rename to src/common/component/InviteModal/InviteByEmail.tsx index 054691cc..ca07b5f8 100644 --- a/src/common/component/InviteModal/InviteByEmail.js +++ b/src/common/component/InviteModal/InviteByEmail.tsx @@ -1,7 +1,10 @@ -import { useEffect, useState } from "react"; +import { useEffect, useState, ChangeEvent } from "react"; import toast from "react-hot-toast"; import styled from "styled-components"; import useInviteLink from "../../hook/useInviteLink"; +import Button from "../styled/Button"; +import Input from "../styled/Input"; + const Styled = styled.div` padding: 16px 0; .input { @@ -64,8 +67,7 @@ const Styled = styled.div` } } `; -import Button from "../styled/Button"; -import Input from "../styled/Input"; + export default function InviteByEmail({ cid = null }) { const [email, setEmail] = useState(""); const { enableSMTP, linkCopied, link, copyLink, generateNewLink, generating } = @@ -75,9 +77,11 @@ export default function InviteByEmail({ cid = null }) { toast.success("Invite Link Copied!"); } }, [linkCopied]); - const handleEmail = (evt) => { + + const handleEmail = (evt: ChangeEvent) => { setEmail(evt.target.value); }; + return (
diff --git a/src/common/component/InviteModal/index.js b/src/common/component/InviteModal/index.tsx similarity index 91% rename from src/common/component/InviteModal/index.js rename to src/common/component/InviteModal/index.tsx index d7dd1142..b58b0282 100644 --- a/src/common/component/InviteModal/index.js +++ b/src/common/component/InviteModal/index.tsx @@ -1,9 +1,10 @@ -// import React from 'react' import styled from "styled-components"; -import { useSelector } from "react-redux"; import InviteByEmail from "./InviteByEmail"; import AddMembers from "./AddMembers"; import CloseIcon from "../../../assets/icons/close.svg"; +import Modal from "../Modal"; +import { useAppSelector } from "../../../app/store"; + const Styled = styled.div` display: flex; flex-direction: column; @@ -26,10 +27,10 @@ const Styled = styled.div` } } `; -import Modal from "../Modal"; + // type: server,channel export default function InviteModal({ type = "server", cid = null, title = "", closeModal }) { - const { channel, server } = useSelector((store) => { + const { channel, server } = useAppSelector((store) => { return { channel: store.channels.byId[cid], server: store.server diff --git a/src/common/component/LeaveChannel/LeaveConfirmModal.js b/src/common/component/LeaveChannel/LeaveConfirmModal.tsx similarity index 85% rename from src/common/component/LeaveChannel/LeaveConfirmModal.js rename to src/common/component/LeaveChannel/LeaveConfirmModal.tsx index d6d71d4d..7c0610dd 100644 --- a/src/common/component/LeaveChannel/LeaveConfirmModal.js +++ b/src/common/component/LeaveChannel/LeaveConfirmModal.tsx @@ -1,4 +1,4 @@ -import { useEffect } from "react"; +import { useEffect, FC } from "react"; import toast from "react-hot-toast"; import { useNavigate } from "react-router-dom"; import useLeaveChannel from "../../hook/useLeaveChannel"; @@ -6,7 +6,13 @@ import Modal from "../Modal"; import StyledModal from "../styled/Modal"; import Button from "../styled/Button"; -export default function LeaveConfirmModal({ id, closeModal, handleNextStep }) { +interface Props { + id: number; + closeModal: () => void; + handleNextStep: () => void; +} + +const LeaveConfirmModal: FC = ({ id, closeModal, handleNextStep }) => { const navigateTo = useNavigate(); const { isOwner, leaving, leaveChannel, leaveSuccess } = useLeaveChannel(id); @@ -47,4 +53,6 @@ export default function LeaveConfirmModal({ id, closeModal, handleNextStep }) { > ); -} +}; + +export default LeaveConfirmModal; diff --git a/src/common/component/LeaveChannel/TransferOwnerModal.js b/src/common/component/LeaveChannel/TransferOwnerModal.tsx similarity index 90% rename from src/common/component/LeaveChannel/TransferOwnerModal.js rename to src/common/component/LeaveChannel/TransferOwnerModal.tsx index 871e4254..4b412e47 100644 --- a/src/common/component/LeaveChannel/TransferOwnerModal.js +++ b/src/common/component/LeaveChannel/TransferOwnerModal.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect, useState, FC } from "react"; import toast from "react-hot-toast"; import styled from "styled-components"; import { useNavigate } from "react-router-dom"; @@ -7,6 +7,7 @@ import useLeaveChannel from "../../hook/useLeaveChannel"; import StyledModal from "../styled/Modal"; import Button from "../styled/Button"; import Contact from "../Contact"; + const UserList = styled.ul` display: flex; flex-direction: column; @@ -28,7 +29,14 @@ const UserList = styled.ul` } } `; -export default function TransferOwnerModal({ id, closeModal, withLeave = true }) { + +interface Props { + id: number; + closeModal: () => void; + withLeave?: boolean; +} + +const TransferOwnerModal: FC = ({ id, closeModal, withLeave = true }) => { const { transferOwner, otherMembers, @@ -97,4 +105,6 @@ export default function TransferOwnerModal({ id, closeModal, withLeave = true }) ); -} +}; + +export default TransferOwnerModal; diff --git a/src/common/component/LeaveChannel/index.js b/src/common/component/LeaveChannel/index.tsx similarity index 64% rename from src/common/component/LeaveChannel/index.js rename to src/common/component/LeaveChannel/index.tsx index 07caa255..bb60d25c 100644 --- a/src/common/component/LeaveChannel/index.js +++ b/src/common/component/LeaveChannel/index.tsx @@ -1,12 +1,20 @@ -import { useState } from "react"; -// import styled from "styled-components"; +import { useState, FC } from "react"; import TransferOwnerModal from "./TransferOwnerModal"; import LeaveConfirmModal from "./LeaveConfirmModal"; -export default function LeaveChannel({ id = null, isOwner = false, closeModal }) { + +interface Props { + id: number; + isOwner?: boolean; + closeModal: () => void; +} + +const LeaveChannel: FC = ({ id, isOwner = false, closeModal }) => { const [transferOwner, setTransferOwner] = useState(isOwner); const handleNextStep = () => { setTransferOwner(true); }; if (transferOwner) return ; return ; -} +}; + +export default LeaveChannel; diff --git a/src/common/component/Loading.js b/src/common/component/Loading.tsx similarity index 96% rename from src/common/component/Loading.js rename to src/common/component/Loading.tsx index 58c0ccf9..d98316c5 100644 --- a/src/common/component/Loading.js +++ b/src/common/component/Loading.tsx @@ -1,9 +1,9 @@ // import { useState, useEffect } from "react"; import styled, { keyframes } from "styled-components"; import { Ring } from "@uiball/loaders"; - import Button from "./styled/Button"; import useLogout from "../hook/useLogout"; + const DelayVisible = keyframes` from{ opacity: 0; @@ -12,6 +12,7 @@ to{ opacity: 1; } `; + const StyledWrapper = styled.div` width: 100%; height: 100%; @@ -37,12 +38,15 @@ const StyledWrapper = styled.div` } } `; + export default function Loading({ reload = false, fullscreen = false }) { const { clearLocalData } = useLogout(); const handleReload = () => { clearLocalData(); + // todo: only firefox has argument location.reload(true); }; + return ( diff --git a/src/common/component/ManageMembers.js b/src/common/component/ManageMembers.tsx similarity index 98% rename from src/common/component/ManageMembers.js rename to src/common/component/ManageMembers.tsx index 46d04d9f..f94a63b9 100644 --- a/src/common/component/ManageMembers.js +++ b/src/common/component/ManageMembers.tsx @@ -1,9 +1,7 @@ import { useEffect } from "react"; import styled from "styled-components"; - import Tippy from "@tippyjs/react"; import { hideAll } from "tippy.js"; -import { useSelector } from "react-redux"; import toast from "react-hot-toast"; import { useUpdateContactMutation } from "../../app/services/contact"; import Contact from "./Contact"; @@ -14,6 +12,8 @@ import IconOwner from "../../assets/icons/owner.svg"; import IconArrowDown from "../../assets/icons/arrow.down.mini.svg"; import IconCheck from "../../assets/icons/check.sign.svg"; import useContactOperation from "../hook/useContactOperation"; +import { useAppSelector } from "../../app/store"; + const StyledWrapper = styled.section` display: flex; flex-direction: column; @@ -114,8 +114,9 @@ const StyledWrapper = styled.section` } } `; + export default function ManageMembers({ cid = null }) { - const { contacts, channels, loginUser } = useSelector((store) => { + const { contacts, channels, loginUser } = useAppSelector((store) => { return { contacts: store.contacts, channels: store.channels, diff --git a/src/common/component/Manifest/Prompt.js b/src/common/component/Manifest/Prompt.tsx similarity index 79% rename from src/common/component/Manifest/Prompt.js rename to src/common/component/Manifest/Prompt.tsx index 0404eedd..b59e9617 100644 --- a/src/common/component/Manifest/Prompt.js +++ b/src/common/component/Manifest/Prompt.tsx @@ -1,8 +1,10 @@ -// import React from "react"; +import { FC } from "react"; import styled from "styled-components"; import Modal from "../Modal"; import IconClose from "../../../assets/icons/close.svg"; -import Button from "../../component/styled/Button"; +// import { ReactComponent as IconClose } from "../../../assets/icons/close.svg"; +import Button from "../styled/Button"; + const Styled = styled.div` position: relative; margin-top: 15px; @@ -11,7 +13,7 @@ const Styled = styled.div` padding: 16px; border-radius: 6px; background: #fff; - box-shadow: 0px 25px 50px rgba(31, 41, 55, 0.25); + box-shadow: 0 25px 50px rgba(31, 41, 55, 0.25); display: flex; flex-direction: column; gap: 12px; @@ -44,7 +46,13 @@ const Styled = styled.div` right: 16px; } `; -export default function Prompt({ handleInstall, closePrompt }) { + +interface Props { + handleInstall?: () => void; + closePrompt?: () => void; +} + +const Prompt: FC = ({ handleInstall, closePrompt }) => { return ( @@ -64,4 +72,6 @@ export default function Prompt({ handleInstall, closePrompt }) { ); -} +}; + +export default Prompt; diff --git a/src/common/component/Manifest/index.js b/src/common/component/Manifest/index.tsx similarity index 95% rename from src/common/component/Manifest/index.js rename to src/common/component/Manifest/index.tsx index e4b188b0..379430a3 100644 --- a/src/common/component/Manifest/index.js +++ b/src/common/component/Manifest/index.tsx @@ -1,6 +1,4 @@ import { useEffect, useState, useRef } from "react"; -// import { useGetServerQuery } from "../../../app/services/server"; -// import manifest from "./manifest.json"; import Prompt from "./Prompt"; import usePrompt from "./usePrompt"; diff --git a/src/common/component/Manifest/usePrompt.js b/src/common/component/Manifest/usePrompt.tsx similarity index 99% rename from src/common/component/Manifest/usePrompt.js rename to src/common/component/Manifest/usePrompt.tsx index 90ec78e1..0278c069 100644 --- a/src/common/component/Manifest/usePrompt.js +++ b/src/common/component/Manifest/usePrompt.tsx @@ -1,5 +1,6 @@ // import React from "react"; import { KEY_PWA_INSTALLED } from "../../../app/config"; + export default function usePrompt() { const resetPrompt = () => { localStorage.removeItem(KEY_PWA_INSTALLED); diff --git a/src/common/component/MarkdownEditor/index.js b/src/common/component/MarkdownEditor/index.tsx similarity index 97% rename from src/common/component/MarkdownEditor/index.js rename to src/common/component/MarkdownEditor/index.tsx index 4b992aa5..90c99b2d 100644 --- a/src/common/component/MarkdownEditor/index.js +++ b/src/common/component/MarkdownEditor/index.tsx @@ -8,7 +8,7 @@ import codeSyntaxHighlight from "@toast-ui/editor-plugin-code-syntax-highlight/d import StyledWrapper from "./styled"; import useUploadFile from "../../hook/useUploadFile"; -import Button from "../../component/styled/Button"; +import Button from "../styled/Button"; function MarkdownEditor({ updateDraft = null, diff --git a/src/common/component/MarkdownEditor/styled.js b/src/common/component/MarkdownEditor/styled.tsx similarity index 99% rename from src/common/component/MarkdownEditor/styled.js rename to src/common/component/MarkdownEditor/styled.tsx index dc69e444..ddca896d 100644 --- a/src/common/component/MarkdownEditor/styled.js +++ b/src/common/component/MarkdownEditor/styled.tsx @@ -1,4 +1,5 @@ import styled from "styled-components"; + const StyledWrapper = styled.div` position: relative; width: 100%; diff --git a/src/common/component/MarkdownStyleOverride.ts b/src/common/component/MarkdownStyleOverride.tsx similarity index 100% rename from src/common/component/MarkdownStyleOverride.ts rename to src/common/component/MarkdownStyleOverride.tsx diff --git a/src/common/component/Message/Commands.js b/src/common/component/Message/Commands.tsx similarity index 98% rename from src/common/component/Message/Commands.js rename to src/common/component/Message/Commands.tsx index 2b2816d4..7b2aceef 100644 --- a/src/common/component/Message/Commands.js +++ b/src/common/component/Message/Commands.tsx @@ -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, diff --git a/src/common/component/Message/ContextMenu.js b/src/common/component/Message/ContextMenu.tsx similarity index 98% rename from src/common/component/Message/ContextMenu.js rename to src/common/component/Message/ContextMenu.tsx index bea96344..1cd00af1 100644 --- a/src/common/component/Message/ContextMenu.js +++ b/src/common/component/Message/ContextMenu.tsx @@ -1,4 +1,3 @@ -// import { useState } from "react"; import Tippy from "@tippyjs/react"; import { useDispatch } from "react-redux"; import ContextMenu from "../ContextMenu"; diff --git a/src/common/component/Message/EditMessage.js b/src/common/component/Message/EditMessage.tsx similarity index 98% rename from src/common/component/Message/EditMessage.js rename to src/common/component/Message/EditMessage.tsx index 020a1e87..609e5f97 100644 --- a/src/common/component/Message/EditMessage.js +++ b/src/common/component/Message/EditMessage.tsx @@ -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(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 (
diff --git a/src/common/component/Message/FavoritedMessage.js b/src/common/component/Message/FavoritedMessage.tsx similarity index 98% rename from src/common/component/Message/FavoritedMessage.js rename to src/common/component/Message/FavoritedMessage.tsx index 899c5713..d31e0393 100644 --- a/src/common/component/Message/FavoritedMessage.js +++ b/src/common/component/Message/FavoritedMessage.tsx @@ -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); diff --git a/src/common/component/Message/ForwardedMessage.js b/src/common/component/Message/ForwardedMessage.tsx similarity index 99% rename from src/common/component/Message/ForwardedMessage.js rename to src/common/component/Message/ForwardedMessage.tsx index 73dc04b4..16315af5 100644 --- a/src/common/component/Message/ForwardedMessage.js +++ b/src/common/component/Message/ForwardedMessage.tsx @@ -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; diff --git a/src/common/component/Message/Mention.js b/src/common/component/Message/Mention.tsx similarity index 62% rename from src/common/component/Message/Mention.js rename to src/common/component/Message/Mention.tsx index 444dc966..86041554 100644 --- a/src/common/component/Message/Mention.js +++ b/src/common/component/Message/Mention.tsx @@ -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 = ({ 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 }) {`@${user.name}`} ); -} +}; + +export default Mention; diff --git a/src/common/component/Message/PinMessageModal.js b/src/common/component/Message/PinMessageModal.tsx similarity index 84% rename from src/common/component/Message/PinMessageModal.js rename to src/common/component/Message/PinMessageModal.tsx index d2e4f9cf..170f8e8c 100644 --- a/src/common/component/Message/PinMessageModal.js +++ b/src/common/component/Message/PinMessageModal.tsx @@ -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 = ({ 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 }) { ); -} +}; + +export default PinMessageModal; diff --git a/src/common/component/Message/PreviewMessage.js b/src/common/component/Message/PreviewMessage.tsx similarity index 86% rename from src/common/component/Message/PreviewMessage.js rename to src/common/component/Message/PreviewMessage.tsx index 9ccaff95..7e9153a8 100644 --- a/src/common/component/Message/PreviewMessage.js +++ b/src/common/component/Message/PreviewMessage.tsx @@ -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; diff --git a/src/common/component/Message/Reaction.js b/src/common/component/Message/Reaction.tsx similarity index 99% rename from src/common/component/Message/Reaction.js rename to src/common/component/Message/Reaction.tsx index 854b5060..c975a3de 100644 --- a/src/common/component/Message/Reaction.js +++ b/src/common/component/Message/Reaction.tsx @@ -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; diff --git a/src/common/component/Message/ReactionPicker.js b/src/common/component/Message/ReactionPicker.tsx similarity index 93% rename from src/common/component/Message/ReactionPicker.js rename to src/common/component/Message/ReactionPicker.tsx index 146e7cd5..b8c46ff9 100644 --- a/src/common/component/Message/ReactionPicker.js +++ b/src/common/component/Message/ReactionPicker.tsx @@ -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 diff --git a/src/common/component/Message/Reply.js b/src/common/component/Message/Reply.tsx similarity index 90% rename from src/common/component/Message/Reply.js rename to src/common/component/Message/Reply.tsx index ad3e6859..7ea472fb 100644 --- a/src/common/component/Message/Reply.js +++ b/src/common/component/Message/Reply.tsx @@ -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 = ({ mid, interactive = true }) => { + const { data, users } = useAppSelector((store) => { return { data: store.message[mid], users: store.contacts.byId }; }); - const handleClick = (evt) => { + const handleClick = (evt: MouseEvent) => { const { mid } = evt.currentTarget.dataset; - const msgEle = document.querySelector(`[data-msg-mid='${mid}']`); + const msgEle = document.querySelector(`[data-msg-mid='${mid}']`); if (msgEle) { msgEle.dataset.highlight = true; msgEle.scrollIntoView({ behavior: "smooth", block: "center" }); diff --git a/src/common/component/Message/URLPreview.js b/src/common/component/Message/URLPreview.tsx similarity index 96% rename from src/common/component/Message/URLPreview.js rename to src/common/component/Message/URLPreview.tsx index e43d30c4..d3f29bd3 100644 --- a/src/common/component/Message/URLPreview.js +++ b/src/common/component/Message/URLPreview.tsx @@ -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; diff --git a/src/common/component/Message/index.js b/src/common/component/Message/index.tsx similarity index 99% rename from src/common/component/Message/index.js rename to src/common/component/Message/index.tsx index 0b65f81d..aa9bfe76 100644 --- a/src/common/component/Message/index.js +++ b/src/common/component/Message/index.tsx @@ -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, diff --git a/src/common/component/Message/renderContent.js b/src/common/component/Message/renderContent.tsx similarity index 99% rename from src/common/component/Message/renderContent.js rename to src/common/component/Message/renderContent.tsx index c3b17c81..6f123777 100644 --- a/src/common/component/Message/renderContent.js +++ b/src/common/component/Message/renderContent.tsx @@ -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, diff --git a/src/common/component/Message/styled.js b/src/common/component/Message/styled.tsx similarity index 99% rename from src/common/component/Message/styled.js rename to src/common/component/Message/styled.tsx index cd4a08b0..0a571d68 100644 --- a/src/common/component/Message/styled.js +++ b/src/common/component/Message/styled.tsx @@ -1,4 +1,5 @@ import styled from "styled-components"; + const StyledMsg = styled.div` position: relative; display: flex; diff --git a/src/common/component/Message/useInView.js b/src/common/component/Message/useInView.ts similarity index 83% rename from src/common/component/Message/useInView.js rename to src/common/component/Message/useInView.ts index 41af38c5..a8230b50 100644 --- a/src/common/component/Message/useInView.js +++ b/src/common/component/Message/useInView.ts @@ -1,7 +1,7 @@ import { useRef, useEffect } from "react"; -export default function useInView() { - const ref = useRef(undefined); +export default function useInView() { + const ref = useRef(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); } diff --git a/src/common/component/Message/useMessageOperation.js b/src/common/component/Message/useMessageOperation.tsx similarity index 95% rename from src/common/component/Message/useMessageOperation.js rename to src/common/component/Message/useMessageOperation.tsx index c2984ab6..0e9e69c1 100644 --- a/src/common/component/Message/useMessageOperation.js +++ b/src/common/component/Message/useMessageOperation.tsx @@ -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, diff --git a/src/common/component/Meta.js b/src/common/component/Meta.tsx similarity index 99% rename from src/common/component/Meta.js rename to src/common/component/Meta.tsx index 8cb46fc5..ad514e8d 100644 --- a/src/common/component/Meta.js +++ b/src/common/component/Meta.tsx @@ -1,6 +1,5 @@ // import React from 'react' import { Helmet } from "react-helmet"; - import BASE_URL from "../../app/config"; import { useGetServerQuery } from "../../app/services/server"; diff --git a/src/common/component/MixedInput/ImageElement.js b/src/common/component/MixedInput/ImageElement.tsx similarity index 99% rename from src/common/component/MixedInput/ImageElement.js rename to src/common/component/MixedInput/ImageElement.tsx index 2782466e..1c60bf10 100644 --- a/src/common/component/MixedInput/ImageElement.js +++ b/src/common/component/MixedInput/ImageElement.tsx @@ -4,6 +4,7 @@ import { Transforms } from "slate"; import { ReactEditor } from "slate-react"; import styled from "styled-components"; import iconClose from "../../../assets/icons/close.circle.svg?url"; + const StylePicture = styled.picture` position: relative; display: flex; @@ -21,6 +22,7 @@ const StylePicture = styled.picture` right: -20px; } `; + export default function ImageElement({ attributes, children, element }) { const editor = useEditorRef(); const path = ReactEditor.findPath(editor, element); diff --git a/src/common/component/MixedInput/StyledCombobox.js b/src/common/component/MixedInput/StyledCombobox.tsx similarity index 88% rename from src/common/component/MixedInput/StyledCombobox.js rename to src/common/component/MixedInput/StyledCombobox.tsx index 1c6b1011..f7d83d9b 100644 --- a/src/common/component/MixedInput/StyledCombobox.js +++ b/src/common/component/MixedInput/StyledCombobox.tsx @@ -1,8 +1,9 @@ -// import React from 'react' 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/MixedInput/config.js b/src/common/component/MixedInput/config.ts similarity index 100% rename from src/common/component/MixedInput/config.js rename to src/common/component/MixedInput/config.ts diff --git a/src/common/component/MixedInput/index.js b/src/common/component/MixedInput/index.tsx similarity index 100% rename from src/common/component/MixedInput/index.js rename to src/common/component/MixedInput/index.tsx diff --git a/src/common/component/MixedInput/plugins.js b/src/common/component/MixedInput/plugins.ts similarity index 100% rename from src/common/component/MixedInput/plugins.js rename to src/common/component/MixedInput/plugins.ts diff --git a/src/common/component/MixedInput/styled.js b/src/common/component/MixedInput/styled.ts similarity index 99% rename from src/common/component/MixedInput/styled.js rename to src/common/component/MixedInput/styled.ts index e1a59dc0..2ec298b7 100644 --- a/src/common/component/MixedInput/styled.js +++ b/src/common/component/MixedInput/styled.ts @@ -1,4 +1,5 @@ import styled from "styled-components"; + const Styled = styled.div` max-height: 50vh; overflow: auto; diff --git a/src/common/component/MixedInput/values/nodeTypes.js b/src/common/component/MixedInput/values/nodeTypes.ts similarity index 100% rename from src/common/component/MixedInput/values/nodeTypes.js rename to src/common/component/MixedInput/values/nodeTypes.ts diff --git a/src/common/component/MixedInput/values/utils.js b/src/common/component/MixedInput/values/utils.ts similarity index 100% rename from src/common/component/MixedInput/values/utils.js rename to src/common/component/MixedInput/values/utils.ts diff --git a/src/common/component/Modal.js b/src/common/component/Modal.tsx similarity index 100% rename from src/common/component/Modal.js rename to src/common/component/Modal.tsx diff --git a/src/common/component/MrakdownRender.js b/src/common/component/MrakdownRender.tsx similarity index 87% rename from src/common/component/MrakdownRender.js rename to src/common/component/MrakdownRender.tsx index 4d5ed2ad..4a8fef1f 100644 --- a/src/common/component/MrakdownRender.js +++ b/src/common/component/MrakdownRender.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState, useRef } from "react"; +import { useEffect, useState, useRef, FC } from "react"; import "prismjs/themes/prism.css"; import "@toast-ui/editor-plugin-code-syntax-highlight/dist/toastui-editor-plugin-code-syntax-highlight.css"; import codeSyntaxHighlight from "@toast-ui/editor-plugin-code-syntax-highlight/dist/toastui-editor-plugin-code-syntax-highlight-all.js"; @@ -11,7 +11,7 @@ import codeSyntaxHighlight from "@toast-ui/editor-plugin-code-syntax-highlight/d import { Viewer } from "@toast-ui/react-editor"; import styled from "styled-components"; -import ImagePreviewModal from "../../common/component/ImagePreviewModal"; +import ImagePreviewModal from "./ImagePreviewModal"; const Styled = styled.div` * { @@ -23,9 +23,15 @@ const Styled = styled.div` align-items: flex-start; } `; -export default function MrakdownRender({ content }) { - const mdContainer = useRef(undefined); + +interface Props { + content: string; +} + +const MrakdownRender: FC = ({ content }) => { + const mdContainer = useRef(null); const [previewImage, setPreviewImage] = useState(null); + useEffect(() => { const container = mdContainer?.current; if (container) { @@ -50,9 +56,11 @@ export default function MrakdownRender({ content }) { ); } }, []); + const closePreviewModal = () => { setPreviewImage(null); }; + return ( <> {previewImage && ( @@ -67,4 +75,6 @@ export default function MrakdownRender({ content }) { ); -} +}; + +export default MrakdownRender; diff --git a/src/common/component/Notification/index.js b/src/common/component/Notification/index.tsx similarity index 89% rename from src/common/component/Notification/index.js rename to src/common/component/Notification/index.tsx index f2760ff4..93d109e1 100644 --- a/src/common/component/Notification/index.js +++ b/src/common/component/Notification/index.tsx @@ -1,6 +1,5 @@ import { useEffect } from "react"; import { useNavigate } from "react-router-dom"; -// import toast, { Toaster } from 'react-hot-toast'; import useDeviceToken from "./useDeviceToken"; import { vapidKey } from "../../../app/config"; import { useUpdateDeviceTokenMutation } from "../../../app/services/auth"; @@ -16,7 +15,7 @@ const Notification = () => { }, [token]); useEffect(() => { - const handleServiceworkerMessage = (event) => { + const handleServiceworkerMessage = (event: MessageEvent) => { const { newPath } = event.data; navigateTo(newPath); }; diff --git a/src/common/component/Notification/useDeviceToken.js b/src/common/component/Notification/useDeviceToken.ts similarity index 99% rename from src/common/component/Notification/useDeviceToken.js rename to src/common/component/Notification/useDeviceToken.ts index ed631ba0..5423fb3f 100644 --- a/src/common/component/Notification/useDeviceToken.js +++ b/src/common/component/Notification/useDeviceToken.ts @@ -2,6 +2,7 @@ import { useState } from "react"; import { initializeApp } from "firebase/app"; import { getToken, getMessaging } from "firebase/messaging"; import { firebaseConfig } from "../../../app/config"; + const useDeviceToken = (vapidKey) => { const [token, setToken] = useState(null); // https only @@ -28,4 +29,5 @@ const useDeviceToken = (vapidKey) => { } return token; }; + export default useDeviceToken; diff --git a/src/common/component/Profile/index.js b/src/common/component/Profile/index.tsx similarity index 90% rename from src/common/component/Profile/index.js rename to src/common/component/Profile/index.tsx index a68b2718..fe4151af 100644 --- a/src/common/component/Profile/index.js +++ b/src/common/component/Profile/index.tsx @@ -1,9 +1,6 @@ -// import { useEffect } from "react"; -import { useSelector } from "react-redux"; +import { FC } from "react"; import { NavLink } from "react-router-dom"; -// import toast from "react-hot-toast"; import Tippy from "@tippyjs/react"; -// import { hideAll } from "tippy.js"; import IconMessage from "../../../assets/icons/message.svg"; import IconCall from "../../../assets/icons/call.svg"; import IconMore from "../../../assets/icons/more.svg"; @@ -11,8 +8,15 @@ import Avatar from "../Avatar"; import StyledWrapper from "./styled"; import StyledMenu from "../styled/Menu"; import useContactOperation from "../../hook/useContactOperation"; +import { useAppSelector } from "../../../app/store"; -export default function Profile({ uid = null, type = "embed", cid = null }) { +interface Props { + uid: number; + type: string; + cid: number; +} + +const Profile: FC = ({ uid = null, type = "embed", cid = null }) => { const { canCall, call, @@ -24,7 +28,7 @@ export default function Profile({ uid = null, type = "embed", cid = null }) { removeUser } = useContactOperation({ uid, cid }); - const { data } = useSelector((store) => { + const { data } = useAppSelector((store) => { return { data: store.contacts.byId[uid] }; @@ -103,4 +107,6 @@ export default function Profile({ uid = null, type = "embed", cid = null }) { ); -} +}; + +export default Profile; diff --git a/src/common/component/Profile/styled.js b/src/common/component/Profile/styled.tsx similarity index 100% rename from src/common/component/Profile/styled.js rename to src/common/component/Profile/styled.tsx diff --git a/src/common/component/ReactionItem.js b/src/common/component/ReactionItem.tsx similarity index 100% rename from src/common/component/ReactionItem.js rename to src/common/component/ReactionItem.tsx diff --git a/src/common/component/RequireAuth.js b/src/common/component/RequireAuth.tsx similarity index 51% rename from src/common/component/RequireAuth.js rename to src/common/component/RequireAuth.tsx index fe2cf079..e4afe57a 100644 --- a/src/common/component/RequireAuth.js +++ b/src/common/component/RequireAuth.tsx @@ -1,13 +1,20 @@ -// import React from 'react' +import React, { FC, ReactElement } from "react"; import { Navigate } from "react-router-dom"; -import { useSelector } from "react-redux"; import { useGetInitializedQuery } from "../../app/services/auth"; +import { useAppSelector } from "../../app/store"; -export default function RequireAuth({ children, redirectTo = "/login" }) { +interface Props { + children: ReactElement; + redirectTo?: string; +} + +const RequireAuth: FC = ({ children, redirectTo = "/login" }) => { const { isLoading } = useGetInitializedQuery(); - const { token, initialized } = useSelector((store) => store.authData); + const { token, initialized } = useAppSelector((store) => store.authData); if (isLoading) return null; // 未初始化 则先走setup 流程 if (!initialized) return ; return token ? children : ; -} +}; + +export default RequireAuth; diff --git a/src/common/component/RequireNoAuth.js b/src/common/component/RequireNoAuth.tsx similarity index 51% rename from src/common/component/RequireNoAuth.js rename to src/common/component/RequireNoAuth.tsx index 9769a9de..4dd0bc92 100644 --- a/src/common/component/RequireNoAuth.js +++ b/src/common/component/RequireNoAuth.tsx @@ -1,13 +1,20 @@ -// import React from 'react' +import { FC, ReactElement } from "react"; import { Navigate } from "react-router-dom"; import { useGetInitializedQuery } from "../../app/services/auth"; -import { useSelector } from "react-redux"; +import { useAppSelector } from "../../app/store"; -export default function RequireNoAuth({ children, redirectTo = "/" }) { +interface Props { + children: ReactElement; + redirectTo?: string; +} + +const RequireNoAuth: FC = ({ children, redirectTo = "/" }) => { const { isLoading } = useGetInitializedQuery(); - const { token, initialized } = useSelector((store) => store.authData); + const { token, initialized } = useAppSelector((store) => store.authData); if (isLoading) return null; // 未初始化 则先走setup 流程 if (!initialized) return ; return token ? : children; -} +}; + +export default RequireNoAuth; diff --git a/src/common/component/SaveTip.js b/src/common/component/SaveTip.tsx similarity index 86% rename from src/common/component/SaveTip.js rename to src/common/component/SaveTip.tsx index 9532b8f1..661bcb5e 100644 --- a/src/common/component/SaveTip.js +++ b/src/common/component/SaveTip.tsx @@ -1,5 +1,6 @@ -// import React from "react"; +import { FC, MouseEvent } from "react"; import styled from "styled-components"; + const StyledWrapper = styled.div` width: 100%; position: absolute; @@ -47,7 +48,13 @@ const StyledWrapper = styled.div` } } `; -export default function SaveTip({ saveHandler, resetHandler }) { + +interface Props { + saveHandler: (e: MouseEvent) => void; + resetHandler: (e: MouseEvent) => void; +} + +const SaveTip: FC = ({ saveHandler, resetHandler }) => { return ( You have unsaved changes! @@ -61,4 +68,6 @@ export default function SaveTip({ saveHandler, resetHandler }) {
); -} +}; + +export default SaveTip; diff --git a/src/common/component/Search.js b/src/common/component/Search.tsx similarity index 90% rename from src/common/component/Search.js rename to src/common/component/Search.tsx index 62f55c96..b8980501 100644 --- a/src/common/component/Search.js +++ b/src/common/component/Search.tsx @@ -1,12 +1,9 @@ -// import { useState } from "react"; import styled from "styled-components"; - import Tippy from "@tippyjs/react"; - import searchIcon from "../../assets/icons/search.svg?url"; import addIcon from "../../assets/icons/add.svg?url"; import AddEntriesMenu from "./AddEntriesMenu"; -import Tooltip from "../component/Tooltip"; +import Tooltip from "./Tooltip"; const StyledWrapper = styled.div` position: relative; @@ -16,7 +13,7 @@ const StyledWrapper = styled.div` align-items: center; justify-content: space-between; gap: 8px; - box-shadow: 0px 1px 0px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.1); .search { display: flex; align-items: center; @@ -35,6 +32,7 @@ const StyledWrapper = styled.div` cursor: pointer; } `; + export default function Search() { console.log("searching"); return ( diff --git a/src/common/component/Send/EmojiPicker.js b/src/common/component/Send/EmojiPicker.tsx similarity index 95% rename from src/common/component/Send/EmojiPicker.js rename to src/common/component/Send/EmojiPicker.tsx index 5f321bd7..51aaa886 100644 --- a/src/common/component/Send/EmojiPicker.js +++ b/src/common/component/Send/EmojiPicker.tsx @@ -1,7 +1,10 @@ import { useState, useRef } from "react"; import styled from "styled-components"; import { useOutsideClick } from "rooks"; -import Tooltip from "../../component/Tooltip"; +import Tooltip from "../Tooltip"; +import Picker from "../EmojiPicker"; +import SmileIcon from "../../../assets/icons/emoji.smile.svg"; + const Styled = styled.div` position: relative; width: fit-content; @@ -25,20 +28,20 @@ const Styled = styled.div` } } `; -import Picker from "../EmojiPicker"; -import SmileIcon from "../../../assets/icons/emoji.smile.svg"; export default function EmojiPicker({ selectEmoji }) { - const ref = useRef(); + const ref = useRef(null); const [visible, setVisible] = useState(false); const togglePickerVisible = () => { setVisible((prev) => !prev); }; + const handleSelect = (emoji) => { console.log("semojii", emoji); selectEmoji(emoji.native); }; + useOutsideClick( ref, (evt) => { @@ -53,6 +56,7 @@ export default function EmojiPicker({ selectEmoji }) { }, visible ); + return ( diff --git a/src/common/component/Send/Replying.js b/src/common/component/Send/Replying.tsx similarity index 95% rename from src/common/component/Send/Replying.js rename to src/common/component/Send/Replying.tsx index 5fc84451..85a1a961 100644 --- a/src/common/component/Send/Replying.js +++ b/src/common/component/Send/Replying.tsx @@ -1,6 +1,5 @@ -// import React from 'react' -import { useSelector } from "react-redux"; import reactStringReplace from "react-string-replace"; +import styled from "styled-components"; import Mention from "../Message/Mention"; import { ContentTypes } from "../../../app/config"; import MrakdownRender from "../MrakdownRender"; @@ -8,12 +7,12 @@ import closeIcon from "../../../assets/icons/close.circle.svg?url"; import pictureIcon from "../../../assets/icons/picture.svg?url"; import { getFileIcon, isImage } from "../../utils"; import useSendMessage from "../../hook/useSendMessage"; -import styled from "styled-components"; +import { useAppSelector } from "../../../app/store"; + const Styled = styled.div` background-color: #f3f4f6; z-index: 999; display: flex; - justify-content: space-between; align-items: flex-start; justify-content: flex-start; gap: 16px; @@ -120,9 +119,10 @@ const renderContent = (data) => { // console.log("replying data", data); return res; }; + export default function Replying({ context, id, mid }) { const { removeReplying } = useSendMessage({ to: id, context }); - const { msg, contactsData } = useSelector((store) => { + const { msg, contactsData } = useAppSelector((store) => { return { contactsData: store.contacts.byId, msg: store.message[mid] }; }); const removeReply = () => { diff --git a/src/common/component/Send/Toolbar.js b/src/common/component/Send/Toolbar.tsx similarity index 91% rename from src/common/component/Send/Toolbar.js rename to src/common/component/Send/Toolbar.tsx index aac89443..4f5f0214 100644 --- a/src/common/component/Send/Toolbar.js +++ b/src/common/component/Send/Toolbar.tsx @@ -1,11 +1,12 @@ -import { useRef } from "react"; +import { ChangeEvent, useRef } from "react"; import styled from "styled-components"; -import Tooltip from "../../component/Tooltip"; +import Tooltip from "../Tooltip"; import AddIcon from "../../../assets/icons/add.solid.svg"; import MarkdownIcon from "../../../assets/icons/markdown.svg"; import FullscreenIcon from "../../../assets/icons/fullscreen.svg"; import ExitFullscreenIcon from "../../../assets/icons/fullscreen.exit.svg"; import useUploadFile from "../../hook/useUploadFile"; + const Styled = styled.div` display: flex; align-items: center; @@ -41,6 +42,7 @@ const Styled = styled.div` } } `; + export default function Toolbar({ toggleMarkdownFullscreen, fullscreen, @@ -49,9 +51,10 @@ export default function Toolbar({ to, context }) { + // todo: check code logic const { addStageFile } = useUploadFile({ context, id: to }); - const fileInputRef = useRef(null); - const handleUpload = (evt) => { + const fileInputRef = useRef(null); + const handleUpload = (evt: ChangeEvent) => { const files = [...evt.target.files]; console.log("files", files); const filesData = files.map((file) => { @@ -64,6 +67,7 @@ export default function Toolbar({ fileInputRef.current.value = ""; // setFiles([...evt.target.files]); }; + return (
diff --git a/src/common/component/Send/UploadFileList/EditFileDetails.js b/src/common/component/Send/UploadFileList/EditFileDetails.tsx similarity index 99% rename from src/common/component/Send/UploadFileList/EditFileDetails.js rename to src/common/component/Send/UploadFileList/EditFileDetails.tsx index fa958e93..ebd3610e 100644 --- a/src/common/component/Send/UploadFileList/EditFileDetails.js +++ b/src/common/component/Send/UploadFileList/EditFileDetails.tsx @@ -4,6 +4,7 @@ import Modal from "../../Modal"; import Button from "../../styled/Button"; import Input from "../../styled/Input"; import CloseIcon from "../../../../assets/icons/close.svg"; + const StyledWrapper = styled.div` background: #fff; display: flex; diff --git a/src/common/component/Send/UploadFileList/index.js b/src/common/component/Send/UploadFileList/index.tsx similarity index 100% rename from src/common/component/Send/UploadFileList/index.js rename to src/common/component/Send/UploadFileList/index.tsx diff --git a/src/common/component/Send/UploadFileList/styled.js b/src/common/component/Send/UploadFileList/styled.tsx similarity index 93% rename from src/common/component/Send/UploadFileList/styled.js rename to src/common/component/Send/UploadFileList/styled.tsx index b0f65632..8bc86572 100644 --- a/src/common/component/Send/UploadFileList/styled.js +++ b/src/common/component/Send/UploadFileList/styled.tsx @@ -1,15 +1,15 @@ import styled from "styled-components"; + const Styled = styled.ul` width: 100%; overflow: auto; display: flex; justify-content: flex-start; gap: 24px; - width: 100%; padding: 24px 16px 16px 16px; background: #e5e7eb; - box-shadow: 0px 1px 0px rgba(0, 0, 0, 0.05); - border-radius: 8px 8px 0px 0px; + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.05); + border-radius: 8px 8px 0 0; .file { position: relative; display: flex; @@ -68,4 +68,5 @@ const Styled = styled.ul` } } `; + export default Styled; diff --git a/src/common/component/Send/index.js b/src/common/component/Send/index.tsx similarity index 97% rename from src/common/component/Send/index.js rename to src/common/component/Send/index.tsx index 534963cb..4cd0c663 100644 --- a/src/common/component/Send/index.js +++ b/src/common/component/Send/index.tsx @@ -1,5 +1,4 @@ import { useEffect, useState } from "react"; -import { useDispatch, useSelector } from "react-redux"; import useSendMessage from "../../hook/useSendMessage"; import useAddLocalFileMessage from "../../hook/useAddLocalFileMessage"; import { updateInputMode } from "../../../app/slices/ui"; @@ -15,6 +14,7 @@ import MarkdownEditor from "../MarkdownEditor"; import MixedInput, { useMixedEditor } from "../MixedInput"; import useDraft from "../../hook/useDraft"; import useUploadFile from "../../hook/useUploadFile"; +import { useAppDispatch, useAppSelector } from "../../../app/store"; const Modes = { text: "text", @@ -30,7 +30,7 @@ function Send({ const editor = useMixedEditor(`${context}_${id}`); const [markdownEditor, setMarkdownEditor] = useState(null); const [markdownFullscreen, setMarkdownFullscreen] = useState(false); - const dispatch = useDispatch(); + const dispatch = useAppDispatch(); const addLocalFileMesage = useAddLocalFileMessage({ context, to: id }); // 谁发的 const { @@ -41,7 +41,7 @@ function Send({ channelsData, contactsData, uids - } = useSelector((store) => { + } = useAppSelector((store) => { return { channelsData: store.channels.byId, uids: store.contacts.ids, @@ -174,6 +174,7 @@ function Send({ ); } + export default Send; // export default memo(Send, (prevs, nexts) => { // console.log("send name", prevs.name, nexts.name); diff --git a/src/common/component/Send/styled.js b/src/common/component/Send/styled.tsx similarity index 100% rename from src/common/component/Send/styled.js rename to src/common/component/Send/styled.tsx diff --git a/src/common/component/Send/useFiles.js b/src/common/component/Send/useFiles.ts similarity index 100% rename from src/common/component/Send/useFiles.js rename to src/common/component/Send/useFiles.ts diff --git a/src/common/component/Server.js b/src/common/component/Server.tsx similarity index 93% rename from src/common/component/Server.js rename to src/common/component/Server.tsx index 7d3a0224..32a7145b 100644 --- a/src/common/component/Server.js +++ b/src/common/component/Server.tsx @@ -1,11 +1,10 @@ -// import { useState } from "react"; import styled from "styled-components"; -import { useSelector } from "react-redux"; +import { NavLink, useLocation } from "react-router-dom"; import Tippy from "@tippyjs/react"; import addIcon from "../../assets/icons/add.svg?url"; import Tooltip from "./Tooltip"; -import { NavLink, useLocation } from "react-router-dom"; import AddEntriesMenu from "./AddEntriesMenu"; +import { useAppSelector } from "../../app/store"; const StyledWrapper = styled.div` min-height: 56px; @@ -52,9 +51,10 @@ const StyledWrapper = styled.div` cursor: pointer; } `; + export default function Server() { const { pathname } = useLocation(); - const { server, userCount } = useSelector((store) => { + const { server, userCount } = useAppSelector((store) => { return { userCount: store.contacts.ids.length, server: store.server @@ -62,6 +62,7 @@ export default function Server() { }); // console.log("server info", server); const { name, description, logo } = server; + return ( diff --git a/src/common/component/StyledSettingContainer.js b/src/common/component/StyledSettingContainer.tsx similarity index 89% rename from src/common/component/StyledSettingContainer.js rename to src/common/component/StyledSettingContainer.tsx index 5439097b..b0474ba5 100644 --- a/src/common/component/StyledSettingContainer.js +++ b/src/common/component/StyledSettingContainer.tsx @@ -1,8 +1,8 @@ -// import React from 'react' +import { FC, ReactElement } from "react"; import styled from "styled-components"; import { useLocation, NavLink } from "react-router-dom"; - import backIcon from "../../assets/icons/arrow.left.svg?url"; + const StyledWrapper = styled.div` width: 100vw; height: 100vh; @@ -81,14 +81,32 @@ const StyledWrapper = styled.div` } } `; -export default function StyledSettingContainer({ + +interface Nav { + name?: string; + title: string; + // todo + items: []; + component: ReactElement; +} + +interface Props { + closeModal: () => void; + title?: string; + navs: Nav[]; + dangers: []; + nav: Nav; + children: ReactElement; +} + +const StyledSettingContainer: FC = ({ closeModal, title = "Settings", navs = [], dangers = [], nav, children -}) { +}) => { const { pathname } = useLocation(); return ( @@ -129,4 +147,6 @@ export default function StyledSettingContainer({
); -} +}; + +export default StyledSettingContainer; diff --git a/src/common/component/TippyDefault.ts b/src/common/component/TippyDefault.tsx similarity index 100% rename from src/common/component/TippyDefault.ts rename to src/common/component/TippyDefault.tsx diff --git a/src/common/component/Tooltip.js b/src/common/component/Tooltip.tsx similarity index 68% rename from src/common/component/Tooltip.js rename to src/common/component/Tooltip.tsx index 0e796469..4a1da2a1 100644 --- a/src/common/component/Tooltip.js +++ b/src/common/component/Tooltip.tsx @@ -1,6 +1,9 @@ // import React from 'react' import Tippy from "@tippyjs/react"; import styled from "styled-components"; +import { Placement } from "tippy.js"; +import { FC, ReactElement } from "react"; + const StyledTip = styled.div` position: relative; background: #fff; @@ -10,7 +13,7 @@ const StyledTip = styled.div` line-height: 18px; color: #1d2939; border-radius: var(--br); - box-shadow: 0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03); + box-shadow: 0 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03); &::after { background-color: inherit; position: absolute; @@ -36,14 +39,17 @@ const StyledTip = styled.div` transform: translate3d(-50%, -50%, 0) rotate(45deg); } `; -export default function Tooltip({ - tip = "", - placement = "right", - delay = null, - children, - ...rest -}) { - const defaultDuration = [300, 250]; + +interface Props { + tip: string; + placement: Placement; + delay?: number | [number | null, number | null]; + children: ReactElement; +} + +const Tooltip: FC = ({ tip = "", placement = "right", delay = null, children, ...rest }) => { + const defaultDuration: [number, number] = [300, 250]; + return ( ); -} +}; + +export default Tooltip; diff --git a/src/common/component/UploadModal/FileItem.js b/src/common/component/UploadModal/FileItem.tsx similarity index 92% rename from src/common/component/UploadModal/FileItem.js rename to src/common/component/UploadModal/FileItem.tsx index f645e8b0..7a64f343 100644 --- a/src/common/component/UploadModal/FileItem.js +++ b/src/common/component/UploadModal/FileItem.tsx @@ -7,6 +7,7 @@ export default function FileItem({ file = null }) { if (file) { const { type, name } = file; if (isTreatAsImage(file)) { + // todo: memory leak, use revokeObjectURL before component didMount setIcon(thumb); return; } diff --git a/src/common/component/UploadModal/index.js b/src/common/component/UploadModal/index.tsx similarity index 92% rename from src/common/component/UploadModal/index.js rename to src/common/component/UploadModal/index.tsx index b07f5c72..e894e8d0 100644 --- a/src/common/component/UploadModal/index.js +++ b/src/common/component/UploadModal/index.tsx @@ -1,15 +1,14 @@ import { useEffect } from "react"; -import { useSelector } from "react-redux"; import FileItem from "./FileItem"; import useUploadFile from "../../hook/useUploadFile"; import Modal from "../Modal"; import Button from "../styled/Button"; -// import { isTreatAsImage } from "../../utils"; import StyledWrapper from "./styled"; import useSendMessage from "../../hook/useSendMessage"; +import { useAppSelector } from "../../../app/store"; export default function UploadModal({ context = "user", sendTo = 0, files = [], closeModal }) { - const from_uid = useSelector((store) => store.authData.uid); + const from_uid = useAppSelector((store) => store.authData.uid); const { sendMessage, isSuccess: sendMessageSuccess, diff --git a/src/common/component/UploadModal/styled.js b/src/common/component/UploadModal/styled.tsx similarity index 100% rename from src/common/component/UploadModal/styled.js rename to src/common/component/UploadModal/styled.tsx diff --git a/src/common/component/UserGuide/index.js b/src/common/component/UserGuide/index.tsx similarity index 89% rename from src/common/component/UserGuide/index.js rename to src/common/component/UserGuide/index.tsx index 7554921d..524b824f 100644 --- a/src/common/component/UserGuide/index.js +++ b/src/common/component/UserGuide/index.tsx @@ -1,17 +1,18 @@ -// import React from 'react' -import { useDispatch, useSelector } from "react-redux"; import styled, { createGlobalStyle } from "styled-components"; import Tippy from "@tippyjs/react"; import { roundArrow } from "tippy.js"; import "tippy.js/dist/svg-arrow.css"; import { updateUserGuide } from "../../../app/slices/ui"; +import steps from "./steps"; +import { useAppDispatch, useAppSelector } from "../../../app/store"; + const Styled = styled.div` display: flex; flex-direction: column; padding: 24px; background: #06aed4; border-radius: var(--br); - box-shadow: 0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03); + box-shadow: 0 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03); color: #ffffff; min-width: 362px; .title { @@ -55,10 +56,10 @@ const OverrideTippyArrowColor = createGlobalStyle` fill:#06aed4 ; } `; -import steps from "./steps"; + export default function UserGuide({ step = 1, placement = "right-start", delay = null, children }) { - const dispatch = useDispatch(); - const { visible, step: reduxStep } = useSelector((store) => store.ui.userGuide); + const dispatch = useAppDispatch(); + const { visible, step: reduxStep } = useAppSelector((store) => store.ui.userGuide); const currStep = steps[step - 1]; const isLastStep = steps.length == step; // if (!visible) return children; diff --git a/src/common/component/UserGuide/steps.js b/src/common/component/UserGuide/steps.ts similarity index 79% rename from src/common/component/UserGuide/steps.js rename to src/common/component/UserGuide/steps.ts index a3a62ba2..dc8c982d 100644 --- a/src/common/component/UserGuide/steps.js +++ b/src/common/component/UserGuide/steps.ts @@ -1,4 +1,9 @@ -const steps = [ +interface Step { + title: string; + description: string; +} + +const steps: Step[] = [ { title: "Step 1", description: "hello world 1" @@ -20,4 +25,5 @@ const steps = [ description: "hello world 1" } ]; + export default steps; diff --git a/src/common/component/styled/Button.js b/src/common/component/styled/Button.tsx similarity index 95% rename from src/common/component/styled/Button.js rename to src/common/component/styled/Button.tsx index e8ca48b3..89d855c5 100644 --- a/src/common/component/styled/Button.js +++ b/src/common/component/styled/Button.tsx @@ -1,10 +1,11 @@ import styled from "styled-components"; + const StyledButton = styled.button` cursor: pointer; padding: 10px 14px; border: none; box-sizing: border-box; - box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05); + box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05); border-radius: var(--br, 4px); font-weight: 500; font-size: 14px; diff --git a/src/common/component/styled/Checkbox.js b/src/common/component/styled/Checkbox.tsx similarity index 96% rename from src/common/component/styled/Checkbox.js rename to src/common/component/styled/Checkbox.tsx index 8785dd85..defa318d 100644 --- a/src/common/component/styled/Checkbox.js +++ b/src/common/component/styled/Checkbox.tsx @@ -1,5 +1,5 @@ -// import React from 'react' import styled from "styled-components"; + const Styled = styled.input` -webkit-appearance: none; /* Remove most all native input styles */ @@ -33,6 +33,7 @@ const Styled = styled.input` opacity: 0.4; } `; + export default function StyledCheckbox(props) { return ; } diff --git a/src/common/component/styled/Input.tsx b/src/common/component/styled/Input.tsx index 86df587f..be717f05 100644 --- a/src/common/component/styled/Input.tsx +++ b/src/common/component/styled/Input.tsx @@ -35,6 +35,7 @@ const StyledWrapper = styled.div` } `; +// todo: check ime problem const StyledInput = styled.input` width: 100%; background: #ffffff; diff --git a/src/common/component/styled/Label.js b/src/common/component/styled/Label.tsx similarity index 99% rename from src/common/component/styled/Label.js rename to src/common/component/styled/Label.tsx index ec7f1ebf..4ea491db 100644 --- a/src/common/component/styled/Label.js +++ b/src/common/component/styled/Label.tsx @@ -1,4 +1,5 @@ import styled from "styled-components"; + const StyledLabel = styled.label` font-weight: 500; font-size: 14px; diff --git a/src/common/component/styled/Menu.js b/src/common/component/styled/Menu.tsx similarity index 93% rename from src/common/component/styled/Menu.js rename to src/common/component/styled/Menu.tsx index 6bbd2868..573457ed 100644 --- a/src/common/component/styled/Menu.js +++ b/src/common/component/styled/Menu.tsx @@ -1,11 +1,12 @@ import styled from "styled-components"; + const StyledMenu = styled.ul` display: flex; flex-direction: column; gap: 2px; padding: 4px; background-color: #fff; - box-shadow: 0px 20px 25px 20px rgba(31, 41, 55, 0.1), 0px 10px 10px rgba(31, 41, 55, 0.04); + box-shadow: 0 20px 25px 20px rgba(31, 41, 55, 0.1), 0 10px 10px rgba(31, 41, 55, 0.04); border-radius: 12px; min-width: 200px; .item { diff --git a/src/common/component/styled/Modal.js b/src/common/component/styled/Modal.tsx similarity index 79% rename from src/common/component/styled/Modal.js rename to src/common/component/styled/Modal.tsx index a66d91bc..d622ef5a 100644 --- a/src/common/component/styled/Modal.js +++ b/src/common/component/styled/Modal.tsx @@ -1,5 +1,6 @@ -// import React from 'react' +import { FC, ReactElement } from "react"; import styled from "styled-components"; + const Styled = styled.div` padding: 32px; filter: drop-shadow(0px 25px 50px rgba(31, 41, 55, 0.25)); @@ -38,13 +39,22 @@ const Styled = styled.div` align-items: center; } `; -export default function StyledModal({ + +interface Props { + title?: string; + description?: string; + buttons: ReactElement[] | ReactElement; + children?: ReactElement; + className?: string; +} + +const StyledModal: FC = ({ title = "", description = "", buttons = null, children, ...props -}) { +}) => { return ( {title &&

{title}

} @@ -53,4 +63,6 @@ export default function StyledModal({ {buttons &&
{buttons}
}
); -} +}; + +export default StyledModal; diff --git a/src/common/component/styled/Radio.js b/src/common/component/styled/Radio.tsx similarity index 100% rename from src/common/component/styled/Radio.js rename to src/common/component/styled/Radio.tsx diff --git a/src/common/component/styled/Select.js b/src/common/component/styled/Select.tsx similarity index 99% rename from src/common/component/styled/Select.js rename to src/common/component/styled/Select.tsx index 44f83a92..ec4e4ecd 100644 --- a/src/common/component/styled/Select.js +++ b/src/common/component/styled/Select.tsx @@ -4,6 +4,7 @@ import Tippy from "@tippyjs/react"; import IconSelect from "../../../assets/icons/check.sign.svg"; import IconArrow from "../../../assets/icons/arrow.down.svg"; import Menu from "./Menu"; + const Styled = styled.div` user-select: none; border: 1px solid #e5e7eb; diff --git a/src/common/component/styled/Textarea.js b/src/common/component/styled/Textarea.tsx similarity index 90% rename from src/common/component/styled/Textarea.js rename to src/common/component/styled/Textarea.tsx index 90e7e5bd..c30d06f9 100644 --- a/src/common/component/styled/Textarea.js +++ b/src/common/component/styled/Textarea.tsx @@ -1,10 +1,11 @@ import styled from "styled-components"; + const StyledTextarea = styled.textarea` font-family: inherit; width: 100%; background: #ffffff; border: 1px solid #e5e7eb; - box-shadow: 0px 1px 2px rgba(31, 41, 55, 0.08); + box-shadow: 0 1px 2px rgba(31, 41, 55, 0.08); border-radius: 4px; font-weight: normal; font-size: 14px; diff --git a/src/common/component/styled/Toggle.js b/src/common/component/styled/Toggle.tsx similarity index 99% rename from src/common/component/styled/Toggle.js rename to src/common/component/styled/Toggle.tsx index e558a69b..1f5bae8b 100644 --- a/src/common/component/styled/Toggle.js +++ b/src/common/component/styled/Toggle.tsx @@ -1,4 +1,5 @@ import styled from "styled-components"; + const StyledToggle = styled.div` cursor: pointer; position: relative; diff --git a/src/common/hook/useAddLocalFileMessage.js b/src/common/hook/useAddLocalFileMessage.ts similarity index 100% rename from src/common/hook/useAddLocalFileMessage.js rename to src/common/hook/useAddLocalFileMessage.ts index f44704c3..3a5a41e9 100644 --- a/src/common/hook/useAddLocalFileMessage.js +++ b/src/common/hook/useAddLocalFileMessage.ts @@ -1,9 +1,9 @@ // import React from 'react' import { useDispatch } from "react-redux"; - import { addMessage } from "../../app/slices/message"; import { addChannelMsg } from "../../app/slices/message.channel"; import { addUserMsg } from "../../app/slices/message.user"; + export default function useAddLocalFileMessage({ context, to }) { const dispatch = useDispatch(); const addContextMessage = context == "channel" ? addChannelMsg : addUserMsg; diff --git a/src/common/hook/useChatScroll.js b/src/common/hook/useChatScroll.ts similarity index 95% rename from src/common/hook/useChatScroll.js rename to src/common/hook/useChatScroll.ts index 23b730e0..e309ce05 100644 --- a/src/common/hook/useChatScroll.js +++ b/src/common/hook/useChatScroll.ts @@ -1,6 +1,8 @@ import { useRef, useEffect } from "react"; // import { useDebounce } from "rooks"; + function useChatScroll(deps = []) { + // todo: ref should be initialized to null const ref = useRef(); // useEffect(() => { // console.log("chat scroll", ref); diff --git a/src/common/hook/useConfig.js b/src/common/hook/useConfig.ts similarity index 98% rename from src/common/hook/useConfig.js rename to src/common/hook/useConfig.ts index ee722305..699c3b03 100644 --- a/src/common/hook/useConfig.js +++ b/src/common/hook/useConfig.ts @@ -1,6 +1,6 @@ import { useEffect, useState } from "react"; -import { isObjectEqual } from "../utils"; import toast from "react-hot-toast"; +import { isObjectEqual } from "../utils"; import { useUpdateLoginConfigMutation, useUpdateSMTPConfigMutation, @@ -11,8 +11,10 @@ import { useLazyGetSMTPConfigQuery, useLazyGetLoginConfigQuery } from "../../app/services/server"; + // config: smtp agora login firebase -let originalValue = null; +let originalValue: null | object = null; + export default function useConfig(config = "smtp") { const [changed, setChanged] = useState(false); const [values, setValues] = useState({}); @@ -105,6 +107,7 @@ export default function useConfig(config = "smtp") { setChanged(false); } }, [values]); + return { reset, changed, diff --git a/src/common/hook/useContactOperation.js b/src/common/hook/useContactOperation.ts similarity index 92% rename from src/common/hook/useContactOperation.js rename to src/common/hook/useContactOperation.ts index 85ac6130..2545320d 100644 --- a/src/common/hook/useContactOperation.js +++ b/src/common/hook/useContactOperation.ts @@ -1,15 +1,15 @@ import { useState, useEffect } from "react"; import toast from "react-hot-toast"; // import { ContentTypes } from "../../../app/config"; -import { useSelector } from "react-redux"; import { useNavigate, useMatch } from "react-router-dom"; import { hideAll } from "tippy.js"; import { useRemoveMembersMutation } from "../../app/services/channel"; import { useLazyDeleteContactQuery } from "../../app/services/contact"; import useConfig from "./useConfig"; import useCopy from "./useCopy"; +import { useAppSelector } from "../../app/store"; -export default function useContactOperation({ uid, cid }) { +export default function useContactOperation({ uid, cid }: { uid: number; cid: number }) { const [passedUid, setPassedUid] = useState(undefined); const { values: agoraConfig } = useConfig("agora"); const isUserDetailPath = useMatch(`/contacts/${uid}`); @@ -17,7 +17,7 @@ export default function useContactOperation({ uid, cid }) { const [removeInChannel, { isSuccess: removeSuccess }] = useRemoveMembersMutation(); const navigateTo = useNavigate(); const { copy } = useCopy(); - const { user, channel, loginUid, isAdmin } = useSelector((store) => { + const { user, channel, loginUid, isAdmin } = useAppSelector((store) => { return { user: store.contacts.byId[uid], channel: store.channels.byId[cid], @@ -25,6 +25,7 @@ export default function useContactOperation({ uid, cid }) { isAdmin: store.contacts.byId[store.authData.uid]?.is_admin }; }); + useEffect(() => { setPassedUid(uid ?? loginUid); }, [uid, loginUid]); @@ -37,35 +38,42 @@ export default function useContactOperation({ uid, cid }) { } } }, [removeSuccess, removeUserSuccess, isUserDetailPath]); + const handleRemoveFromChannel = (id) => { const isNumber = !Number.isNaN(+id); const finalId = isNumber ? id || passedUid : passedUid; removeInChannel({ id: +cid, members: [+finalId] }); hideAll(); }; + const handleRemove = (id) => { const isNumber = !Number.isNaN(+id); const finalId = isNumber ? id || passedUid : passedUid; removeUser(finalId); hideAll(); }; + const copyEmail = (email) => { const isString = typeof email == "string"; const finalEmail = isString ? email || user?.email : user?.email; copy(finalEmail); hideAll(); }; + const startChat = () => { navigateTo(`/chat/dm/${uid}`); }; + const call = () => { toast.success("Cooming Soon..."); hideAll(); }; + const canRemoveFromChannel = cid && !channel?.is_public && (isAdmin || channel?.owner == loginUid); const canCall = agoraConfig.enabled && loginUid != uid; const canRemove = isAdmin && loginUid != uid && !cid; + return { canRemove, removeUser: handleRemove, diff --git a/src/common/hook/useContextMenu.js b/src/common/hook/useContextMenu.tsx similarity index 99% rename from src/common/hook/useContextMenu.js rename to src/common/hook/useContextMenu.tsx index 9beceb80..02bbc4ac 100644 --- a/src/common/hook/useContextMenu.js +++ b/src/common/hook/useContextMenu.tsx @@ -2,6 +2,7 @@ import { useState } from "react"; import { hideAll } from "tippy.js"; import Tippy from "@tippyjs/react"; import Menu from "../component/ContextMenu"; + export default function useContextMenu(placement = "right-start") { const [visible, setVisible] = useState(false); // for tippy.js diff --git a/src/common/hook/useCopy.js b/src/common/hook/useCopy.ts similarity index 100% rename from src/common/hook/useCopy.js rename to src/common/hook/useCopy.ts diff --git a/src/common/hook/useDeleteMessage.js b/src/common/hook/useDeleteMessage.ts similarity index 90% rename from src/common/hook/useDeleteMessage.js rename to src/common/hook/useDeleteMessage.ts index 1ac5b33f..d13e693a 100644 --- a/src/common/hook/useDeleteMessage.js +++ b/src/common/hook/useDeleteMessage.ts @@ -1,9 +1,10 @@ import { useState } from "react"; -import { useSelector } from "react-redux"; import { useLazyDeleteMessageQuery } from "../../app/services/message"; +import { useAppSelector } from "../../app/store"; + export default function useDeleteMessage() { const [deleting, setDeleting] = useState(false); - const { loginUser, messageData } = useSelector((store) => { + const { loginUser, messageData } = useAppSelector((store) => { return { messageData: store.message, loginUser: store.contacts.byId[store.authData.uid] diff --git a/src/common/hook/useDraft.js b/src/common/hook/useDraft.ts similarity index 77% rename from src/common/hook/useDraft.js rename to src/common/hook/useDraft.ts index c17d7bf0..b591a6d6 100644 --- a/src/common/hook/useDraft.js +++ b/src/common/hook/useDraft.ts @@ -1,10 +1,10 @@ -// import React from 'react' -import { useDispatch, useSelector } from "react-redux"; import { updateDraftMarkdown, updateDraftMixedText } from "../../app/slices/ui"; +import { useAppDispatch, useAppSelector } from "../../app/store"; + export default function useDraft({ context = "", id = "" }) { - const dispatch = useDispatch(); + const dispatch = useAppDispatch(); const _key = `${context}_${id}`; - const { draftMarkdown, draftMixedText } = useSelector((store) => { + const { draftMarkdown, draftMixedText } = useAppSelector((store) => { return { draftMarkdown: store.ui.draftMarkdown, draftMixedText: store.ui.draftMixedText @@ -17,8 +17,10 @@ export default function useDraft({ context = "", id = "" }) { dispatch(update({ key: _key, value })); }; }; + const getDraft = (type = "mixed") => { return type == "mixed" ? draftMixedText[_key] : draftMarkdown[_key]; }; + return { getDraft, getUpdateDraft }; } diff --git a/src/common/hook/useFavMessage.js b/src/common/hook/useFavMessage.ts similarity index 91% rename from src/common/hook/useFavMessage.js rename to src/common/hook/useFavMessage.ts index dea8ce9f..a1f439a8 100644 --- a/src/common/hook/useFavMessage.js +++ b/src/common/hook/useFavMessage.ts @@ -1,25 +1,27 @@ import { useState, useEffect } from "react"; -import { useSelector } from "react-redux"; import { useLazyRemoveFavoriteQuery, useFavoriteMessageMutation } from "../../app/services/message"; +import { useAppSelector } from "../../app/store"; + export default function useFavMessage({ cid = null, uid = null }) { const [removeFav] = useLazyRemoveFavoriteQuery(); const [addFav] = useFavoriteMessageMutation(); const [favorites, setFavorites] = useState([]); - const { favs = [] } = useSelector((store) => { - return { - favs: store.favorites - }; + const { favs = [] } = useAppSelector((store) => { + return { favs: store.favorites }; }); + const addFavorite = async (mid = []) => { const mids = Array.isArray(mid) ? mid.map((i) => +i) : [+mid]; if (mids.length == 0) return; const { error = null } = await addFav(mids); return !error; }; + const removeFavorite = (id) => { if (!id) return; removeFav(id); }; + const isFavorited = (mid = null) => { if (!mid) return false; let mids = []; @@ -31,6 +33,7 @@ export default function useFavMessage({ cid = null, uid = null }) { }); return mids.findIndex((i) => i == mid) > -1; }; + useEffect(() => { let filtereds = []; filtereds = cid @@ -48,6 +51,7 @@ export default function useFavMessage({ cid = null, uid = null }) { setFavorites(filtereds); }, [cid, uid, favs]); + // console.log("filtered", cid, uid, favs); return { isFavorited, diff --git a/src/common/hook/useFilteredChannels.js b/src/common/hook/useFilteredChannels.ts similarity index 58% rename from src/common/hook/useFilteredChannels.js rename to src/common/hook/useFilteredChannels.ts index f941294f..b14758f4 100644 --- a/src/common/hook/useFilteredChannels.js +++ b/src/common/hook/useFilteredChannels.ts @@ -1,25 +1,30 @@ import { useState, useEffect } from "react"; -import { useSelector } from "react-redux"; +import { useAppSelector } from "../../app/store"; +import { Channel } from "../../types/channel"; + export default function useFilteredChannels() { const [input, setInput] = useState(""); - const channels = useSelector((store) => Object.values(store.channels.byId)); - const [filteredChannels, setfilteredChannels] = useState([]); + const channels = useAppSelector((store) => Object.values(store.channels.byId)); + const [filteredChannels, setFilteredChannels] = useState([]); + useEffect(() => { if (!input) { - setfilteredChannels(channels); + setFilteredChannels(channels); } else { let str = ["", ...input.toLowerCase(), ""].join(".*"); let reg = new RegExp(str); - setfilteredChannels( + setFilteredChannels( channels.filter((c) => { return reg.test(c.name.toLowerCase()); }) ); } }, [input]); - const updateInput = (val) => { + + const updateInput = (val: string) => { setInput(val); }; + return { input, channels: filteredChannels, diff --git a/src/common/hook/useFilteredUsers.js b/src/common/hook/useFilteredUsers.ts similarity index 77% rename from src/common/hook/useFilteredUsers.js rename to src/common/hook/useFilteredUsers.ts index 731042c6..28ce8aae 100644 --- a/src/common/hook/useFilteredUsers.js +++ b/src/common/hook/useFilteredUsers.ts @@ -1,8 +1,9 @@ import { useState, useEffect } from "react"; -import { useSelector } from "react-redux"; +import { useAppSelector } from "../../app/store"; + export default function useFilteredUsers() { const [input, setInput] = useState(""); - const contacts = useSelector((store) => Object.values(store.contacts.byId)); + const contacts = useAppSelector((store) => Object.values(store.contacts.byId)); const [filteredUsers, setFilteredUsers] = useState([]); useEffect(() => { if (!input) { @@ -17,9 +18,11 @@ export default function useFilteredUsers() { ); } }, [input]); - const updateInput = (val) => { + + const updateInput = (val: string) => { setInput(val); }; + return { input, contacts: filteredUsers, diff --git a/src/common/hook/useForwardMessage.js b/src/common/hook/useForwardMessage.ts similarity index 99% rename from src/common/hook/useForwardMessage.js rename to src/common/hook/useForwardMessage.ts index 1bf443d3..d7f527b2 100644 --- a/src/common/hook/useForwardMessage.js +++ b/src/common/hook/useForwardMessage.ts @@ -2,6 +2,7 @@ import { useState } from "react"; import { useSendChannelMsgMutation } from "../../app/services/channel"; import { useSendMsgMutation } from "../../app/services/contact"; import { useCreateArchiveMutation } from "../../app/services/message"; + export default function useForwardMessage() { const [forwarding, setForwarding] = useState(false); const [ diff --git a/src/common/hook/useGithubAuthConfig.js b/src/common/hook/useGithubAuthConfig.ts similarity index 96% rename from src/common/hook/useGithubAuthConfig.js rename to src/common/hook/useGithubAuthConfig.ts index ac2173ef..5fa29c4a 100644 --- a/src/common/hook/useGithubAuthConfig.js +++ b/src/common/hook/useGithubAuthConfig.ts @@ -1,9 +1,9 @@ import { useState, useEffect } from "react"; -// import toast from "react-hot-toast"; import { useGetGithubAuthConfigQuery, useUpdateGithubAuthConfigMutation } from "../../app/services/server"; + export default function useGithubAuthConfig() { const [changed, setChanged] = useState(false); const [config, setConfig] = useState({}); diff --git a/src/common/hook/useGoogleAuthConfig.js b/src/common/hook/useGoogleAuthConfig.ts similarity index 96% rename from src/common/hook/useGoogleAuthConfig.js rename to src/common/hook/useGoogleAuthConfig.ts index a2361221..be683745 100644 --- a/src/common/hook/useGoogleAuthConfig.js +++ b/src/common/hook/useGoogleAuthConfig.ts @@ -1,9 +1,9 @@ import { useState, useEffect } from "react"; -// import toast from "react-hot-toast"; import { useGetGoogleAuthConfigQuery, useUpdateGoogleAuthConfigMutation } from "../../app/services/server"; + export default function useGoogleAuthConfig() { const [changed, setChanged] = useState(false); const [clientId, setClientId] = useState(""); diff --git a/src/common/hook/useInviteLink.js b/src/common/hook/useInviteLink.ts similarity index 95% rename from src/common/hook/useInviteLink.js rename to src/common/hook/useInviteLink.ts index 8adcd0d8..4ebc3842 100644 --- a/src/common/hook/useInviteLink.js +++ b/src/common/hook/useInviteLink.ts @@ -2,7 +2,8 @@ import { useState, useEffect } from "react"; import useCopy from "./useCopy"; import { useGetSMTPStatusQuery } from "../../app/services/server"; import { useLazyCreateInviteLinkQuery as useCreateChannelInviteLinkQuery } from "../../app/services/channel"; -export default function useInviteLink(cid = "") { + +export default function useInviteLink(cid: string | null = "") { const [finalLink, setFinalLink] = useState(""); const { data: SMTPEnabled, isSuccess: smtpStatusFetchSuccess } = useGetSMTPStatusQuery(); const [generateChannelInviteLink, { data: channelInviteLink, isLoading: generatingChannelLink }] = diff --git a/src/common/hook/useLeaveChannel.js b/src/common/hook/useLeaveChannel.ts similarity index 81% rename from src/common/hook/useLeaveChannel.js rename to src/common/hook/useLeaveChannel.ts index 294961ce..f6693e68 100644 --- a/src/common/hook/useLeaveChannel.js +++ b/src/common/hook/useLeaveChannel.ts @@ -1,8 +1,8 @@ -// import React from 'react' -import { useSelector } from "react-redux"; import { useUpdateChannelMutation, useLazyLeaveChannelQuery } from "../../app/services/channel"; -export default function useLeaveChannel(cid = null) { - const { channel, loginUid } = useSelector((store) => { +import { useAppSelector } from "../../app/store"; + +export default function useLeaveChannel(cid: number) { + const { channel, loginUid } = useAppSelector((store) => { return { channel: store.channels.byId[cid], loginUid: store.authData.uid }; }); const [update, { isLoading: transfering, isSuccess: transferSuccess }] = diff --git a/src/common/hook/useLogout.js b/src/common/hook/useLogout.ts similarity index 100% rename from src/common/hook/useLogout.js rename to src/common/hook/useLogout.ts diff --git a/src/common/hook/useMessageFeed.js b/src/common/hook/useMessageFeed.ts similarity index 100% rename from src/common/hook/useMessageFeed.js rename to src/common/hook/useMessageFeed.ts diff --git a/src/common/hook/useNormalizeMessage.js b/src/common/hook/useNormalizeMessage.ts similarity index 82% rename from src/common/hook/useNormalizeMessage.js rename to src/common/hook/useNormalizeMessage.ts index 4d091ab6..1d06a7d4 100644 --- a/src/common/hook/useNormalizeMessage.js +++ b/src/common/hook/useNormalizeMessage.ts @@ -1,8 +1,9 @@ import { useState, useEffect } from "react"; -import { normalizeArchiveData } from "../../common/utils"; +import { normalizeArchiveData } from "../utils"; import { useLazyGetArchiveMessageQuery } from "../../app/services/message"; + export default function useNormalizeMessage() { - const [filePath, setFilePath] = useState(null); + const [filePath, setFilePath] = useState(null); const [normalizedMessages, setNormalizedMessages] = useState(null); const [getArchiveMessage, { data, isError, isLoading, isSuccess }] = useLazyGetArchiveMessageQuery(); @@ -18,7 +19,7 @@ export default function useNormalizeMessage() { } }, [filePath]); - const normalizeMessage = (file_path) => { + const normalizeMessage = (file_path: string) => { setFilePath(file_path); }; return { diff --git a/src/common/hook/useNotification.js b/src/common/hook/useNotification.ts similarity index 100% rename from src/common/hook/useNotification.js rename to src/common/hook/useNotification.ts diff --git a/src/common/hook/usePWABadge.js b/src/common/hook/usePWABadge.ts similarity index 99% rename from src/common/hook/usePWABadge.js rename to src/common/hook/usePWABadge.ts index a6fd8b15..d1f05f5c 100644 --- a/src/common/hook/usePWABadge.js +++ b/src/common/hook/usePWABadge.ts @@ -1,5 +1,6 @@ import { useEffect } from "react"; import PWABadge from "pwa-badge"; + export default function usePWABadge() { // Create an Instance const badge = new PWABadge(); diff --git a/src/common/hook/usePinMessage.js b/src/common/hook/usePinMessage.ts similarity index 88% rename from src/common/hook/usePinMessage.js rename to src/common/hook/usePinMessage.ts index 65dbc13a..1eb701be 100644 --- a/src/common/hook/usePinMessage.js +++ b/src/common/hook/usePinMessage.ts @@ -1,9 +1,10 @@ import { useState, useEffect } from "react"; -import { useSelector } from "react-redux"; import { usePinMessageMutation, useUnpinMessageMutation } from "../../app/services/message"; -export default function usePinMessage(cid = null) { +import { useAppSelector } from "../../app/store"; + +export default function usePinMessage(cid: number) { const [pins, setPins] = useState([]); - const { channel, loginUser } = useSelector((store) => { + const { channel, loginUser } = useAppSelector((store) => { return { channel: store.channels.byId[cid], loginUser: store.contacts.byId[store.authData.uid] diff --git a/src/common/hook/useRemoveLocalMessage.js b/src/common/hook/useRemoveLocalMessage.ts similarity index 100% rename from src/common/hook/useRemoveLocalMessage.js rename to src/common/hook/useRemoveLocalMessage.ts diff --git a/src/common/hook/useSendMessage.js b/src/common/hook/useSendMessage.ts similarity index 100% rename from src/common/hook/useSendMessage.js rename to src/common/hook/useSendMessage.ts diff --git a/src/common/hook/useStreaming/chat.handler.js b/src/common/hook/useStreaming/chat.handler.ts similarity index 99% rename from src/common/hook/useStreaming/chat.handler.js rename to src/common/hook/useStreaming/chat.handler.ts index b8ef985e..fc247061 100644 --- a/src/common/hook/useStreaming/chat.handler.js +++ b/src/common/hook/useStreaming/chat.handler.ts @@ -6,6 +6,7 @@ import { addFileMessage, removeFileMessage } from "../../../app/slices/message.f import { addUserMsg, removeUserMsg } from "../../../app/slices/message.user"; import { updateAfterMid } from "../../../app/slices/footprint"; import { ContentTypes } from "../../../app/config"; + const handler = (data, dispatch, currState) => { const { mid, @@ -155,4 +156,5 @@ const handler = (data, dispatch, currState) => { break; } }; + export default handler; diff --git a/src/common/hook/useStreaming/index.js b/src/common/hook/useStreaming/index.ts similarity index 98% rename from src/common/hook/useStreaming/index.js rename to src/common/hook/useStreaming/index.ts index 20a13d3a..9d7e9fd5 100644 --- a/src/common/hook/useStreaming/index.js +++ b/src/common/hook/useStreaming/index.ts @@ -2,7 +2,6 @@ import { useEffect, useState } from "react"; import { fetchEventSource, EventStreamContentType } from "@microsoft/fetch-event-source"; import toast from "react-hot-toast"; import dayjs from "dayjs"; - import BASE_URL from "../../../app/config"; import { setReady } from "../../../app/slices/ui"; import { useRenewMutation } from "../../../app/services/auth"; @@ -22,10 +21,12 @@ import { import { updateUsersByLogs, updateUsersStatus } from "../../../app/slices/contacts"; import { resetAuthData } from "../../../app/slices/auth.data"; import chatMessageHandler from "./chat.handler"; -import store from "../../../app/store"; -import { useDispatch, useSelector } from "react-redux"; +import store, { useAppDispatch, useAppSelector } from "../../../app/store"; + class RetriableError extends Error {} + class FatalError extends Error {} + const getQueryString = (params = {}) => { const sp = new URLSearchParams(); Object.entries(params).forEach(([key, val]) => { @@ -40,19 +41,21 @@ const getQueryString = (params = {}) => { // initialized: "initialized", // streaming: "streaming", // }; -let inter = null; +let inter: number | null = null; + export default function useStreaming() { const [readyPullData, setReadyPullData] = useState(false); const { authData: { uid: loginUid }, ui: { ready, online }, footprint: { afterMid, usersVersion, readUsers, readChannels } - } = useSelector((store) => store); + } = useAppSelector((store) => store); const [renewToken] = useRenewMutation(); - const dispatch = useDispatch(); + const dispatch = useAppDispatch(); let initialized = false; let initializing = false; let controller = new AbortController(); + const startStreaming = async () => { console.log("start streaming", initialized, initializing); if (initialized || initializing) return; @@ -310,15 +313,18 @@ export default function useStreaming() { // for controlling return controller; }; + const stopStreaming = () => { console.log("stop st"); if (controller && controller.abort) { controller.abort(); } }; + const setStreamingReady = (ready) => { setReadyPullData(ready); }; + useEffect(() => { console.log("network changed", online, readyPullData); if (readyPullData) { diff --git a/src/common/hook/useUploadFile.js b/src/common/hook/useUploadFile.ts similarity index 95% rename from src/common/hook/useUploadFile.js rename to src/common/hook/useUploadFile.ts index a79ba031..80ef54ab 100644 --- a/src/common/hook/useUploadFile.js +++ b/src/common/hook/useUploadFile.ts @@ -1,15 +1,14 @@ import { useState, useRef } from "react"; -import { useDispatch, useSelector } from "react-redux"; -// import { ContentTypes } from "../../app/config"; +import toast from "react-hot-toast"; import { updateUploadFiles } from "../../app/slices/ui"; import BASE_URL, { FILE_SLICE_SIZE } from "../../app/config"; import { usePrepareUploadFileMutation, useUploadFileMutation } from "../../app/services/message"; -import toast from "react-hot-toast"; +import { useAppDispatch, useAppSelector } from "../../app/store"; export default function useUploadFile(props = {}) { const { context = "", id = "" } = props; - const dispatch = useDispatch(); - const { stageFiles, replying } = useSelector((store) => { + const dispatch = useAppDispatch(); + const { stageFiles, replying } = useAppSelector((store) => { return { stageFiles: store.ui.uploadFiles[`${context}_${id}`] || [], replying: store.message.replying[`${context}_${id}`] @@ -35,6 +34,7 @@ export default function useUploadFile(props = {}) { formData.append("chunk_is_last", is_last); return uploadFileFn(formData); }; + const uploadFile = async (file) => { if (!file) return; setData(null); @@ -107,12 +107,15 @@ export default function useUploadFile(props = {}) { setData(res); return res; }; + const stopUploading = () => { canneledRef.current = true; }; + const removeStageFile = (idx) => { dispatch(updateUploadFiles({ context, id, operation: "remove", index: idx })); }; + const addStageFile = (fileData = {}) => { if (replying) { toast.error("Only text is supported when replying a message"); @@ -120,9 +123,11 @@ export default function useUploadFile(props = {}) { } dispatch(updateUploadFiles({ context, id, data: fileData })); }; + const resetStageFiles = () => { dispatch(updateUploadFiles({ context, id, operation: "reset" })); }; + const updateStageFile = (idx, data = {}) => { dispatch( updateUploadFiles({ @@ -134,6 +139,7 @@ export default function useUploadFile(props = {}) { }) ); }; + return { stopUploading, data, diff --git a/src/common/utils.js b/src/common/utils.tsx similarity index 99% rename from src/common/utils.js rename to src/common/utils.tsx index 3669c409..82a5c05f 100644 --- a/src/common/utils.js +++ b/src/common/utils.tsx @@ -6,9 +6,11 @@ import IconUnkown from "../assets/icons/file.unkown.svg"; import IconDoc from "../assets/icons/file.doc.svg"; import IconCode from "../assets/icons/file.code.svg"; import IconImage from "../assets/icons/file.image.svg"; + export const isImage = (file_type = "", size = 0) => { return file_type.startsWith("image") && size <= FILE_IMAGE_SIZE; }; + const deepSortObject = (obj) => { return Object.fromEntries( Object.entries(obj) @@ -19,6 +21,7 @@ const deepSortObject = (obj) => { .sort() ); }; + export const isObjectEqual = (obj1, obj2) => { // Check for reference equal if (obj1 === obj2) return true; diff --git a/src/routes/chat/ChannelChat/PinList.js b/src/routes/chat/ChannelChat/PinList.tsx similarity index 100% rename from src/routes/chat/ChannelChat/PinList.js rename to src/routes/chat/ChannelChat/PinList.tsx diff --git a/src/routes/chat/ChannelChat/index.js b/src/routes/chat/ChannelChat/index.tsx similarity index 100% rename from src/routes/chat/ChannelChat/index.js rename to src/routes/chat/ChannelChat/index.tsx diff --git a/src/routes/chat/ChannelChat/styled.js b/src/routes/chat/ChannelChat/styled.tsx similarity index 100% rename from src/routes/chat/ChannelChat/styled.js rename to src/routes/chat/ChannelChat/styled.tsx diff --git a/src/routes/chat/ChannelList/NavItem.js b/src/routes/chat/ChannelList/NavItem.tsx similarity index 99% rename from src/routes/chat/ChannelList/NavItem.js rename to src/routes/chat/ChannelList/NavItem.tsx index ed42d553..cb1b0d97 100644 --- a/src/routes/chat/ChannelList/NavItem.js +++ b/src/routes/chat/ChannelList/NavItem.tsx @@ -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"; diff --git a/src/routes/chat/ChannelList/index.js b/src/routes/chat/ChannelList/index.tsx similarity index 87% rename from src/routes/chat/ChannelList/index.js rename to src/routes/chat/ChannelList/index.tsx index 3f680632..7c4c91f7 100644 --- a/src/routes/chat/ChannelList/index.js +++ b/src/routes/chat/ChannelList/index.tsx @@ -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 }; }); diff --git a/src/routes/chat/ChannelList/styled.js b/src/routes/chat/ChannelList/styled.tsx similarity index 99% rename from src/routes/chat/ChannelList/styled.js rename to src/routes/chat/ChannelList/styled.tsx index 90551b73..f002d091 100644 --- a/src/routes/chat/ChannelList/styled.js +++ b/src/routes/chat/ChannelList/styled.tsx @@ -82,4 +82,5 @@ const Styled = styled(NavLink)` } } `; + export default Styled; diff --git a/src/routes/chat/DMChat/index.js b/src/routes/chat/DMChat/index.tsx similarity index 100% rename from src/routes/chat/DMChat/index.js rename to src/routes/chat/DMChat/index.tsx index ecb9d8da..fe421309 100644 --- a/src/routes/chat/DMChat/index.js +++ b/src/routes/chat/DMChat/index.tsx @@ -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, diff --git a/src/routes/chat/DMChat/styled.js b/src/routes/chat/DMChat/styled.tsx similarity index 100% rename from src/routes/chat/DMChat/styled.js rename to src/routes/chat/DMChat/styled.tsx diff --git a/src/routes/chat/DMList/NavItem.js b/src/routes/chat/DMList/NavItem.tsx similarity index 100% rename from src/routes/chat/DMList/NavItem.js rename to src/routes/chat/DMList/NavItem.tsx diff --git a/src/routes/chat/DMList/index.js b/src/routes/chat/DMList/index.tsx similarity index 51% rename from src/routes/chat/DMList/index.js rename to src/routes/chat/DMList/index.tsx index 4e280184..2ac1c786 100644 --- a/src/routes/chat/DMList/index.js +++ b/src/routes/chat/DMList/index.tsx @@ -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 = ({ 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 ( - - ); - }); -} + return ( + <> + {sessions + .sort((s1, s2) => { + if (!s1.lastMid) return s2.lastMid - Infinity; + return s2.lastMid - s1.lastMid; + }) + .map(({ lastMid, uid, unreads }) => { + return ( + + ); + })} + + ); +}; + +export default DMList; diff --git a/src/routes/chat/FavList.js b/src/routes/chat/FavList.tsx similarity index 99% rename from src/routes/chat/FavList.js rename to src/routes/chat/FavList.tsx index 5391de82..b30c24e4 100644 --- a/src/routes/chat/FavList.js +++ b/src/routes/chat/FavList.tsx @@ -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) => { diff --git a/src/routes/chat/Layout/Operations.js b/src/routes/chat/Layout/Operations.tsx similarity index 94% rename from src/routes/chat/Layout/Operations.js rename to src/routes/chat/Layout/Operations.tsx index 31b9a7ae..1be2ac98 100644 --- a/src/routes/chat/Layout/Operations.js +++ b/src/routes/chat/Layout/Operations.tsx @@ -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 ( <> diff --git a/src/routes/chat/Layout/index.js b/src/routes/chat/Layout/index.tsx similarity index 87% rename from src/routes/chat/Layout/index.js rename to src/routes/chat/Layout/index.tsx index 56cd5684..8bddf4b2 100644 --- a/src/routes/chat/Layout/index.js +++ b/src/routes/chat/Layout/index.tsx @@ -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 = ({ 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(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 && } @@ -112,4 +124,6 @@ export default function Layout({ ); -} +}; + +export default Layout; diff --git a/src/routes/chat/Layout/styled.js b/src/routes/chat/Layout/styled.tsx similarity index 100% rename from src/routes/chat/Layout/styled.js rename to src/routes/chat/Layout/styled.tsx diff --git a/src/routes/chat/LoadMore.js b/src/routes/chat/LoadMore.tsx similarity index 100% rename from src/routes/chat/LoadMore.js rename to src/routes/chat/LoadMore.tsx diff --git a/src/routes/chat/SessionList/ContextMenu.js b/src/routes/chat/SessionList/ContextMenu.tsx similarity index 99% rename from src/routes/chat/SessionList/ContextMenu.js rename to src/routes/chat/SessionList/ContextMenu.tsx index e3157cf9..99adccfe 100644 --- a/src/routes/chat/SessionList/ContextMenu.js +++ b/src/routes/chat/SessionList/ContextMenu.tsx @@ -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" ? [ diff --git a/src/routes/chat/SessionList/Session.js b/src/routes/chat/SessionList/Session.tsx similarity index 99% rename from src/routes/chat/SessionList/Session.js rename to src/routes/chat/SessionList/Session.tsx index af990247..7fbc26b0 100644 --- a/src/routes/chat/SessionList/Session.js +++ b/src/routes/chat/SessionList/Session.tsx @@ -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 (
  • { + 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 ( <> diff --git a/src/routes/chat/SessionList/styled.js b/src/routes/chat/SessionList/styled.tsx similarity index 100% rename from src/routes/chat/SessionList/styled.js rename to src/routes/chat/SessionList/styled.tsx diff --git a/src/routes/chat/ThirdApps.js b/src/routes/chat/ThirdApps.tsx similarity index 100% rename from src/routes/chat/ThirdApps.js rename to src/routes/chat/ThirdApps.tsx diff --git a/src/routes/chat/index.team.js b/src/routes/chat/index.team.tsx similarity index 100% rename from src/routes/chat/index.team.js rename to src/routes/chat/index.team.tsx diff --git a/src/routes/chat/index.js b/src/routes/chat/index.tsx similarity index 100% rename from src/routes/chat/index.js rename to src/routes/chat/index.tsx diff --git a/src/routes/chat/styled.js b/src/routes/chat/styled.tsx similarity index 100% rename from src/routes/chat/styled.js rename to src/routes/chat/styled.tsx diff --git a/src/routes/chat/useSession.js b/src/routes/chat/useSession.ts similarity index 85% rename from src/routes/chat/useSession.js rename to src/routes/chat/useSession.ts index 1ad6dd01..40ba2f62 100644 --- a/src/routes/chat/useSession.js +++ b/src/routes/chat/useSession.ts @@ -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, diff --git a/src/routes/chat/utils.js b/src/routes/chat/utils.tsx similarity index 99% rename from src/routes/chat/utils.js rename to src/routes/chat/utils.tsx index d50392f9..f5a3bba2 100644 --- a/src/routes/chat/utils.js +++ b/src/routes/chat/utils.tsx @@ -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 ); }; + export const renderMessageFragment = ({ selectMode = false, isFirst = false, diff --git a/src/routes/contacts/index.js b/src/routes/contacts/index.tsx similarity index 100% rename from src/routes/contacts/index.js rename to src/routes/contacts/index.tsx diff --git a/src/routes/contacts/styled.js b/src/routes/contacts/styled.tsx similarity index 100% rename from src/routes/contacts/styled.js rename to src/routes/contacts/styled.tsx diff --git a/src/routes/favs/index.js b/src/routes/favs/index.tsx similarity index 100% rename from src/routes/favs/index.js rename to src/routes/favs/index.tsx diff --git a/src/routes/favs/styled.js b/src/routes/favs/styled.tsx similarity index 100% rename from src/routes/favs/styled.js rename to src/routes/favs/styled.tsx diff --git a/src/routes/home/Menu.js b/src/routes/home/Menu.tsx similarity index 100% rename from src/routes/home/Menu.js rename to src/routes/home/Menu.tsx diff --git a/src/routes/home/ServerDropList.js b/src/routes/home/ServerDropList.tsx similarity index 100% rename from src/routes/home/ServerDropList.js rename to src/routes/home/ServerDropList.tsx diff --git a/src/routes/home/Tools.js b/src/routes/home/Tools.tsx similarity index 100% rename from src/routes/home/Tools.js rename to src/routes/home/Tools.tsx diff --git a/src/routes/home/User.js b/src/routes/home/User.tsx similarity index 73% rename from src/routes/home/User.js rename to src/routes/home/User.tsx index da955210..8ab2342e 100644 --- a/src/routes/home/User.js +++ b/src/routes/home/User.tsx @@ -1,8 +1,9 @@ -// import React from 'react'; +import { FC } from "react"; import styled from "styled-components"; -import Avatar from "../../common/component/Avatar"; -import { useSelector } from "react-redux"; import { NavLink, useLocation } from "react-router-dom"; +import Avatar from "../../common/component/Avatar"; +import { useAppSelector } from "../../app/store"; + const StyledWrapper = styled.div` padding: 10px 12px; .avatar { @@ -16,10 +17,16 @@ const StyledWrapper = styled.div` } } `; -export default function User({ uid = null }) { + +interface Props { + uid: number; +} + +const User: FC = ({ uid }) => { const { pathname } = useLocation(); - const user = useSelector((store) => store.contacts.byId[uid]); + const user = useAppSelector((store) => store.contacts.byId[uid]); if (!user) return null; + return ( @@ -29,4 +36,6 @@ export default function User({ uid = null }) { ); -} +}; + +export default User; diff --git a/src/routes/home/index.js b/src/routes/home/index.tsx similarity index 100% rename from src/routes/home/index.js rename to src/routes/home/index.tsx diff --git a/src/routes/home/styled.js b/src/routes/home/styled.tsx similarity index 100% rename from src/routes/home/styled.js rename to src/routes/home/styled.tsx diff --git a/src/routes/home/usePreload.js b/src/routes/home/usePreload.ts similarity index 94% rename from src/routes/home/usePreload.js rename to src/routes/home/usePreload.ts index d8f1893a..4457c01d 100644 --- a/src/routes/home/usePreload.js +++ b/src/routes/home/usePreload.ts @@ -1,10 +1,10 @@ import { useEffect } from "react"; -import { useSelector } from "react-redux"; import initCache, { useRehydrate } from "../../app/cache"; import { useLazyGetFavoritesQuery } from "../../app/services/message"; import { useLazyGetContactsQuery } from "../../app/services/contact"; import { useLazyGetServerQuery } from "../../app/services/server"; import useStreaming from "../../common/hook/useStreaming"; +import { useAppSelector } from "../../app/store"; // pollingInterval: 0, // const querySetting = { // refetchOnMountOrArgChange: true, @@ -12,7 +12,7 @@ import useStreaming from "../../common/hook/useStreaming"; // let request = null; export default function usePreload() { const { rehydrate, rehydrated } = useRehydrate(); - const { loginUid, token } = useSelector((store) => { + const { loginUid, token } = useAppSelector((store) => { return { loginUid: store.authData.uid, token: store.authData.token }; }); const { setStreamingReady } = useStreaming(); diff --git a/src/routes/login/MagicLinkLogin.js b/src/routes/login/MagicLinkLogin.tsx similarity index 91% rename from src/routes/login/MagicLinkLogin.js rename to src/routes/login/MagicLinkLogin.tsx index b26f57cc..8f267eee 100644 --- a/src/routes/login/MagicLinkLogin.js +++ b/src/routes/login/MagicLinkLogin.tsx @@ -1,16 +1,18 @@ -// import { useState, useEffect } from "react"; -import Button from "../../common/component/styled/Button"; import styled from "styled-components"; import { useNavigate } from "react-router-dom"; +import Button from "../../common/component/styled/Button"; + const StyledMagicButton = styled(Button)` width: 100%; margin-bottom: 16px; `; + export default function MagicLinkLogin() { const navigate = useNavigate(); const handleGoogleLogin = () => { navigate("/send_magic_link"); // signIn(); }; + return Sign in with Magic Link; } diff --git a/src/routes/login/MetamaskLoginButton.js b/src/routes/login/MetamaskLoginButton.tsx similarity index 100% rename from src/routes/login/MetamaskLoginButton.js rename to src/routes/login/MetamaskLoginButton.tsx diff --git a/src/routes/login/OidcLoginButton.js b/src/routes/login/OidcLoginButton.tsx similarity index 100% rename from src/routes/login/OidcLoginButton.js rename to src/routes/login/OidcLoginButton.tsx diff --git a/src/routes/login/OidcLoginEntry.js b/src/routes/login/OidcLoginEntry.tsx similarity index 99% rename from src/routes/login/OidcLoginEntry.js rename to src/routes/login/OidcLoginEntry.tsx index e04565b5..bc71cb40 100644 --- a/src/routes/login/OidcLoginEntry.js +++ b/src/routes/login/OidcLoginEntry.tsx @@ -13,6 +13,7 @@ export default function OidcLoginEntry({ issuer }) { redirect_uri: `${location.origin}/#/login` }); }; + useEffect(() => { if (isSuccess) { console.log("wtf", data); @@ -21,6 +22,7 @@ export default function OidcLoginEntry({ issuer }) { } }, [data, isSuccess]); console.log(issuer); + return ( {Boolean(issuer.favicon) && icon} diff --git a/src/routes/login/SignUpLink.js b/src/routes/login/SignUpLink.tsx similarity index 99% rename from src/routes/login/SignUpLink.js rename to src/routes/login/SignUpLink.tsx index 9400df8b..edeca3d4 100644 --- a/src/routes/login/SignUpLink.js +++ b/src/routes/login/SignUpLink.tsx @@ -21,11 +21,13 @@ const StyledSignUpLink = styled.p` cursor: pointer; } `; + export default function MagicLinkLogin() { const navigate = useNavigate(); const handleSignUp = () => { navigate("/register"); }; + return ( Don’t have an account? diff --git a/src/routes/login/index.js b/src/routes/login/index.tsx similarity index 99% rename from src/routes/login/index.js rename to src/routes/login/index.tsx index 459aa63a..433aa78a 100644 --- a/src/routes/login/index.js +++ b/src/routes/login/index.tsx @@ -16,6 +16,7 @@ import useGoogleAuthConfig from "../../common/hook/useGoogleAuthConfig"; import useGithubAuthConfig from "../../common/hook/useGithubAuthConfig"; import GoogleLoginButton from "../../common/component/GoogleLoginButton"; import GithubLoginButton from "../../common/component/GithubLoginButton"; + export default function LoginPage() { const { data: enableSMTP } = useGetSMTPStatusQuery(); const [login, { isSuccess, isLoading, error }] = useLoginMutation(); @@ -26,6 +27,7 @@ export default function LoginPage() { email: "", password: "" }); + useEffect(() => { const query = new URLSearchParams(location.search); // const githubCode = query.get("gcode"); @@ -121,6 +123,7 @@ export default function LoginPage() { }; const { email, password } = input; if (!loginConfigSuccess) return null; + const { magic_link, github: enableGithubLogin, @@ -129,10 +132,12 @@ export default function LoginPage() { oidc = [], who_can_sign_up: whoCanSignUp } = loginConfig; + const enableMagicLink = enableSMTP && magic_link; const googleLogin = enableGoogleLogin && clientId; const hasDivider = enableMagicLink || googleLogin || enableMetamaskLogin || oidc.length > 0 || enableGithubLogin; + return (
    diff --git a/src/routes/login/styled.js b/src/routes/login/styled.tsx similarity index 99% rename from src/routes/login/styled.js rename to src/routes/login/styled.tsx index 8c32ae0a..957a0d34 100644 --- a/src/routes/login/styled.js +++ b/src/routes/login/styled.tsx @@ -1,5 +1,6 @@ import styled from "styled-components"; import Button from "../../common/component/styled/Button"; + export const StyledSocialButton = styled(Button)` width: 100%; margin-bottom: 16px; @@ -15,6 +16,7 @@ export const StyledSocialButton = styled(Button)` height: 24px; } `; + const StyledWrapper = styled.div` display: flex; justify-content: center; diff --git a/src/routes/oauth/index.js b/src/routes/oauth/index.tsx similarity index 100% rename from src/routes/oauth/index.js rename to src/routes/oauth/index.tsx diff --git a/src/routes/oauth/styled.js b/src/routes/oauth/styled.tsx similarity index 88% rename from src/routes/oauth/styled.js rename to src/routes/oauth/styled.tsx index c4b5e936..ac647072 100644 --- a/src/routes/oauth/styled.js +++ b/src/routes/oauth/styled.tsx @@ -1,4 +1,5 @@ import styled from "styled-components"; + const StyledWrapper = styled.div` display: flex; justify-content: center; @@ -7,7 +8,7 @@ const StyledWrapper = styled.div` .form { padding: 36px 40px 32px 40px; /* border: 1px solid #eee; */ - box-shadow: 0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06); + box-shadow: 0 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06); border-radius: 12px; .tips { display: flex; @@ -41,7 +42,7 @@ const StyledWrapper = styled.div` width: 360px; background: #ffffff; border: 1px solid #d0d5dd; - box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05); + box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05); border-radius: 8px; padding: 10px 14px; font-weight: normal; @@ -61,7 +62,7 @@ const StyledWrapper = styled.div` padding: 10px; background: #1fe1f9; border: 1px solid #1fe1f9; - box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05); + box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05); border-radius: 8px; &.google { color: #344054; diff --git a/src/routes/onboarding/index.js b/src/routes/onboarding/index.tsx similarity index 100% rename from src/routes/onboarding/index.js rename to src/routes/onboarding/index.tsx diff --git a/src/routes/onboarding/steps/adminAccount.js b/src/routes/onboarding/steps/adminAccount.tsx similarity index 100% rename from src/routes/onboarding/steps/adminAccount.js rename to src/routes/onboarding/steps/adminAccount.tsx diff --git a/src/routes/onboarding/steps/donePage.js b/src/routes/onboarding/steps/donePage.tsx similarity index 100% rename from src/routes/onboarding/steps/donePage.js rename to src/routes/onboarding/steps/donePage.tsx diff --git a/src/routes/onboarding/steps/inviteLink.js b/src/routes/onboarding/steps/inviteLink.tsx similarity index 100% rename from src/routes/onboarding/steps/inviteLink.js rename to src/routes/onboarding/steps/inviteLink.tsx diff --git a/src/routes/onboarding/steps/serverName.js b/src/routes/onboarding/steps/serverName.tsx similarity index 100% rename from src/routes/onboarding/steps/serverName.js rename to src/routes/onboarding/steps/serverName.tsx diff --git a/src/routes/onboarding/steps/welcomePage.js b/src/routes/onboarding/steps/welcomePage.tsx similarity index 100% rename from src/routes/onboarding/steps/welcomePage.js rename to src/routes/onboarding/steps/welcomePage.tsx diff --git a/src/routes/onboarding/steps/whoCanSignUp.js b/src/routes/onboarding/steps/whoCanSignUp.tsx similarity index 100% rename from src/routes/onboarding/steps/whoCanSignUp.js rename to src/routes/onboarding/steps/whoCanSignUp.tsx diff --git a/src/routes/onboarding/styled.js b/src/routes/onboarding/styled.tsx similarity index 100% rename from src/routes/onboarding/styled.js rename to src/routes/onboarding/styled.tsx diff --git a/src/routes/onboarding/useServerSetup.js b/src/routes/onboarding/useServerSetup.ts similarity index 100% rename from src/routes/onboarding/useServerSetup.js rename to src/routes/onboarding/useServerSetup.ts diff --git a/src/routes/reg/EmailNextStepTip.js b/src/routes/reg/EmailNextStepTip.tsx similarity index 96% rename from src/routes/reg/EmailNextStepTip.js rename to src/routes/reg/EmailNextStepTip.tsx index 02143d6a..47b6ce3f 100644 --- a/src/routes/reg/EmailNextStepTip.js +++ b/src/routes/reg/EmailNextStepTip.tsx @@ -1,5 +1,5 @@ -// import React from "react"; import styled from "styled-components"; + const Styled = styled.div` display: flex; flex-direction: column; @@ -22,6 +22,7 @@ const Styled = styled.div` } } `; + export default function EmailNextTip() { return ( diff --git a/src/routes/reg/ExpiredTip.js b/src/routes/reg/ExpiredTip.tsx similarity index 99% rename from src/routes/reg/ExpiredTip.js rename to src/routes/reg/ExpiredTip.tsx index 7a6f44c1..85c79602 100644 --- a/src/routes/reg/ExpiredTip.js +++ b/src/routes/reg/ExpiredTip.tsx @@ -1,5 +1,6 @@ // import React from "react"; import styled from "styled-components"; + const Styled = styled.div` display: flex; flex-direction: column; @@ -22,6 +23,7 @@ const Styled = styled.div` } } `; + export default function ExpiredTip() { return ( diff --git a/src/routes/reg/Register.js b/src/routes/reg/Register.tsx similarity index 89% rename from src/routes/reg/Register.js rename to src/routes/reg/Register.tsx index e8285d9b..8d42dcfa 100644 --- a/src/routes/reg/Register.js +++ b/src/routes/reg/Register.tsx @@ -1,12 +1,9 @@ -import { useState, useEffect } from "react"; -// import { useDispatch } from "react-redux"; +import { useState, useEffect, FormEvent, ChangeEvent } from "react"; import { useNavigate } from "react-router-dom"; -// import toast from "react-hot-toast"; import Input from "../../common/component/styled/Input"; import Button from "../../common/component/styled/Button"; import { useSendRegMagicLinkMutation } from "../../app/services/auth"; import EmailNextTip from "./EmailNextStepTip"; -// import { useSendLoginMagicLinkMutation } from "../../app/services/auth"; export default function Reg() { const [sendRegMagicLink, { isLoading, data, isSuccess }] = useSendRegMagicLinkMutation(); @@ -17,6 +14,7 @@ export default function Reg() { password: "", confirmPassword: "" }); + useEffect(() => { const query = new URLSearchParams(location.search); // const githubCode = query.get("gcode"); @@ -25,6 +23,7 @@ export default function Reg() { setMagicToken(token); } }, []); + useEffect(() => { if (isSuccess && data) { const { new_magic_token, mail_is_sent } = data; @@ -35,7 +34,7 @@ export default function Reg() { } }, [isSuccess, data]); - const handleReg = (evt) => { + const handleReg = (evt: FormEvent) => { evt.preventDefault(); const { email, password } = input; sendRegMagicLink({ @@ -46,7 +45,7 @@ export default function Reg() { // sendMagicLink(email); }; - const handleInput = (evt) => { + const handleInput = (evt: ChangeEvent) => { const { type } = evt.target.dataset; const { value } = evt.target; // console.log(type, value); @@ -55,6 +54,7 @@ export default function Reg() { return { ...prev }; }); }; + const { email, password } = input; if (data?.mail_is_sent) return ; return ( diff --git a/src/routes/reg/SignInLink.js b/src/routes/reg/SignInLink.tsx similarity index 99% rename from src/routes/reg/SignInLink.js rename to src/routes/reg/SignInLink.tsx index c4bd9903..6af02144 100644 --- a/src/routes/reg/SignInLink.js +++ b/src/routes/reg/SignInLink.tsx @@ -20,6 +20,7 @@ const StyledSignInLink = styled.p` cursor: pointer; } `; + export default function SignInLink() { const navigate = useNavigate(); const handleSignIn = () => { diff --git a/src/routes/reg/index.js b/src/routes/reg/index.tsx similarity index 100% rename from src/routes/reg/index.js rename to src/routes/reg/index.tsx diff --git a/src/routes/reg/styled.js b/src/routes/reg/styled.tsx similarity index 93% rename from src/routes/reg/styled.js rename to src/routes/reg/styled.tsx index 14d3e46b..caaeb35f 100644 --- a/src/routes/reg/styled.js +++ b/src/routes/reg/styled.tsx @@ -1,4 +1,5 @@ import styled from "styled-components"; + const StyledWrapper = styled.div` display: flex; justify-content: center; @@ -7,7 +8,7 @@ const StyledWrapper = styled.div` .form { max-width: 440px; padding: 36px 40px 32px 40px; - box-shadow: 0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06); + box-shadow: 0 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06); border-radius: 12px; .tips { display: flex; diff --git a/src/routes/resources/Filter/Channel.js b/src/routes/resources/Filter/Channel.tsx similarity index 94% rename from src/routes/resources/Filter/Channel.js rename to src/routes/resources/Filter/Channel.tsx index 8303152a..91b04573 100644 --- a/src/routes/resources/Filter/Channel.js +++ b/src/routes/resources/Filter/Channel.tsx @@ -1,16 +1,15 @@ -// import React from 'react' -// import { useSelector } from "react-redux"; import styled from "styled-components"; import CheckSign from "../../../assets/icons/check.sign.svg"; import ChannelIcon from "../../../common/component/ChannelIcon"; import Search from "../Search"; import useFilteredChannels from "../../../common/hook/useFilteredChannels"; + const Styled = styled.div` padding: 0 4px 4px 4px; background: #ffffff; max-height: 400px; overflow: auto; - box-shadow: 0px 24px 48px -12px rgba(16, 24, 40, 0.18); + box-shadow: 0 24px 48px -12px rgba(16, 24, 40, 0.18); border-radius: 8px; display: flex; flex-direction: column; @@ -52,11 +51,13 @@ const Styled = styled.div` } } `; + export default function Channel({ select = "", updateFilter }) { const { input, updateInput, channels } = useFilteredChannels(); const handleClick = (gid) => { updateFilter({ channel: gid }); }; + return (
    diff --git a/src/routes/resources/Filter/Date.js b/src/routes/resources/Filter/Date.tsx similarity index 96% rename from src/routes/resources/Filter/Date.js rename to src/routes/resources/Filter/Date.tsx index 797f375a..ad7cb2af 100644 --- a/src/routes/resources/Filter/Date.js +++ b/src/routes/resources/Filter/Date.tsx @@ -1,5 +1,3 @@ -// import React from 'react' -// import { useSelector } from "react-redux"; import styled from "styled-components"; import CheckSign from "../../../assets/icons/check.sign.svg"; @@ -39,6 +37,7 @@ const Styled = styled.div` } } `; + export const Dates = { today: { title: "Today", @@ -57,6 +56,7 @@ export const Dates = { title: "Last 12 months" } }; + export default function Date({ select = "", updateFilter }) { // const { input, updateInput, contacts } = useFilteredUsers(); // const contacts=useSelector(store=>store.contacts); @@ -66,6 +66,7 @@ export default function Date({ select = "", updateFilter }) { const handleClick = (dur) => { updateFilter({ date: dur }); }; + return (
      diff --git a/src/routes/resources/Filter/From.js b/src/routes/resources/Filter/From.tsx similarity index 93% rename from src/routes/resources/Filter/From.js rename to src/routes/resources/Filter/From.tsx index 5e65f181..5a8df03c 100644 --- a/src/routes/resources/Filter/From.js +++ b/src/routes/resources/Filter/From.tsx @@ -1,17 +1,15 @@ -// import React from 'react' -// import { useSelector } from "react-redux"; import styled from "styled-components"; import Search from "../Search"; import CheckSign from "../../../assets/icons/check.sign.svg"; - import Contact from "../../../common/component/Contact"; import useFilteredUsers from "../../../common/hook/useFilteredUsers"; + const Styled = styled.div` padding: 0 4px 4px 4px; background: #ffffff; max-height: 300px; overflow: auto; - box-shadow: 0px 24px 48px -12px rgba(16, 24, 40, 0.18); + box-shadow: 0 24px 48px -12px rgba(16, 24, 40, 0.18); border-radius: 8px; display: flex; flex-direction: column; @@ -49,6 +47,7 @@ const Styled = styled.div` } } `; + export default function From({ select = "", updateFilter }) { const { input, updateInput, contacts } = useFilteredUsers(); // const contacts=useSelector(store=>store.contacts); @@ -58,6 +57,7 @@ export default function From({ select = "", updateFilter }) { const handleClick = (uid) => { updateFilter({ from: uid }); }; + return (
      diff --git a/src/routes/resources/Filter/Type.js b/src/routes/resources/Filter/Type.tsx similarity index 94% rename from src/routes/resources/Filter/Type.js rename to src/routes/resources/Filter/Type.tsx index 292b314a..90885b65 100644 --- a/src/routes/resources/Filter/Type.js +++ b/src/routes/resources/Filter/Type.tsx @@ -1,5 +1,3 @@ -// import React from 'react' -// import { useSelector } from "react-redux"; import styled from "styled-components"; import IconPdf from "../../../assets/icons/file.pdf.svg"; import IconAudio from "../../../assets/icons/file.audio.svg"; @@ -16,7 +14,7 @@ const Styled = styled.div` min-width: 200px; /* max-height: 230px; */ overflow: auto; - box-shadow: 0px 24px 48px -12px rgba(16, 24, 40, 0.18); + box-shadow: 0 24px 48px -12px rgba(16, 24, 40, 0.18); border-radius: 8px; display: flex; flex-direction: column; @@ -33,7 +31,6 @@ const Styled = styled.div` display: flex; align-items: center; gap: 8px; - color: #616161; font-weight: 600; font-size: 14px; line-height: 20px; diff --git a/src/routes/resources/Filter/index.js b/src/routes/resources/Filter/index.tsx similarity index 94% rename from src/routes/resources/Filter/index.js rename to src/routes/resources/Filter/index.tsx index 68e2de5a..53c1d8b4 100644 --- a/src/routes/resources/Filter/index.js +++ b/src/routes/resources/Filter/index.tsx @@ -1,13 +1,14 @@ import { useState } from "react"; import styled from "styled-components"; import Tippy from "@tippyjs/react"; -import { useSelector } from "react-redux"; import Avatar from "../../../common/component/Avatar"; import FilterDate, { Dates } from "./Date"; import FilterFrom from "./From"; import FilterChannel from "./Channel"; import FilterType, { FileTypes } from "./Type"; import ArrowDown from "../../../assets/icons/arrow.down.svg"; +import { useAppSelector } from "../../../app/store"; + const Styled = styled.div` /* padding: 20px 0; */ display: flex; @@ -20,7 +21,7 @@ const Styled = styled.div` gap: 8px; border: 1px solid #d0d5dd; box-sizing: border-box; - box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05); + box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05); border-radius: var(--br); padding: 7px 12px; font-weight: 500; @@ -49,24 +50,25 @@ export default function Filter({ filter, updateFilter }) { from: false, type: false }); + const toggleFilterVisible = (obj) => { setFiltersVisible((prev) => { return { ...prev, ...obj }; }); }; + const handleUpdateFilter = (data) => { updateFilter(data); let _key = Object.keys(data)[0]; let tmp = { [_key]: false }; - console.log("wtffff", tmp); toggleFilterVisible(tmp); }; - const { contactMap, channelMap } = useSelector((store) => { + const { contactMap, channelMap } = useAppSelector((store) => { return { contactMap: store.contacts.byId, channelMap: store.channels.byId }; }); - console.log("maps", contactMap, filter); + const { from, channel, type, date } = filter; const { channel: channelVisible, @@ -74,6 +76,7 @@ export default function Filter({ filter, updateFilter }) { type: typeVisible, from: fromVisible } = filtersVisible; + return ( { if (updateSearchValue) { updateSearchValue(evt.target.value); } }; + return ( diff --git a/src/routes/resources/View.js b/src/routes/resources/View.tsx similarity index 86% rename from src/routes/resources/View.js rename to src/routes/resources/View.tsx index a554e916..3e863c77 100644 --- a/src/routes/resources/View.js +++ b/src/routes/resources/View.tsx @@ -1,14 +1,15 @@ -// import React from 'react' +import { MouseEvent } from "react"; import styled from "styled-components"; import { useDispatch } from "react-redux"; import { updateFileListView } from "../../app/slices/ui"; import { Views } from "../../app/config"; import IconList from "../../assets/icons/file.list.svg"; import IconGrid from "../../assets/icons/file.grid.svg"; + const Styled = styled.ul` display: flex; border: 1px solid #d0d5dd; - box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05); + box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05); border-radius: 8px; box-sizing: border-box; @@ -23,7 +24,7 @@ const Styled = styled.ul` &.item .item, &.grid .grid { border: 1px solid #52edff; - box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05); + box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05); border-radius: 8px; svg { transition: all 0.2s ease; @@ -36,11 +37,12 @@ const Styled = styled.ul` export default function View({ view = Views.item }) { const dispatch = useDispatch(); - const handleChangeView = (evt) => { + const handleChangeView = (evt: MouseEvent) => { const { view: clickView } = evt.currentTarget.dataset; if (clickView == view) return; dispatch(updateFileListView(view == Views.item ? Views.grid : Views.item)); }; + return (
    • diff --git a/src/routes/resources/index.js b/src/routes/resources/index.tsx similarity index 93% rename from src/routes/resources/index.js rename to src/routes/resources/index.tsx index 196ba48a..ffd6d248 100644 --- a/src/routes/resources/index.js +++ b/src/routes/resources/index.tsx @@ -1,15 +1,14 @@ import { useState, useEffect, useRef, memo } from "react"; -import Styled from "./styled"; -import { useSelector } from "react-redux"; import Masonry from "masonry-layout"; -// import waterfall from "waterfall.js/src/waterfall"; +import Styled from "./styled"; import { Views } from "../../app/config"; import View from "./View"; import Search from "./Search"; import Filter from "./Filter"; import FileBox from "../../common/component/FileBox"; +import { useAppSelector } from "../../app/store"; + const checkFilter = (data, filter, channelMessage) => { - console.log("filter data", data); let selected = true; const { mid, file_type, created_at, from_uid, properties } = data; const { @@ -35,11 +34,12 @@ const checkFilter = (data, filter, channelMessage) => { } return selected; }; + let msnry = null; function ResourceManagement({ fileMessages }) { const listContainerRef = useRef(null); const [filter, setFilter] = useState({}); - const { message, view, channelMessage } = useSelector((store) => { + const { message, view, channelMessage } = useAppSelector((store) => { return { message: store.message, channelMessage: store.channelMessage, @@ -52,11 +52,13 @@ function ResourceManagement({ fileMessages }) { return { ...prev, ...data }; }); }; + const handleUpdateSearch = (val) => { setFilter((prev) => { return { ...prev, name: val }; }); }; + useEffect(() => { if (view == Views.grid && listContainerRef) { const container = listContainerRef.current; @@ -84,7 +86,6 @@ function ResourceManagement({ fileMessages }) { // } }, [view, filter]); - console.log("files", fileMessages); return ( @@ -119,7 +120,9 @@ function ResourceManagement({ fileMessages }) { ); } + const equals = (a, b) => a.length === b.length && a.every((v, i) => v == b[i]); + export default memo(ResourceManagement, (prevs, nexts) => { return equals(prevs.fileMessages, nexts.fileMessages); }); diff --git a/src/routes/resources/styled.js b/src/routes/resources/styled.tsx similarity index 99% rename from src/routes/resources/styled.js rename to src/routes/resources/styled.tsx index 08b18b24..4f12d58b 100644 --- a/src/routes/resources/styled.js +++ b/src/routes/resources/styled.tsx @@ -1,4 +1,5 @@ import styled from "styled-components"; + const Styled = styled.div` height: 100vh; overflow-y: scroll; diff --git a/src/routes/sendMagicLink/SentTip.js b/src/routes/sendMagicLink/SentTip.tsx similarity index 64% rename from src/routes/sendMagicLink/SentTip.js rename to src/routes/sendMagicLink/SentTip.tsx index f1b705c9..0dba8407 100644 --- a/src/routes/sendMagicLink/SentTip.js +++ b/src/routes/sendMagicLink/SentTip.tsx @@ -1,6 +1,12 @@ -// import React from "react"; import Button from "../../common/component/styled/Button"; -export default function SentTip({ email, reset }) { +import { FC, MouseEvent } from "react"; + +interface Props { + email: string; + reset?: (e: MouseEvent) => void; +} + +const SentTip: FC = ({ email, reset }) => { return (

      Check your email

      @@ -12,4 +18,6 @@ export default function SentTip({ email, reset }) {
      ); -} +}; + +export default SentTip; diff --git a/src/routes/sendMagicLink/index.js b/src/routes/sendMagicLink/index.tsx similarity index 92% rename from src/routes/sendMagicLink/index.js rename to src/routes/sendMagicLink/index.tsx index 66676e2a..7ddba020 100644 --- a/src/routes/sendMagicLink/index.js +++ b/src/routes/sendMagicLink/index.tsx @@ -1,6 +1,4 @@ -/* eslint-disable no-undef */ -import { useState, useEffect } from "react"; -// import { useDispatch } from "react-redux"; +import { useState, useEffect, ChangeEvent, FormEvent } from "react"; import { useNavigate } from "react-router-dom"; import toast from "react-hot-toast"; import BASE_URL from "../../app/config"; @@ -13,10 +11,9 @@ import SentTip from "./SentTip"; export default function SendMagicLinkPage() { const [sent, setSent] = useState(false); const [sendMagicLink, { isSuccess, isLoading, error }] = useSendLoginMagicLinkMutation(); - const navigateTo = useNavigate(); - // const dispatch = useDispatch(); const [email, setEmail] = useState(""); + useEffect(() => { if (isSuccess) { toast.success("Send Email Successfully!"); @@ -48,20 +45,23 @@ export default function SendMagicLinkPage() { const handlePwdPath = () => { navigateTo("/login"); }; - const handleLogin = (evt) => { + + const handleLogin = (evt: FormEvent) => { evt.preventDefault(); sendMagicLink(email); }; - const handleInput = (evt) => { + const handleInput = (evt: ChangeEvent) => { const { value } = evt.target; console.log(value); setEmail(value); }; + const handleReset = () => { setEmail(""); setSent(false); }; + return (
      diff --git a/src/routes/sendMagicLink/styled.js b/src/routes/sendMagicLink/styled.tsx similarity index 100% rename from src/routes/sendMagicLink/styled.js rename to src/routes/sendMagicLink/styled.tsx diff --git a/src/routes/setting/APIConfig.js b/src/routes/setting/APIConfig.tsx similarity index 98% rename from src/routes/setting/APIConfig.js rename to src/routes/setting/APIConfig.tsx index 78413d95..c30f2b88 100644 --- a/src/routes/setting/APIConfig.js +++ b/src/routes/setting/APIConfig.tsx @@ -1,6 +1,15 @@ import { useEffect } from "react"; import styled from "styled-components"; +import Tippy from "@tippyjs/react"; +import toast from "react-hot-toast"; import { hideAll } from "tippy.js"; +import Input from "../../common/component/styled/Input"; +import Button from "../../common/component/styled/Button"; +import { + useGetThirdPartySecretQuery, + useUpdateThirdPartySecretMutation +} from "../../app/services/server"; + const StyledConfirm = styled.div` padding: 12px; border-radius: 10px; @@ -48,19 +57,12 @@ const Styled = styled.div` line-height: 1.5; } `; -import Input from "../../common/component/styled/Input"; -import Button from "../../common/component/styled/Button"; -import { - useGetThirdPartySecretQuery, - useUpdateThirdPartySecretMutation -} from "../../app/services/server"; -import Tippy from "@tippyjs/react"; -import toast from "react-hot-toast"; + export default function APIConfig() { const { data } = useGetThirdPartySecretQuery(); const [updateSecret, { data: updatedSecret, isSuccess, isLoading }] = useUpdateThirdPartySecretMutation(); - console.log("secret", data); + useEffect(() => { if (isSuccess) { hideAll(); diff --git a/src/routes/setting/LogoutConfirmModal.js b/src/routes/setting/LogoutConfirmModal.tsx similarity index 100% rename from src/routes/setting/LogoutConfirmModal.js rename to src/routes/setting/LogoutConfirmModal.tsx diff --git a/src/routes/setting/MyAccount.js b/src/routes/setting/MyAccount.tsx similarity index 95% rename from src/routes/setting/MyAccount.js rename to src/routes/setting/MyAccount.tsx index ea6610bf..6889a99d 100644 --- a/src/routes/setting/MyAccount.js +++ b/src/routes/setting/MyAccount.tsx @@ -1,11 +1,12 @@ -import { useEffect, useState } from "react"; +import { useEffect, useState, MouseEvent } from "react"; import styled from "styled-components"; -import { useSelector } from "react-redux"; import toast from "react-hot-toast"; import { useUpdateAvatarMutation } from "../../app/services/contact"; import AvatarUploader from "../../common/component/AvatarUploader"; import ProfileBasicEditModal from "./ProfileBasicEditModal"; import UpdatePasswordModal from "./UpdatePasswordModal"; +import { useAppSelector } from "../../app/store"; + const StyledWrapper = styled.div` display: flex; flex-direction: column; @@ -109,28 +110,34 @@ const EditModalInfo = { intro: "Enter a new email." } }; + export default function MyAccount() { const [passwordModal, setPasswordModal] = useState(false); const [editModal, setEditModal] = useState(null); const [uploadAvatar, { isSuccess: uploadSuccess }] = useUpdateAvatarMutation(); - const loginUser = useSelector((store) => { + const loginUser = useAppSelector((store) => { return store.contacts.byId[store.authData.uid]; }); + useEffect(() => { if (uploadSuccess) { toast.success("update avatar successfully!"); } }, [uploadSuccess]); - const handleBasicEdit = (evt) => { + + const handleBasicEdit = (evt: MouseEvent) => { const { edit } = evt.target.dataset; setEditModal(edit); }; + const closeBasicEditModal = () => { setEditModal(null); }; + const togglePasswordModal = () => { setPasswordModal((prev) => !prev); }; + if (!loginUser) return null; const { uid, avatar, name, email } = loginUser; return ( diff --git a/src/routes/setting/Notifications.js b/src/routes/setting/Notifications.tsx similarity index 95% rename from src/routes/setting/Notifications.js rename to src/routes/setting/Notifications.tsx index 76ad81cf..6806b43e 100644 --- a/src/routes/setting/Notifications.js +++ b/src/routes/setting/Notifications.tsx @@ -1,12 +1,13 @@ -// import React from "react"; import styled from "styled-components"; import useNotification from "../../common/hook/useNotification"; import StyledToggle from "../../common/component/styled/Toggle"; import Label from "../../common/component/styled/Label"; + const StyledWrapper = styled.div` display: flex; flex-direction: column; `; + export default function Notifications() { const { status, enableNotification } = useNotification(); const handleEnableNotify = () => { @@ -14,6 +15,7 @@ export default function Notifications() { enableNotification(); } }; + return ( diff --git a/src/routes/setting/Overview.js b/src/routes/setting/Overview.tsx similarity index 97% rename from src/routes/setting/Overview.js rename to src/routes/setting/Overview.tsx index 5451579f..2e121aad 100644 --- a/src/routes/setting/Overview.js +++ b/src/routes/setting/Overview.tsx @@ -1,6 +1,6 @@ import { useState, useEffect } from "react"; import styled from "styled-components"; -import { useSelector } from "react-redux"; +import toast from "react-hot-toast"; import { useGetServerQuery, useUpdateServerMutation, @@ -13,8 +13,8 @@ import Input from "../../common/component/styled/Input"; import Label from "../../common/component/styled/Label"; import Textarea from "../../common/component/styled/Textarea"; import SaveTip from "../../common/component/SaveTip"; -import toast from "react-hot-toast"; import StyledRadio from "../../common/component/styled/Radio"; +import { useAppSelector } from "../../app/store"; const StyledWrapper = styled.div` position: relative; @@ -55,7 +55,7 @@ const StyledWrapper = styled.div` background: #ecfeff; border: 1px solid #ecfeff; box-sizing: border-box; - box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05); + box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05); border-radius: 8px; } } @@ -97,8 +97,9 @@ const StyledWrapper = styled.div` } } `; + export default function Overview() { - const loginUser = useSelector((store) => { + const loginUser = useAppSelector((store) => { return store.contacts.byId[store.authData.uid]; }); const [changed, setChanged] = useState(false); diff --git a/src/routes/setting/ProfileBasicEditModal.js b/src/routes/setting/ProfileBasicEditModal.tsx similarity index 99% rename from src/routes/setting/ProfileBasicEditModal.js rename to src/routes/setting/ProfileBasicEditModal.tsx index 13b26786..dda5e841 100644 --- a/src/routes/setting/ProfileBasicEditModal.js +++ b/src/routes/setting/ProfileBasicEditModal.tsx @@ -1,10 +1,13 @@ // import React from "react"; import { useEffect, useState } from "react"; import styled from "styled-components"; +import toast from "react-hot-toast"; import Input from "../../common/component/styled/Input"; import { useUpdateInfoMutation } from "../../app/services/contact"; import StyledModal from "../../common/component/styled/Modal"; import Button from "../../common/component/styled/Button"; +import Modal from "../../common/component/Modal"; + const StyledEdit = styled(StyledModal)` .input { margin: 48px 0; @@ -20,8 +23,7 @@ const StyledEdit = styled(StyledModal)` } } `; -import Modal from "../../common/component/Modal"; -import toast from "react-hot-toast"; + export default function ProfileBasicEditModal({ label = "Username", valueKey = "name", diff --git a/src/routes/setting/UpdatePasswordModal.js b/src/routes/setting/UpdatePasswordModal.tsx similarity index 92% rename from src/routes/setting/UpdatePasswordModal.js rename to src/routes/setting/UpdatePasswordModal.tsx index 5db9ec87..976f401e 100644 --- a/src/routes/setting/UpdatePasswordModal.js +++ b/src/routes/setting/UpdatePasswordModal.tsx @@ -1,10 +1,12 @@ -// import React from "react"; -import { useEffect, useState } from "react"; +import { ChangeEvent, useEffect, useState, FC } from "react"; import styled from "styled-components"; +import toast from "react-hot-toast"; import Input from "../../common/component/styled/Input"; import { useUpdatePasswordMutation, useGetCredentialsQuery } from "../../app/services/auth"; import StyledModal from "../../common/component/styled/Modal"; import Button from "../../common/component/styled/Button"; +import Modal from "../../common/component/Modal"; + const StyledEdit = styled(StyledModal)` .input { margin: 16px 0; @@ -20,9 +22,12 @@ const StyledEdit = styled(StyledModal)` } } `; -import Modal from "../../common/component/Modal"; -import toast from "react-hot-toast"; -export default function ProfileBasicEditModal({ closeModal }) { + +interface Props { + closeModal: () => void; +} + +const ProfileBasicEditModal: FC = ({ closeModal }) => { const { data } = useGetCredentialsQuery(); const [input, setInput] = useState({ current: "", @@ -31,7 +36,7 @@ export default function ProfileBasicEditModal({ closeModal }) { }); // const dispatch = useDispatch(); const [updatePassword, { isLoading, isSuccess }] = useUpdatePasswordMutation(); - const handleChange = (evt) => { + const handleChange = (evt: ChangeEvent) => { const { type } = evt.target.dataset; setInput((prev) => { return { ...prev, [type]: evt.target.value }; @@ -116,4 +121,6 @@ export default function ProfileBasicEditModal({ closeModal }) { ); -} +}; + +export default ProfileBasicEditModal; diff --git a/src/routes/setting/config/Agora.js b/src/routes/setting/config/Agora.tsx similarity index 98% rename from src/routes/setting/config/Agora.js rename to src/routes/setting/config/Agora.tsx index 1dd49056..20f610a8 100644 --- a/src/routes/setting/config/Agora.js +++ b/src/routes/setting/config/Agora.tsx @@ -1,4 +1,3 @@ -// import { useState, useEffect } from "react"; import StyledContainer from "./StyledContainer"; import Input from "../../../common/component/styled/Input"; import Textarea from "../../../common/component/styled/Textarea"; @@ -6,12 +5,14 @@ import Label from "../../../common/component/styled/Label"; import Toggle from "../../../common/component/styled/Toggle"; import SaveTip from "../../../common/component/SaveTip"; import useConfig from "../../../common/hook/useConfig"; + export default function ConfigAgora() { const { changed, reset, values, setValues, toggleEnable, updateConfig } = useConfig("agora"); const handleUpdate = () => { // const { token_url, description } = values; updateConfig(values); }; + const handleChange = (evt) => { const newValue = evt.target.value; const { type } = evt.target.dataset; @@ -29,6 +30,7 @@ export default function ConfigAgora() { rtm_secret, enabled = false } = values ?? {}; + return (
      diff --git a/src/routes/setting/config/Firebase.js b/src/routes/setting/config/Firebase.tsx similarity index 100% rename from src/routes/setting/config/Firebase.js rename to src/routes/setting/config/Firebase.tsx diff --git a/src/routes/setting/config/IssuerList/index.js b/src/routes/setting/config/IssuerList/index.tsx similarity index 96% rename from src/routes/setting/config/IssuerList/index.js rename to src/routes/setting/config/IssuerList/index.tsx index 2c7e7f86..f28684dd 100644 --- a/src/routes/setting/config/IssuerList/index.js +++ b/src/routes/setting/config/IssuerList/index.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { ChangeEvent, useState } from "react"; import Select from "../../../../common/component/styled/Select"; import Button from "../../../../common/component/styled/Button"; import Input from "../../../../common/component/styled/Input"; @@ -11,13 +11,16 @@ import IconMinus from "../../../../assets/icons/minus.circle.svg"; export default function IssuerList({ issuers = [], onChange }) { const [select, setSelect] = useState({}); const [newDomain, setNewDomain] = useState(""); - const handleNewDomain = (evt) => { + + const handleNewDomain = (evt: ChangeEvent) => { setNewDomain(evt.target.value); }; + const disableBtn = (!newDomain && !select?.value) || !select?.title || issuers.some((issuer) => issuer.domain === newDomain); + return (
        diff --git a/src/routes/setting/config/IssuerList/styled.js b/src/routes/setting/config/IssuerList/styled.tsx similarity index 99% rename from src/routes/setting/config/IssuerList/styled.js rename to src/routes/setting/config/IssuerList/styled.tsx index 5f147356..777dca4f 100644 --- a/src/routes/setting/config/IssuerList/styled.js +++ b/src/routes/setting/config/IssuerList/styled.tsx @@ -1,4 +1,5 @@ import styled from "styled-components"; + const Styled = styled.div` padding: 16px 0; width: 100%; diff --git a/src/routes/setting/config/Logins.js b/src/routes/setting/config/Logins.tsx similarity index 99% rename from src/routes/setting/config/Logins.js rename to src/routes/setting/config/Logins.tsx index 81b16334..9f03f0a0 100644 --- a/src/routes/setting/config/Logins.js +++ b/src/routes/setting/config/Logins.tsx @@ -1,4 +1,3 @@ -// import { useState } from "react"; import toast from "react-hot-toast"; import StyledContainer from "./StyledContainer"; import Toggle from "../../../common/component/styled/Toggle"; @@ -10,6 +9,7 @@ import Tooltip from "./Tooltip"; import IssuerList from "./IssuerList"; import useGoogleAuthConfig from "../../../common/hook/useGoogleAuthConfig"; import useGithubAuthConfig from "../../../common/hook/useGithubAuthConfig"; + export default function Logins() { const { changed: clientIdChanged, diff --git a/src/routes/setting/config/SMTP.js b/src/routes/setting/config/SMTP.tsx similarity index 100% rename from src/routes/setting/config/SMTP.js rename to src/routes/setting/config/SMTP.tsx diff --git a/src/routes/setting/config/StyledContainer.js b/src/routes/setting/config/StyledContainer.tsx similarity index 99% rename from src/routes/setting/config/StyledContainer.js rename to src/routes/setting/config/StyledContainer.tsx index 22f7ac60..fb46552e 100644 --- a/src/routes/setting/config/StyledContainer.js +++ b/src/routes/setting/config/StyledContainer.tsx @@ -1,4 +1,5 @@ import styled from "styled-components"; + const StyledContainer = styled.div` position: relative; width: 512px; diff --git a/src/routes/setting/config/Tooltip.js b/src/routes/setting/config/Tooltip.tsx similarity index 100% rename from src/routes/setting/config/Tooltip.js rename to src/routes/setting/config/Tooltip.tsx diff --git a/src/routes/setting/index.js b/src/routes/setting/index.tsx similarity index 95% rename from src/routes/setting/index.js rename to src/routes/setting/index.tsx index 97b56f04..086c42b2 100644 --- a/src/routes/setting/index.js +++ b/src/routes/setting/index.tsx @@ -1,10 +1,11 @@ import { useState } from "react"; -// import { useDispatch } from "react-redux"; import { useNavigate, useSearchParams } from "react-router-dom"; import StyledSettingContainer from "../../common/component/StyledSettingContainer"; import useNavs from "./navs"; import LogoutConfirmModal from "./LogoutConfirmModal"; -let from = null; + +let from: string | null = null; + export default function Setting() { const [searchParams] = useSearchParams(); const navs = useNavs(); @@ -26,6 +27,7 @@ export default function Setting() { setLogoutConfirm((prev) => !prev); }; const currNav = flatenNavs.find((n) => n.name == navKey) || flatenNavs[0]; + return ( <> { - const loginUser = useSelector((store) => { + const loginUser = useAppSelector((store) => { return store.contacts.byId[store.authData.uid]; }); - const Navs = navs.filter((nav) => { + return navs.filter((nav) => { if (loginUser?.is_admin) { return true; } else { return !nav.admin; } }); - return Navs; }; export default useNavs; diff --git a/src/routes/settingChannel/DeleteConfirmModal.js b/src/routes/settingChannel/DeleteConfirmModal.tsx similarity index 87% rename from src/routes/settingChannel/DeleteConfirmModal.js rename to src/routes/settingChannel/DeleteConfirmModal.tsx index 63f5603d..94dc9ec6 100644 --- a/src/routes/settingChannel/DeleteConfirmModal.js +++ b/src/routes/settingChannel/DeleteConfirmModal.tsx @@ -1,5 +1,4 @@ -// import React from "react"; -import { useEffect } from "react"; +import { useEffect, FC } from "react"; import toast from "react-hot-toast"; import { useNavigate } from "react-router-dom"; import Modal from "../../common/component/Modal"; @@ -7,13 +6,19 @@ import { useLazyRemoveChannelQuery } from "../../app/services/channel"; import StyledModal from "../../common/component/styled/Modal"; import Button from "../../common/component/styled/Button"; -export default function DeleteConfirmModal({ id, closeModal }) { +interface Props { + id?: number; + closeModal: () => void; +} + +const DeleteConfirmModal: FC = ({ id, closeModal }) => { const navigateTo = useNavigate(); // const pathMatched = useMatch(`/chat/channel/${id}`); const [deleteChannel, { isLoading, isSuccess }] = useLazyRemoveChannelQuery(); const handleDelete = () => { deleteChannel(id); }; + useEffect(() => { if (isSuccess) { toast.success("delete channel successfully!"); @@ -21,6 +26,7 @@ export default function DeleteConfirmModal({ id, closeModal }) { navigateTo("/chat"); } }, [isSuccess]); + if (!id) return null; return ( @@ -42,4 +48,6 @@ export default function DeleteConfirmModal({ id, closeModal }) { > ); -} +}; + +export default DeleteConfirmModal; diff --git a/src/routes/settingChannel/Overview.js b/src/routes/settingChannel/Overview.tsx similarity index 96% rename from src/routes/settingChannel/Overview.js rename to src/routes/settingChannel/Overview.tsx index 2a2e725f..fae7af2c 100644 --- a/src/routes/settingChannel/Overview.js +++ b/src/routes/settingChannel/Overview.tsx @@ -12,7 +12,8 @@ import Label from "../../common/component/styled/Label"; import Textarea from "../../common/component/styled/Textarea"; import SaveTip from "../../common/component/SaveTip"; import channelIcon from "../../assets/icons/channel.svg?url"; -import { useSelector } from "react-redux"; +import { useAppSelector } from "../../app/store"; + const StyledWrapper = styled.div` position: relative; width: 512px; @@ -43,7 +44,7 @@ const StyledWrapper = styled.div` } `; export default function Overview({ id = 0 }) { - const { loginUser, channel } = useSelector((store) => { + const { loginUser, channel } = useAppSelector((store) => { return { loginUser: store.contacts.byId[store.authData.uid], channel: store.channels.byId[id] @@ -58,6 +59,7 @@ export default function Overview({ id = 0 }) { const { name, description } = values; updateChannel({ id, name, description }); }; + const handleChange = (evt) => { const newValue = evt.target.value; const { type } = evt.target.dataset; @@ -65,18 +67,22 @@ export default function Overview({ id = 0 }) { return { ...prev, [type]: newValue }; }); }; + const updateIcon = (image) => { updateChannelIcon({ gid: id, image }); }; + const handleReset = () => { console.log("reset", data); setValues(data); }; + useEffect(() => { if (data) { setValues(data); } }, [data]); + useEffect(() => { if (data && values) { const { name, description } = values; @@ -99,7 +105,7 @@ export default function Overview({ id = 0 }) { if (!values || !id) return null; const { name, description } = values; const readOnly = !loginUser?.is_admin && channel?.owner != loginUser?.uid; - console.log("channel icon", channel); + return ( diff --git a/src/routes/settingChannel/index.js b/src/routes/settingChannel/index.tsx similarity index 93% rename from src/routes/settingChannel/index.js rename to src/routes/settingChannel/index.tsx index 01cfc02f..9bc60c50 100644 --- a/src/routes/settingChannel/index.js +++ b/src/routes/settingChannel/index.tsx @@ -1,14 +1,16 @@ import { useState } from "react"; -import { useSelector } from "react-redux"; import { useParams, useNavigate, useSearchParams } from "react-router-dom"; import LeaveChannel from "../../common/component/LeaveChannel"; import StyledSettingContainer from "../../common/component/StyledSettingContainer"; import DeleteConfirmModal from "./DeleteConfirmModal"; import useNavs from "./navs"; -let from = null; +import { useAppSelector } from "../../app/store"; + +let from: string | null = null; + export default function ChannelSetting() { const { cid } = useParams(); - const { isAdmin, loginUid, channel } = useSelector((store) => { + const { isAdmin, loginUid, channel } = useAppSelector((store) => { return { loginUid: store.authData.uid, isAdmin: store.contacts.byId[store.authData.uid]?.is_admin, diff --git a/src/routes/settingChannel/navs.js b/src/routes/settingChannel/navs.tsx similarity index 100% rename from src/routes/settingChannel/navs.js rename to src/routes/settingChannel/navs.tsx diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 23623814..07a05c54 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -1,8 +1,10 @@ import { PrecacheEntry } from "workbox-precaching/src/_types"; +import localforage from "localforage"; export declare global { interface Window { __WB_MANIFEST: Array; skipWaiting: () => void; + CACHE: { [key: string]: typeof localforage }; } } diff --git a/yarn.lock b/yarn.lock index 019f37af..66de65a5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2852,6 +2852,13 @@ dependencies: "@types/node" "*" +"@types/emoji-mart@^3.0.9": + version "3.0.9" + resolved "https://registry.npmmirror.com/@types/emoji-mart/-/emoji-mart-3.0.9.tgz#2f7ef5d9ec194f28029c46c81a5fc1e5b0efa73c" + integrity sha512-qdBo/2Y8MXaJ/2spKjDZocuq79GpnOhkwMHnK2GnVFa8WYFgfA+ei6sil3aeWQPCreOKIx9ogPpR5+7MaOqYAA== + dependencies: + "@types/react" "*" + "@types/escape-html@^1.0.0": version "1.0.2" resolved "http://mirrors.cloud.tencent.com/npm/@types%2fescape-html/-/escape-html-1.0.2.tgz#072b7b13784fb3cee9c2450c22f36405983f5e3c" @@ -2977,6 +2984,13 @@ jest-matcher-utils "^27.0.0" pretty-format "^27.0.0" +"@types/jquery@*": + version "3.5.14" + resolved "https://registry.npmmirror.com/@types/jquery/-/jquery-3.5.14.tgz#ac8e11ee591e94d4d58da602cb3a5a8320dee577" + integrity sha512-X1gtMRMbziVQkErhTQmSe2jFwwENA/Zr+PprCkF63vFq+Yt5PZ4AlKqgmeNlwgn7dhsXEK888eIW2520EpC+xg== + dependencies: + "@types/sizzle" "*" + "@types/js-cookie@^2.2.6": version "2.2.7" resolved "http://mirrors.cloud.tencent.com/npm/@types%2fjs-cookie/-/js-cookie-2.2.7.tgz#226a9e31680835a6188e887f3988e60c04d3f6a3" @@ -3002,6 +3016,13 @@ resolved "http://mirrors.cloud.tencent.com/npm/@types%2flong/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== +"@types/masonry-layout@^4.2.5": + version "4.2.5" + resolved "https://registry.npmmirror.com/@types/masonry-layout/-/masonry-layout-4.2.5.tgz#1d6180ec07ad21df7f85d20ac6e99b061854d00f" + integrity sha512-/DSIDMDsXlS+7JfzywA2zm9x+veO/z1QDcjKLS4OhDZH7sFdreKJbNFKb7jYA3NrY3bRvFGCamp5+DeIArLzow== + dependencies: + "@types/jquery" "*" + "@types/mdast@^3.0.0": version "3.0.10" resolved "http://mirrors.cloud.tencent.com/npm/@types%2fmdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af" @@ -3071,6 +3092,20 @@ dependencies: "@types/react" "*" +"@types/react-helmet@^6.1.5": + version "6.1.5" + resolved "https://registry.npmmirror.com/@types/react-helmet/-/react-helmet-6.1.5.tgz#35f89a6b1646ee2bc342a33a9a6c8777933f9083" + integrity sha512-/ICuy7OHZxR0YCAZLNg9r7I9aijWUWvxaPR6uTuyxe8tAj5RL4Sw1+R6NhXUtOsarkGYPmaHdBDvuXh2DIN/uA== + dependencies: + "@types/react" "*" + +"@types/react-linkify@^1.0.1": + version "1.0.1" + resolved "https://registry.npmmirror.com/@types/react-linkify/-/react-linkify-1.0.1.tgz#4ece351faef22bfde1280b6d9ace5e88683a74d4" + integrity sha512-qPxYwjB41ezoKdLXs0MrQ1FnhF3apyyxf3J7WVQQCBu/GyZQAW7Y3TY4317jdh0450QJ4fLqj0rnhIJvFZOamQ== + dependencies: + "@types/react" "*" + "@types/react@*": version "18.0.9" resolved "http://mirrors.tencent.com/npm/@types%2freact/-/react-18.0.9.tgz#d6712a38bd6cd83469603e7359511126f122e878" @@ -3121,6 +3156,11 @@ "@types/mime" "^1" "@types/node" "*" +"@types/sizzle@*": + version "2.3.3" + resolved "https://registry.npmmirror.com/@types/sizzle/-/sizzle-2.3.3.tgz#ff5e2f1902969d305225a047c8a0fd5c915cebef" + integrity sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ== + "@types/sockjs@^0.3.33": version "0.3.33" resolved "https://mirrors.cloud.tencent.com/npm/@types%2fsockjs/-/sockjs-0.3.33.tgz#570d3a0b99ac995360e3136fd6045113b1bd236f"