From 003353e43fbd35f153071c88b6823e59f6a54ed0 Mon Sep 17 00:00:00 2001 From: HD Date: Wed, 29 Jun 2022 16:54:58 +0800 Subject: [PATCH] refactor: add typescript support to project --- src/app/services/auth.ts | 8 ++- src/app/services/server.ts | 9 +-- src/common/component/AvatarUploader.tsx | 4 +- src/common/component/ChannelIcon.tsx | 4 +- src/common/component/ChannelModal/index.tsx | 22 +++---- src/common/component/GoogleLoginButton.tsx | 21 +++---- .../component/StyledSettingContainer.tsx | 31 ++++++---- src/common/component/styled/Select.tsx | 33 +++++++--- src/common/hook/useLogout.ts | 4 ++ src/common/hook/useNormalizeMessage.ts | 4 +- src/routes/index.tsx | 11 ++-- src/routes/invite/index.tsx | 57 +++++++++-------- src/routes/onboarding/index.tsx | 13 ++-- src/routes/onboarding/useServerSetup.ts | 15 +++-- src/routes/reg/ExpiredTip.tsx | 1 - src/routes/reg/RegWithUsername.tsx | 61 ++++++++++--------- src/routes/reg/Register.tsx | 25 +++++--- src/routes/reg/index.tsx | 2 - src/routes/resources/Search.tsx | 15 ++++- src/routes/sendMagicLink/index.tsx | 6 +- src/routes/sendMagicLink/styled.tsx | 3 +- src/routes/setting/APIConfig.tsx | 4 +- src/routes/setting/LogoutConfirmModal.tsx | 29 +++++---- src/routes/setting/ProfileBasicEditModal.tsx | 22 +++++-- src/routes/setting/UpdatePasswordModal.tsx | 10 ++- .../setting/config/IssuerList/index.tsx | 30 ++++++--- src/routes/setting/config/Tooltip.tsx | 5 +- src/routes/setting/index.tsx | 21 +++---- src/routes/settingChannel/Overview.tsx | 22 ++++--- src/routes/settingChannel/index.tsx | 59 ++++++++++-------- src/routes/settingChannel/navs.tsx | 19 +++++- src/types/channel.ts | 7 +++ src/types/server.ts | 5 +- 33 files changed, 358 insertions(+), 224 deletions(-) diff --git a/src/app/services/auth.ts b/src/app/services/auth.ts index f836cdf8..008565e2 100644 --- a/src/app/services/auth.ts +++ b/src/app/services/auth.ts @@ -51,7 +51,7 @@ export const authApi = createApi({ } } }), - register: builder.mutation({ + register: builder.mutation({ query: (data) => ({ url: `user/register`, method: "POST", @@ -143,10 +143,12 @@ export const authApi = createApi({ url: `/user/check_email?email=${encodeURIComponent(email)}` }) }), - getCredentials: builder.query({ + // todo: check return type + getCredentials: builder.query({ query: () => ({ url: "/token/credentials" }) }), - logout: builder.query({ + // todo: check return type + logout: builder.query({ query: () => ({ url: "token/logout" }), async onQueryStarted(params, { dispatch, queryFulfilled }) { try { diff --git a/src/app/services/server.ts b/src/app/services/server.ts index 5d66ce09..2a20276a 100644 --- a/src/app/services/server.ts +++ b/src/app/services/server.ts @@ -10,11 +10,12 @@ import { LoginConfig, Server, TestEmailDTO, - NewAdminDTO, + CreateAdminDTO, SMTPConfig, AgoraConfig, GithubAuthConfig } from "../../types/server"; + const defaultExpireDuration = 7 * 24 * 60 * 60; export const serverApi = createApi({ @@ -169,7 +170,7 @@ export const serverApi = createApi({ }), updateServer: builder.mutation({ query: (data) => ({ - url: `admin/system/organization`, + url: "admin/system/organization", method: "POST", body: data }), @@ -184,9 +185,9 @@ export const serverApi = createApi({ } } }), - createAdmin: builder.mutation({ + createAdmin: builder.mutation({ query: (data) => ({ - url: `/admin/system/create_admin`, + url: "/admin/system/create_admin", method: "POST", body: data }) diff --git a/src/common/component/AvatarUploader.tsx b/src/common/component/AvatarUploader.tsx index 9e3e334e..2e648c50 100644 --- a/src/common/component/AvatarUploader.tsx +++ b/src/common/component/AvatarUploader.tsx @@ -64,9 +64,9 @@ const StyledWrapper = styled.div` interface Props { url?: string; name?: string; - type?: "user"; + type?: "user" | "channel"; disabled?: boolean; - uploadImage: (file: File) => Promise; + uploadImage: (file: File) => void; } const AvatarUploader: FC = ({ diff --git a/src/common/component/ChannelIcon.tsx b/src/common/component/ChannelIcon.tsx index b469f1ec..b477ff10 100644 --- a/src/common/component/ChannelIcon.tsx +++ b/src/common/component/ChannelIcon.tsx @@ -6,7 +6,7 @@ import LockHashIcon from "../../assets/icons/channel.private.svg"; interface Props { personal?: boolean; muted?: boolean; - className: string; + className?: string; } const Styled = styled.div` @@ -16,7 +16,7 @@ const Styled = styled.div` } `; -const ChannelIcon: FC = ({ personal = false, muted = false, className }) => { +const ChannelIcon: FC = ({ personal = false, muted = false, className = "" }) => { return ( {personal ? : } diff --git a/src/common/component/ChannelModal/index.tsx b/src/common/component/ChannelModal/index.tsx index dfbf2717..34518b57 100644 --- a/src/common/component/ChannelModal/index.tsx +++ b/src/common/component/ChannelModal/index.tsx @@ -10,19 +10,13 @@ import StyledCheckbox from "../styled/Checkbox"; import useFilteredUsers from "../../hook/useFilteredUsers"; import { useCreateChannelMutation } from "../../../app/services/channel"; import { useAppSelector } from "../../../app/store"; +import { CreateChannelDTO } from "../../../types/channel"; interface Props { personal?: boolean; closeModal: () => void; } -interface CreateChannelDTO { - name: string; - description: string; - members?: number[]; - is_public: boolean; -} - const ChannelModal: FC = ({ personal = false, closeModal }) => { const { contactsData, loginUid } = useAppSelector((store) => { return { contactsData: store.contacts.byId, loginUid: store.authData.uid }; @@ -31,7 +25,7 @@ const ChannelModal: FC = ({ personal = false, closeModal }) => { const [data, setData] = useState({ name: "", description: "", - members: [loginUid], + members: loginUid ? [Number(loginUid)] : [], is_public: !personal }); @@ -82,13 +76,15 @@ const ChannelModal: FC = ({ personal = false, closeModal }) => { }; const toggleCheckMember = ({ currentTarget }: MouseEvent) => { - const { members } = data; + const members = data.members ?? []; const { uid } = currentTarget.dataset; - let tmp = members.includes(+uid) ? members.filter((m) => m != uid) : [...members, +uid]; + const uidNum = Number(uid); + let tmp = members.includes(uidNum) ? members.filter((m) => m != uidNum) : [...members, uidNum]; setData((prev) => ({ ...prev, members: tmp })); }; - const loginUser = contactsData[loginUid]; + if (!loginUid) return null; + const loginUser = contactsData[Number(loginUid)]; if (!loginUser) return null; const { name, members, is_public } = data; @@ -108,13 +104,13 @@ const ChannelModal: FC = ({ personal = false, closeModal }) => {
    {contacts.map((u) => { const { uid } = u; - const checked = members.includes(uid); + const checked = members ? members.includes(uid) : false; return (
  • = ({ type = "login", clientId }) => { const [login, { isSuccess, isLoading, error }] = useLoginMutation(); - //拿本地存的magic token + // 拿本地存的magic token const magic_token = localStorage.getItem(KEY_LOCAL_MAGIC_TOKEN); const { signIn, loaded } = useGoogleLogin({ onScriptLoadFailure: (wtf) => { console.error("google login script load failure", wtf); }, clientId, - onSuccess: ({ tokenId, ...rest }) => { - console.info("google oauth success", tokenId, rest); - login({ - magic_token, - id_token: tokenId, - type: "google" - }); + onSuccess: (res) => { + if ("code" in res) { + console.error(`google login failed: ${res.code}`); + } else { + login({ magic_token, id_token: res.tokenId, type: "google" }); + } }, onFailure: (wtf) => { console.error("google login failure", wtf); @@ -57,7 +56,7 @@ const GoogleLoginButton: FC = ({ type = "login", clientId }) => { } }, [isSuccess]); useEffect(() => { - if (error) { + if (error && "status" in error) { switch (error.status) { case 410: toast.error( @@ -71,14 +70,14 @@ const GoogleLoginButton: FC = ({ type = "login", clientId }) => { return; } }, [error]); + const handleGoogleLogin = () => { signIn(); }; - // console.log("google login ", loaded); return ( - + {loaded ? `${type === "login" ? "Sign in" : "Sign up"} with Google` : `Initializing`} ); diff --git a/src/common/component/StyledSettingContainer.tsx b/src/common/component/StyledSettingContainer.tsx index b0474ba5..97f2cda7 100644 --- a/src/common/component/StyledSettingContainer.tsx +++ b/src/common/component/StyledSettingContainer.tsx @@ -1,18 +1,21 @@ -import { FC, ReactElement } from "react"; +import { FC, ReactNode } from "react"; import styled from "styled-components"; import { useLocation, NavLink } from "react-router-dom"; import backIcon from "../../assets/icons/arrow.left.svg?url"; +import { Nav } from "../../routes/settingChannel/navs"; const StyledWrapper = styled.div` width: 100vw; height: 100vh; display: flex; + > .left { max-height: 100vh; overflow: scroll; padding: 32px 16px; min-width: 212px; background-color: #f5f6f7; + > .title { cursor: pointer; font-weight: bold; @@ -21,16 +24,16 @@ const StyledWrapper = styled.div` color: #1c1c1e; margin-bottom: 32px; padding-left: 24px; - background: url(${backIcon}); background-size: 16px; - background-repeat: no-repeat; - background-position: left; + background: url(${backIcon}) no-repeat left; } + > .items { display: flex; flex-direction: column; gap: 2px; margin-bottom: 36px; + &:before { padding-left: 12px; content: attr(data-title); @@ -40,31 +43,37 @@ const StyledWrapper = styled.div` color: #6b7280; margin-bottom: 2px; } + .item { font-weight: 500; font-size: 14px; line-height: 20px; color: #44494f; border-radius: 4px; + &:hover, &.curr { background: #e7e5e4; } + > a { display: block; padding: 4px 12px; } } + &.danger .item { cursor: pointer; padding: 4px 12px; color: #ef4444; + &:hover { background: none; } } } } + > .right { background-color: #fff; width: 100%; @@ -72,6 +81,7 @@ const StyledWrapper = styled.div` /* max-height: -webkit-fill-available; */ overflow: auto; padding: 32px; + > .title { font-weight: bold; font-size: 20px; @@ -82,21 +92,18 @@ const StyledWrapper = styled.div` } `; -interface Nav { - name?: string; +export interface Danger { title: string; - // todo - items: []; - component: ReactElement; + handler: () => void; } interface Props { closeModal: () => void; title?: string; navs: Nav[]; - dangers: []; - nav: Nav; - children: ReactElement; + dangers: Danger[]; + nav: { title: string; name?: string; component?: ReactNode }; + children: ReactNode; } const StyledSettingContainer: FC = ({ diff --git a/src/common/component/styled/Select.tsx b/src/common/component/styled/Select.tsx index ec4e4ecd..69e555df 100644 --- a/src/common/component/styled/Select.tsx +++ b/src/common/component/styled/Select.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { FC, useState } from "react"; import styled from "styled-components"; import Tippy from "@tippyjs/react"; import IconSelect from "../../../assets/icons/check.sign.svg"; @@ -26,21 +26,34 @@ const Styled = styled.div` } `; -const CURRENT_NOT_SET = {}; +export interface Option { + icon?: string; + title: string; + value: string; + selected: boolean; + underline?: boolean; +} -export default function Select({ options = [], updateSelect = null, current = CURRENT_NOT_SET }) { +interface Props { + options: Option[]; + updateSelect: null | ((option: Partial
  • - - {(current !== CURRENT_NOT_SET ? current : curr)?.title || `Select`} - + {(current !== null ? current : curr)?.title || "Select"} ); -} +}; + +export default Select; diff --git a/src/common/hook/useLogout.ts b/src/common/hook/useLogout.ts index 28dc54d7..b7f60997 100644 --- a/src/common/hook/useLogout.ts +++ b/src/common/hook/useLogout.ts @@ -11,6 +11,10 @@ import { useLazyLogoutQuery } from "../../app/services/auth"; export default function useLogout() { const dispatch = useDispatch(); const [logout, { isLoading, isSuccess }] = useLazyLogoutQuery(); + // todo: remove batch + // If you're using React 18, you do not need to use the batch API. React 18 automatically + // batches all state updates, no matter where they're queued. + // ref: https://react-redux.js.org/api/batch const clearLocalData = () => { batch(() => { dispatch(resetFootprint()); diff --git a/src/common/hook/useNormalizeMessage.ts b/src/common/hook/useNormalizeMessage.ts index 1d06a7d4..b42c7a3e 100644 --- a/src/common/hook/useNormalizeMessage.ts +++ b/src/common/hook/useNormalizeMessage.ts @@ -1,10 +1,10 @@ import { useState, useEffect } from "react"; -import { normalizeArchiveData } from "../utils"; +import { normalizeArchiveData, ArchiveMessage } from "../utils"; import { useLazyGetArchiveMessageQuery } from "../../app/services/message"; export default function useNormalizeMessage() { const [filePath, setFilePath] = useState(null); - const [normalizedMessages, setNormalizedMessages] = useState(null); + const [normalizedMessages, setNormalizedMessages] = useState(null); const [getArchiveMessage, { data, isError, isLoading, isSuccess }] = useLazyGetArchiveMessageQuery(); useEffect(() => { diff --git a/src/routes/index.tsx b/src/routes/index.tsx index 1b9d1cd3..b493cf78 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -1,6 +1,6 @@ import { Suspense, useEffect, lazy } from "react"; import { Route, Routes, HashRouter } from "react-router-dom"; -import { Provider, useSelector } from "react-redux"; +import { Provider } from "react-redux"; import toast from "react-hot-toast"; import NotFoundPage from "./404"; // import Welcome from './Welcome' @@ -25,16 +25,19 @@ import Meta from "../common/component/Meta"; import HomePage from "./home"; import ChatPage from "./chat"; import Loading from "../common/component/Loading"; -import store from "../app/store"; +import store, { useAppSelector } from "../app/store"; const PageRoutes = () => { - const { ui: { online }, fileMessages } = useSelector((store) => { + const { + ui: { online }, + fileMessages + } = useAppSelector((store) => { return { ui: store.ui, fileMessages: store.fileMessage }; }); // 掉线检测 useEffect(() => { - let toastId = '0'; + let toastId = "0"; if (!online) { toast.error("Network Offline!", { duration: Infinity }); } else { diff --git a/src/routes/invite/index.tsx b/src/routes/invite/index.tsx index 38bf0827..e73d6608 100644 --- a/src/routes/invite/index.tsx +++ b/src/routes/invite/index.tsx @@ -1,79 +1,84 @@ -import { useState, useEffect } from "react"; +import { useState, useEffect, FormEvent, ChangeEvent, FC } from "react"; import StyledWrapper from "./styled"; import { Navigate } from "react-router-dom"; import toast from "react-hot-toast"; import BASE_URL from "../../app/config"; import { useRegisterMutation } from "../../app/services/auth"; import { useCheckMagicTokenValidMutation } from "../../app/services/auth"; -import { useSelector } from "react-redux"; +import { useAppSelector } from "../../app/store"; -export default function InvitePage() { - const { token: loginToken } = useSelector((store) => store.authData); +interface AuthForm { + name: string; + email: string; + password: string; +} + +const InvitePage: FC = () => { + const { token: loginToken } = useAppSelector((store) => store.authData); const [secondPwd, setSecondPwd] = useState(""); const [samePwd, setSamePwd] = useState(true); - const [token, setToken] = useState(""); + const [token, setToken] = useState(""); const [valid, setValid] = useState(false); // const [sp] = useSearchParams(); // const navigateTo = useNavigate(); const [register, { data, isLoading, isSuccess, isError, error }] = useRegisterMutation(); const [checkToken, { data: isValid, isLoading: checkLoading, isSuccess: checkSuccess }] = useCheckMagicTokenValidMutation(); + useEffect(() => { - // console.log(search); const query = new URLSearchParams(location.search); setToken(query.get("token")); }, []); + useEffect(() => { if (token) { checkToken(token); } }, [token]); + useEffect(() => { if (checkSuccess) { - console.log({ isValid }); setValid(isValid); } else { setValid(false); } }, [checkSuccess, isValid]); - const [input, setInput] = useState({ - name: "", - email: "", - password: "" - }); + const [input, setInput] = useState({ name: "", email: "", password: "" }); - const handleReg = (evt) => { + const handleReg = (evt: FormEvent) => { evt.preventDefault(); if (!samePwd) { toast.error("two passwords not same"); return; } - console.log("wtf", input); register({ ...input, magic_token: token, gender: 1 }); }; - const handleInput = (evt) => { - const { type } = evt.target.dataset; + + const handleInput = (evt: ChangeEvent) => { + const { type } = evt.target.dataset as { type: keyof AuthForm }; const { value } = evt.target; - console.log(type, value); setInput((prev) => { prev[type] = value; return { ...prev }; }); }; - const handleSecondPwdInput = (evt) => { + + const handleSecondPwdInput = (evt: ChangeEvent) => { const { value } = evt.target; setSecondPwd(value); }; + const handlePwdCheck = () => { if (secondPwd) { setSamePwd(secondPwd == input.password); } }; + useEffect(() => { if (!samePwd) { toast.error("two passwords not same"); @@ -88,8 +93,7 @@ export default function InvitePage() { location.href = `/#/login`; // navigateTo("/login",); }, 500); - } else if (isError) { - console.log("register failed", error); + } else if (isError && error && "data" in error) { switch (error.status) { case 400: toast.error("Register Failed: please check inputs"); @@ -102,6 +106,8 @@ export default function InvitePage() { email_conflict: "email conflict", name_conflict: "name conflict" }; + // todo + // @ts-ignore toast.error(`Register Failed: ${tips[error.data?.reason]}`); break; } @@ -114,9 +120,10 @@ export default function InvitePage() { const { email, password, name } = input; if (loginToken) return ; - if (!token) return "token not found"; - if (checkLoading) return "checking token valid"; - if (!valid) return "invite token expires or invalid"; + if (!token) return <>token not found; + if (checkLoading) return <>checking token valid; + if (!valid) return <>invite token expires or invalid; + return (
    @@ -168,4 +175,6 @@ export default function InvitePage() {
    ); -} +}; + +export default InvitePage; diff --git a/src/routes/onboarding/index.tsx b/src/routes/onboarding/index.tsx index c00252f0..3094a7c6 100644 --- a/src/routes/onboarding/index.tsx +++ b/src/routes/onboarding/index.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { FC } from "react"; import { Helmet } from "react-helmet"; import { Swiper, SwiperSlide } from "swiper/react"; import "swiper/css"; @@ -11,9 +11,14 @@ import DonePage from "./steps/donePage"; import useServerSetup, { steps } from "./useServerSetup"; import StyledOnboardingPage from "./styled"; -function Navigator({ step, setStep }) { +interface Props { + step: string; + setStep: (step: string) => void; +} + +const Navigator: FC = ({ step, setStep }) => { const index = steps.map((value) => value.name).indexOf(step); - const canJumpTo = steps.find((value) => value.name === step).canJumpTo || []; + const canJumpTo = steps.find((value) => value.name === step)?.canJumpTo || []; return (
    @@ -41,7 +46,7 @@ function Navigator({ step, setStep }) { })}
    ); -} +}; export default function OnboardingPage() { const serverSetup = useServerSetup(); diff --git a/src/routes/onboarding/useServerSetup.ts b/src/routes/onboarding/useServerSetup.ts index 56d3fe90..2ac07d89 100644 --- a/src/routes/onboarding/useServerSetup.ts +++ b/src/routes/onboarding/useServerSetup.ts @@ -1,7 +1,14 @@ import { useCallback, useState } from "react"; +import { Swiper } from "swiper/types"; // `name` for in-code usage, `label` for display -const steps = [ +export interface Step { + name: string; + label: string; + canJumpTo?: string[]; +} + +const steps: Step[] = [ { name: "welcomePage", label: "Welcome Page" @@ -31,12 +38,12 @@ const steps = [ ]; export default function useServerSetup() { - const [swiper, setSwiper] = useState(null); + const [swiper, setSwiper] = useState(null); - const [index, setIndex] = useState(0); + const [index, setIndex] = useState(0); const step = steps[index].name; const setStep = useCallback( - (name) => { + (name: string) => { const newIndex = steps.map((step) => step.name).indexOf(name); setIndex(newIndex); if (swiper !== null) { diff --git a/src/routes/reg/ExpiredTip.tsx b/src/routes/reg/ExpiredTip.tsx index fa295df8..ad8cea60 100644 --- a/src/routes/reg/ExpiredTip.tsx +++ b/src/routes/reg/ExpiredTip.tsx @@ -1,4 +1,3 @@ -// import React from "react"; import styled from "styled-components"; const Styled = styled.div` diff --git a/src/routes/reg/RegWithUsername.tsx b/src/routes/reg/RegWithUsername.tsx index 7221778c..833d7004 100644 --- a/src/routes/reg/RegWithUsername.tsx +++ b/src/routes/reg/RegWithUsername.tsx @@ -1,17 +1,15 @@ -/* eslint-disable no-undef */ -import { useState, useEffect } from "react"; +import { useState, useEffect, FC, FormEvent, ChangeEvent } from "react"; import { useDispatch } from "react-redux"; import { useParams } from "react-router-dom"; +import toast from "react-hot-toast"; import { setAuthData } from "../../app/slices/auth.data"; - import Input from "../../common/component/styled/Input"; import Button from "../../common/component/styled/Button"; import { useLoginMutation, useCheckMagicTokenValidMutation } from "../../app/services/auth"; -import toast from "react-hot-toast"; import ExpiredTip from "./ExpiredTip"; import { useRegisterMutation } from "../../app/services/auth"; -export default function RegWithUsername() { +const RegWithUsername: FC = () => { const [checkTokenInvalid, { data: isTokenValid, isLoading: checkingToken }] = useCheckMagicTokenValidMutation(); const [ @@ -28,7 +26,8 @@ export default function RegWithUsername() { const [username, setUsername] = useState(""); const query = new URLSearchParams(location.search); // const githubCode = query.get("gcode"); - const token = query.get("magic_token"); + // todo: check if query param exists + const token = query.get("magic_token") as string; useEffect(() => { if (token) { checkTokenInvalid(token); @@ -36,25 +35,29 @@ export default function RegWithUsername() { }, [token]); useEffect(() => { - switch (loginError?.status) { - case 401: - toast.error("Invalided Token"); - break; - - default: - break; + if (loginError && "status" in loginError) { + switch (loginError.status) { + case 401: + toast.error("Invalided Token"); + break; + default: + break; + } } }, [loginError]); - useEffect(() => { - switch (regError?.status) { - case 409: - toast.error("Something Conflicted!"); - break; - default: - break; + useEffect(() => { + if (regError && "status" in regError) { + switch (regError.status) { + case 409: + toast.error("Something Conflicted!"); + break; + default: + break; + } } }, [regError]); + useEffect(() => { const isSuccess = loginSuccess || regSuccess; const data = loginData || regData; @@ -67,7 +70,7 @@ export default function RegWithUsername() { } }, [loginSuccess, regSuccess, loginData, regData]); - const handleAuth = (evt) => { + const handleAuth = (evt: FormEvent) => { evt.preventDefault(); if (from == "reg") { register({ @@ -83,13 +86,12 @@ export default function RegWithUsername() { } }; - const handleInput = (evt) => { - const { value } = evt.target; - setUsername(value); + const handleInput = (evt: ChangeEvent) => { + setUsername(evt.target.value); }; - console.log("ffff", from); - if (!token) return "No Token"; - if (checkingToken) return "Checking Magic Link..."; + + if (!token) return <>"No Token"; + if (checkingToken) return <>"Checking Magic Link..."; if (!isTokenValid) return ; const isLoading = loginLoading || regLoading; const isSuccess = loginSuccess || regSuccess; @@ -112,9 +114,12 @@ export default function RegWithUsername() { onChange={handleInput} /> ); -} +}; + +export default RegWithUsername; diff --git a/src/routes/reg/Register.tsx b/src/routes/reg/Register.tsx index cefb98b5..9c24d018 100644 --- a/src/routes/reg/Register.tsx +++ b/src/routes/reg/Register.tsx @@ -1,6 +1,5 @@ -import { useState, useEffect } from "react"; +import { useState, useEffect, ChangeEvent, FormEvent } from "react"; import toast from "react-hot-toast"; -// import { useNavigate } from "react-router-dom"; import BASE_URL, { KEY_LOCAL_MAGIC_TOKEN } from "../../app/config"; import Input from "../../common/component/styled/Input"; import Button from "../../common/component/styled/Button"; @@ -13,13 +12,19 @@ import useGoogleAuthConfig from "../../common/hook/useGoogleAuthConfig"; import GoogleLoginButton from "../../common/component/GoogleLoginButton"; import GithubLoginButton from "../../common/component/GithubLoginButton"; +interface AuthForm { + email: string; + password: string; + confirmPassword: string; +} + export default function Reg() { const [sendRegMagicLink, { isLoading: signingUp, data, isSuccess }] = useSendRegMagicLinkMutation(); const [checkEmail, { isLoading: checkingEmail }] = useLazyCheckEmailQuery(); // const navigateTo = useNavigate(); const [magicToken, setMagicToken] = useState(""); - const [input, setInput] = useState({ + const [input, setInput] = useState({ email: "", password: "", confirmPassword: "" @@ -47,7 +52,7 @@ export default function Reg() { } }, [isSuccess, data]); - const handleReg = async (evt) => { + const handleReg = async (evt: FormEvent) => { evt.preventDefault(); const { email, password, confirmPassword } = input; if (password !== confirmPassword) { @@ -55,7 +60,6 @@ export default function Reg() { return; } const { data: canReg } = await checkEmail(email); - console.log("can reg", canReg); if (canReg) { sendRegMagicLink({ magic_token: magicToken, @@ -67,21 +71,23 @@ export default function Reg() { } // sendMagicLink(email); }; + const handleCompare = () => { const { password, confirmPassword } = input; if (password !== confirmPassword) { toast.error("Not Same Password!"); } }; - const handleInput = (evt) => { - const { type } = evt.target.dataset; + + const handleInput = (evt: ChangeEvent) => { + const { type } = evt.target.dataset as { type: keyof AuthForm }; const { value } = evt.target; - // console.log(type, value); setInput((prev) => { prev[type] = value; return { ...prev }; }); }; + const { clientId } = useGoogleAuthConfig(); const { config: githubAuthConfig } = useGithubAuthConfig(); const { data: loginConfig, isSuccess: loginConfigSuccess } = useGetLoginConfigQuery(); @@ -94,10 +100,11 @@ export default function Reg() { const googleLogin = enableGoogleLogin && clientId; // magic token 没有并且没有开放注册 if (whoCanSignUp !== "EveryOne" && !magicToken) - return `Sign up method is updated to Invitation Link Only`; + return <>Sign up method is updated to Invitation Link Only; const { email, password, confirmPassword } = input; if (data?.mail_is_sent) return ; const isLoading = signingUp || checkingEmail; + return ( <>
    diff --git a/src/routes/reg/index.tsx b/src/routes/reg/index.tsx index a47c69a5..5216c5b1 100644 --- a/src/routes/reg/index.tsx +++ b/src/routes/reg/index.tsx @@ -2,8 +2,6 @@ import { Outlet } from "react-router-dom"; import StyledWrapper from "./styled"; export default function RegContainer() { - // const isRegHome = useMatch(`/register`); - return (
    diff --git a/src/routes/resources/Search.tsx b/src/routes/resources/Search.tsx index 11f21796..d8ee3173 100644 --- a/src/routes/resources/Search.tsx +++ b/src/routes/resources/Search.tsx @@ -1,3 +1,4 @@ +import { ChangeEvent, FC } from "react"; import styled from "styled-components"; import iconSearch from "../../assets/icons/search.svg?url"; @@ -24,8 +25,14 @@ const Styled = styled.div` } `; -export default function Search({ value = "", updateSearchValue = null, embed = false }) { - const handleChange = (evt) => { +interface Props { + value?: string; + updateSearchValue?: (value: string) => void; + embed?: boolean; +} + +const Search: FC = ({ value = "", updateSearchValue = null, embed = false }) => { + const handleChange = (evt: ChangeEvent) => { if (updateSearchValue) { updateSearchValue(evt.target.value); } @@ -36,4 +43,6 @@ export default function Search({ value = "", updateSearchValue = null, embed = f ); -} +}; + +export default Search; diff --git a/src/routes/sendMagicLink/index.tsx b/src/routes/sendMagicLink/index.tsx index 575722a7..f20cbbe7 100644 --- a/src/routes/sendMagicLink/index.tsx +++ b/src/routes/sendMagicLink/index.tsx @@ -22,8 +22,7 @@ export default function SendMagicLinkPage() { }, [isSuccess]); useEffect(() => { - if (error) { - console.log(error); + if (error && "status" in error) { switch (error.status) { case "PARSING_ERROR": toast.error(error.data); @@ -32,7 +31,7 @@ export default function SendMagicLinkPage() { toast.error("Username or Password Incorrect"); break; case 404: - toast.error("Account not exsit"); + toast.error("Account not exist"); break; default: toast.error("Something Error"); @@ -53,7 +52,6 @@ export default function SendMagicLinkPage() { const handleInput = (evt: ChangeEvent) => { const { value } = evt.target; - console.log(value); setEmail(value); }; diff --git a/src/routes/sendMagicLink/styled.tsx b/src/routes/sendMagicLink/styled.tsx index cd232fbd..883c3c12 100644 --- a/src/routes/sendMagicLink/styled.tsx +++ b/src/routes/sendMagicLink/styled.tsx @@ -1,4 +1,5 @@ import styled from "styled-components"; + const StyledWrapper = styled.div` display: flex; justify-content: center; @@ -8,7 +9,7 @@ const StyledWrapper = styled.div` max-width: 440px; padding: 32px 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; diff --git a/src/routes/setting/APIConfig.tsx b/src/routes/setting/APIConfig.tsx index c09f1509..f3d91a91 100644 --- a/src/routes/setting/APIConfig.tsx +++ b/src/routes/setting/APIConfig.tsx @@ -86,10 +86,10 @@ export default function APIConfig() { Are you sure to update API secret? Previous secret will be invalided
    - -
    diff --git a/src/routes/setting/LogoutConfirmModal.tsx b/src/routes/setting/LogoutConfirmModal.tsx index aa165059..a6a3567e 100644 --- a/src/routes/setting/LogoutConfirmModal.tsx +++ b/src/routes/setting/LogoutConfirmModal.tsx @@ -1,12 +1,12 @@ -// import React from "react"; -import { useEffect, useState } from "react"; +import { ChangeEvent, FC, useEffect, useState } from "react"; import styled from "styled-components"; -// import { useNavigate } from "react-router-dom"; - +import toast from "react-hot-toast"; +import Modal from "../../common/component/Modal"; import StyledModal from "../../common/component/styled/Modal"; import Button from "../../common/component/styled/Button"; import Checkbox from "../../common/component/styled/Checkbox"; import useLogout from "../../common/hook/useLogout"; + const StyledConfirm = styled(StyledModal)` .clear { font-weight: normal; @@ -26,21 +26,25 @@ const StyledConfirm = styled(StyledModal)` } } `; -import Modal from "../../common/component/Modal"; -import toast from "react-hot-toast"; -export default function LogoutConfirmModal({ closeModal }) { + +interface Props { + closeModal: () => void; +} + +const LogoutConfirmModal: FC = ({ closeModal }) => { const [clearLocal, setClearLocal] = useState(false); const { logout, exited, exiting, clearLocalData } = useLogout(); const handleLogout = () => { logout(); }; - const handleCheck = (evt) => { + + const handleCheck = (evt: ChangeEvent) => { setClearLocal(evt.target.checked); }; + useEffect(() => { if (exited) { if (clearLocal) { - console.log("clear all store"); clearLocalData(); } toast.success("Logout Successfully"); @@ -50,6 +54,7 @@ export default function LogoutConfirmModal({ closeModal }) { // location.reload(); } }, [exited, clearLocal]); + return ( } @@ -74,4 +79,6 @@ export default function LogoutConfirmModal({ closeModal }) { ); -} +}; + +export default LogoutConfirmModal; diff --git a/src/routes/setting/ProfileBasicEditModal.tsx b/src/routes/setting/ProfileBasicEditModal.tsx index dda5e841..92956bab 100644 --- a/src/routes/setting/ProfileBasicEditModal.tsx +++ b/src/routes/setting/ProfileBasicEditModal.tsx @@ -1,5 +1,4 @@ -// import React from "react"; -import { useEffect, useState } from "react"; +import { ChangeEvent, FC, useEffect, useState } from "react"; import styled from "styled-components"; import toast from "react-hot-toast"; import Input from "../../common/component/styled/Input"; @@ -24,18 +23,27 @@ const StyledEdit = styled(StyledModal)` } `; -export default function ProfileBasicEditModal({ +interface Props { + label?: string; + valueKey?: string; + value?: string; + title?: string; + intro?: string; + closeModal: () => void; +} + +const ProfileBasicEditModal: FC = ({ label = "Username", valueKey = "name", value = "", title = "Change your username", intro = "Enter a new username and your existing password.", closeModal -}) { +}) => { const [input, setInput] = useState(value); // const dispatch = useDispatch(); const [update, { isLoading, isSuccess }] = useUpdateInfoMutation(); - const handleChange = (evt) => { + const handleChange = (evt: ChangeEvent) => { setInput(evt.target.value); }; const handleUpdate = () => { @@ -69,4 +77,6 @@ export default function ProfileBasicEditModal({ ); -} +}; + +export default ProfileBasicEditModal; diff --git a/src/routes/setting/UpdatePasswordModal.tsx b/src/routes/setting/UpdatePasswordModal.tsx index 976f401e..0b286ef6 100644 --- a/src/routes/setting/UpdatePasswordModal.tsx +++ b/src/routes/setting/UpdatePasswordModal.tsx @@ -27,9 +27,15 @@ interface Props { closeModal: () => void; } +interface BaseForm { + current: string; + newPassword: string; + confirmPassword: string; +} + const ProfileBasicEditModal: FC = ({ closeModal }) => { const { data } = useGetCredentialsQuery(); - const [input, setInput] = useState({ + const [input, setInput] = useState({ current: "", newPassword: "", confirmPassword: "" @@ -37,7 +43,7 @@ const ProfileBasicEditModal: FC = ({ closeModal }) => { // const dispatch = useDispatch(); const [updatePassword, { isLoading, isSuccess }] = useUpdatePasswordMutation(); const handleChange = (evt: ChangeEvent) => { - const { type } = evt.target.dataset; + const { type } = evt.target.dataset as { type: keyof BaseForm }; setInput((prev) => { return { ...prev, [type]: evt.target.value }; }); diff --git a/src/routes/setting/config/IssuerList/index.tsx b/src/routes/setting/config/IssuerList/index.tsx index f28684dd..cd267553 100644 --- a/src/routes/setting/config/IssuerList/index.tsx +++ b/src/routes/setting/config/IssuerList/index.tsx @@ -1,15 +1,25 @@ -import { ChangeEvent, useState } from "react"; -import Select from "../../../../common/component/styled/Select"; +import { ChangeEvent, FC, useState } from "react"; +import Select, { Option } from "../../../../common/component/styled/Select"; import Button from "../../../../common/component/styled/Button"; import Input from "../../../../common/component/styled/Input"; import Toggle from "../../../../common/component/styled/Toggle"; import options from "./items.json"; import Styled from "./styled"; -// import IconPlus from "../../../../assets/icons/plus.circle.svg"; import IconMinus from "../../../../assets/icons/minus.circle.svg"; -export default function IssuerList({ issuers = [], onChange }) { - const [select, setSelect] = useState({}); +interface Issuer { + domain: string; + enable: boolean; + favicon: string; +} + +interface Props { + issuers: Issuer[]; + onChange: (issuers: Issuer[]) => void; +} + +const IssuerList: FC = ({ issuers = [], onChange }) => { + const [select, setSelect] = useState | null>(null); const [newDomain, setNewDomain] = useState(""); const handleNewDomain = (evt: ChangeEvent) => { @@ -87,7 +97,9 @@ export default function IssuerList({ issuers = [], onChange }) {