From 0df3237d21407972b468f6cdfcd8caa36ac937af Mon Sep 17 00:00:00 2001 From: liangzai <2440983361@qq.com> Date: Mon, 23 Sep 2024 21:09:54 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9Edialog=20=E4=BD=99=E9=A2=9D?= =?UTF-8?q?=E4=B8=8D=E8=B6=B3=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/contexts/CombinedProviders.tsx | 7 +- src/contexts/DialogContext.tsx | 104 +++++++++++++++++++++++++++++ src/hooks/useFetch.tsx | 13 +++- 3 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 src/contexts/DialogContext.tsx diff --git a/src/contexts/CombinedProviders.tsx b/src/contexts/CombinedProviders.tsx index 8246665..7cd839f 100644 --- a/src/contexts/CombinedProviders.tsx +++ b/src/contexts/CombinedProviders.tsx @@ -1,9 +1,14 @@ import { ToastProvider } from "@/contexts/ToastContext"; import { UserProvider } from "@/contexts/UserContext"; +import { DialogProvider } from "./DialogContext"; export default function CombinedProviders({ children, }: Readonly<{ children: React.ReactNode; }>) { - return {children}; + return ( + + {children} + + ); } diff --git a/src/contexts/DialogContext.tsx b/src/contexts/DialogContext.tsx new file mode 100644 index 0000000..01c7089 --- /dev/null +++ b/src/contexts/DialogContext.tsx @@ -0,0 +1,104 @@ +// components/DialogProvider.tsx +"use client"; +import React, { createContext, useContext, useState, ReactNode } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { useTranslations } from "next-intl"; + +interface DialogContextType { + showDialog: ( + message: string, + onConfirm: () => void, + onCancel?: () => void + ) => void; +} +interface Dialog { + id: number; + message: string; + onConfirm: () => void; + onCancel?: () => void; +} + +const DialogContext = createContext(undefined); + +export const DialogProvider: React.FC<{ children: ReactNode }> = ({ + children, +}) => { + const [dialogs, setDialogs] = useState([]); + const [nextId, setNextId] = useState(0); + const t = useTranslations("dialog"); + const showDialog = ( + message: string, + onConfirm: () => void, + onCancel?: () => void + ) => { + setDialogs((prevDialogs) => [ + ...prevDialogs, + { id: nextId, message, onConfirm, onCancel }, + ]); + setNextId(nextId + 1); + }; + + const removeDialog = (id: number) => { + setDialogs((prevDialogs) => + prevDialogs.filter((dialog) => dialog.id !== id) + ); + }; + + return ( + + {children} + {/* Dialog container */} + + {dialogs.map((dialog) => ( + + + {dialog.message} + + { + dialog.onCancel?.(); + removeDialog(dialog.id); + }} + > + {t("Cancel")} + + { + dialog.onConfirm(); + removeDialog(dialog.id); + }} + > + {t("Confirmation")} + + + + + ))} + + + ); +}; + +// 自定义 hook 来使用 DialogContext +export const useDialog = () => { + const context = useContext(DialogContext); + if (context === undefined) { + throw new Error("useDialog must be used within a DialogProvider"); + } + return context; +}; diff --git a/src/hooks/useFetch.tsx b/src/hooks/useFetch.tsx index 071623b..7938f2b 100644 --- a/src/hooks/useFetch.tsx +++ b/src/hooks/useFetch.tsx @@ -2,7 +2,9 @@ import { useState } from "react"; import queryString from "query-string"; import { useToast } from "@/contexts/ToastContext"; - +import { useDialog } from "@/contexts/DialogContext"; +import { useRouter } from "next/navigation"; +import { useTranslations } from "next-intl"; type Method = "GET" | "POST" | "PUT" | "DELETE" | "PATCH"; type Params = Record; @@ -29,6 +31,9 @@ const useFetch = ({ url, method, cacheTime = 0 }: UseFetch) => { const [error, setError] = useState(null); const { addToast } = useToast(); + const { showDialog } = useDialog(); + const t = useTranslations("fetch"); + const router = useRouter(); const fetchData = async (params?: Params): Promise => { setError(null); setLoading(true); @@ -53,6 +58,11 @@ const useFetch = ({ url, method, cacheTime = 0 }: UseFetch) => { } catch (err: any) { setError(err.message); addToast(err.message, "error"); + if (err.code === 402) { + showDialog(t("InsufficientIntegration"), () => { + router.push("/pricing"); + }); + } reject(err.message); // 失败时 reject 错误信息 } finally { setLoading(false); @@ -143,6 +153,7 @@ const interceptorsResponse = (res: Response): Promise => { }); } else { return reject({ + code: data.code, message: data.message, url: requestUrl, });