chore: download case

This commit is contained in:
Tristan Yang
2025-08-22 09:55:10 +08:00
parent 749d825bfe
commit e64fe6a82a
5 changed files with 52 additions and 32 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "vocechat-web", "name": "vocechat-web",
"version": "0.9.19", "version": "0.9.20",
"homepage": "https://voce.chat", "homepage": "https://voce.chat",
"dependencies": { "dependencies": {
"@metamask/onboarding": "^1.0.1", "@metamask/onboarding": "^1.0.1",
+47 -27
View File
@@ -1,4 +1,4 @@
import { FC, useEffect } from "react"; import { FC, useEffect, useRef } from "react";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FetchBaseQueryError } from "@reduxjs/toolkit/dist/query"; import { FetchBaseQueryError } from "@reduxjs/toolkit/dist/query";
@@ -12,58 +12,78 @@ type Props = {
code: string; code: string;
from?: GithubLoginSource; from?: GithubLoginSource;
}; };
const GithubCallback: FC<Props> = ({ code, from = "webapp" }) => { const GithubCallback: FC<Props> = ({ code, from = "webapp" }) => {
const { t } = useTranslation("auth"); const { t } = useTranslation("auth");
const { t: ct } = useTranslation(); const { t: ct } = useTranslation();
//拿本地存的 magic token
const magic_token = localStorage.getItem(KEY_LOCAL_MAGIC_TOKEN); // 使用 ref 来防止重复调用
const hasTriedLogin = useRef(false);
const [login, { isLoading, isSuccess, error }] = useLoginMutation(); const [login, { isLoading, isSuccess, error }] = useLoginMutation();
useEffect(() => { useEffect(() => {
if (code && !isLoading) { // 防止重复调用登录
if (code && !hasTriedLogin.current && !isLoading && !isSuccess) {
const magic_token = localStorage.getItem(KEY_LOCAL_MAGIC_TOKEN);
hasTriedLogin.current = true;
login({ login({
magic_token, magic_token,
code, code,
type: "github", type: "github",
}); });
} }
}, [code, isLoading]); }, [code, login, isLoading, isSuccess]); // 完整的依赖项列表
useEffect(() => { useEffect(() => {
if (isSuccess) { if (isSuccess || from == "webapp") {
toast.success(ct("tip.login")); toast.success(ct("tip.login"));
// 通知 widget // 通知 widget
if (from == "widget") { if (from === "widget") {
localStorage.setItem("widget", `${new Date().getTime()}`); localStorage.setItem("widget", `${new Date().getTime()}`);
} }
// webapp 跳回首页 // webapp 跳回首页
if (from == "webapp") { if (from === "webapp") {
location.href = "/"; location.href = "/";
} }
} }
}, [isSuccess, from]); }, [isSuccess, from, ct]);
useEffect(() => {
if (error) { // useEffect(() => {
console.log(error); // if (error) {
// todo: why? // console.log(error);
switch ((error as FetchBaseQueryError).status) {
case 410: // switch ((error as FetchBaseQueryError).status) {
toast.error( // case 410:
"No associated account found, please contact user admin for an invitation link to join." // toast.error(
); // "No associated account found, please contact user admin for an invitation link to join."
break; // );
default: // break;
toast.error("Something Error"); // default:
break; // {
} // console.log("login error");
} // // toast.error("Something Error");
}, [error]); // }
// break;
// }
// }
// }, [error]);
const handleClose = () => { const handleClose = () => {
window.close(); window.close();
}; };
if (error) return <span className="text-red-500 text-lg">Something Error</span>;
// if (error) {
// return <span className="text-red-500 text-lg">Something Error</span>;
// }
return ( return (
<section className="flex-center flex-col gap-3"> <section className="flex-center flex-col gap-3">
<StyledButton onClick={handleClose}>{ct("action.close")}</StyledButton> <StyledButton onClick={handleClose}>{ct("action.close")}</StyledButton>
{isSuccess && from == "widget" && <h1>{t("github_cb_tip")}</h1>} {isSuccess && from === "widget" && <h1>{t("github_cb_tip")}</h1>}
<span className="text-3xl text-green-600 font-bold"> <span className="text-3xl text-green-600 font-bold">
{isLoading ? t("github_logging_in") : t("github_login_success")} {isLoading ? t("github_logging_in") : t("github_login_success")}
</span> </span>
+2 -2
View File
@@ -14,7 +14,7 @@ const StyledWrapper = ({ children }: DOMAttributes<HTMLDivElement> & { children?
// type Props = { // type Props = {
// type: "payment_success"; // type: "payment_success";
// }; // };
// 该页面服务于一些第三方服务的回调,比如stripe付款成功的回调,GitHub登录成功的回调 // 该页面服务于一些第三方服务的回调,比如 stripe 付款成功的回调,GitHub 登录成功的回调
export default function CallbackPage() { export default function CallbackPage() {
const { type = "", payload = "" } = useParams(); const { type = "", payload = "" } = useParams();
// stripe 付款成功 // stripe 付款成功
@@ -25,7 +25,7 @@ export default function CallbackPage() {
</StyledWrapper> </StyledWrapper>
); );
} }
// github授权成功 // github 授权成功
if (type == "github") { if (type == "github") {
const query = new URLSearchParams(location.search); const query = new URLSearchParams(location.search);
const code = query.get("code") ?? ""; const code = query.get("code") ?? "";
+1 -1
View File
@@ -17,7 +17,7 @@ import SignUpLink from "./SignUpLink";
import SocialLoginButtons from "./SocialLoginButtons"; import SocialLoginButtons from "./SocialLoginButtons";
import { shallowEqual } from "react-redux"; import { shallowEqual } from "react-redux";
import SelectLanguage from "../../components/Language"; import SelectLanguage from "../../components/Language";
import Downloads from "../../components/downloads"; import Downloads from "../../components/Downloads";
const defaultInput = { const defaultInput = {
email: "", email: "",
+1 -1
View File
@@ -4,7 +4,7 @@ import { Outlet, useOutletContext, useSearchParams } from "react-router-dom";
import { useCheckMagicTokenValidMutation } from "@/app/services/auth"; import { useCheckMagicTokenValidMutation } from "@/app/services/auth";
import ExpiredTip from "./ExpiredTip"; import ExpiredTip from "./ExpiredTip";
import SelectLanguage from "../../components/Language"; import SelectLanguage from "../../components/Language";
import Downloads from "../../components/downloads"; import Downloads from "../../components/Downloads";
type ContextType = { token: string }; type ContextType = { token: string };
export default function RegContainer() { export default function RegContainer() {