Selaa lähdekoodia

忘记密码功能

fogwind 20 tuntia sitten
vanhempi
commit
9c008eb712

+ 0 - 26
src/app/(public)/customer/reset-password/[token]/page.tsx

@@ -1,26 +0,0 @@
-import ResetPasswordWrapper from "../_components/ResetPasswordWrapper";
-
-export default async function ResetPasswordPage({
-  searchParams,
-  params,
-}: {
-  params: Promise<{ token: string; }>;
-  searchParams?: Promise<{ [key: string]: string | string[] | undefined }>;
-}) {
-    const { token } = await params;
-    const resolvedParams = await searchParams;
-    //   const { page = '1', sort = 'asc', query = '' } = await searchParams
-
-
-
-
-
-
-  return (
-    <>
-        <ResetPasswordWrapper />
-        {token}
-        <p>{resolvedParams ? JSON.stringify(resolvedParams) : resolvedParams}</p>
-    </>
-  );
-}

+ 54 - 27
src/app/(public)/customer/reset-password/_components/ResetPasswordWrapper.tsx

@@ -1,28 +1,39 @@
 "use client";
 
 import { useForm, SubmitHandler } from "react-hook-form";
+import {RESET_PASSWORD} from "@/graphql";
+import { useRouter } from "next/navigation";
+import { useApolloClient } from "@apollo/client/react";
+import { useCustomToast } from '@/utils/hooks/useToast';
+import { confirmDialog } from "@/components/theme/ui/kernel/confirm/api";
 import { overlayLoading } from "@/components/theme/ui/kernel/loading/api";
 import PasswordInput from "@/components/theme/ui/PasswordInput";
 
 type ResetPasswordFormData= {
     password: string;
-    password_confirmation: string;
+    passwordConfirmation: string;
 };
 
-export default function ResetPasswordWrapper() {
-    // const { showToast } = useCustomToast();
-    // const [emailValue, setEmailValue] = useState('');
-
+export default function ResetPasswordWrapper({
+    token,
+    email
+}: {
+    token: string;
+    email: string;
+}) {
+    const router = useRouter();
+    const { showToast } = useCustomToast();
+    const apolloClient = useApolloClient();
     const {
         register,
         handleSubmit,
         formState: { errors },
     } = useForm<ResetPasswordFormData>({
-        mode: "onSubmit",
+        mode: "onChange",
         reValidateMode: "onChange",
         defaultValues: {
             "password": '',
-            "password_confirmation": ''
+            "passwordConfirmation": ''
         }
     });
 
@@ -31,24 +42,40 @@ export default function ResetPasswordWrapper() {
         overlayLoading.start();
         console.log(data);
 
-        // try {
-        //     const result = await recoverPasswordAction({
-        //         password: data.password,
-        //         password_confirmation: data.password_confirmation
-        //     });
+        apolloClient.mutate({
+            mutation: RESET_PASSWORD,
+            variables: {
+                token: token,
+                email: email,
+                password: data.password,
+                passwordConfirmation: data.passwordConfirmation
+            }
+        }).then((res) => {
+            overlayLoading.stop();
+            const resData = res.data?.createResetPassword?.resetPassword ?? null;
+            if(resData?.success) {
 
-        //     // Show success/error API response
-        //     if (result.success) {
-        //         showToast(result.msg, "success");
-        //         setEmailValue(data.email);
-        //     } else {
-        //         showToast(result.msg, "danger");
-        //     }
-        // } catch {
-        //     showToast("Something went wrong. Please try again later.", "danger");
-        // } finally {
-        //     overlayLoading.stop();
-        // }
+                confirmDialog({
+                    title: "Notice",
+                    content: "Reset password successfully. Please to login.",
+                    noCancel: true,
+                }).then(() => {
+                    router.replace('/customer/login');
+                });
+            } else {
+                // const msg = (resData?.message ?? 'Reset password failed.') + ' You can try again.'
+                // confirmDialog({
+                //     title: "Notice",
+                //     content: msg,
+                // }).then(() => {
+                //     router.replace('/customer/forget-password');
+                // }).catch(() => {/**关闭 */});
+                showToast(resData?.message ?? 'Reset password failed.', "danger");
+            }
+        }).catch((err) => {
+            overlayLoading.stop();
+            showToast(err.message, "danger");
+        });
     };
 
     return (
@@ -80,7 +107,7 @@ export default function ResetPasswordWrapper() {
                                 return true;
                             },
                         })}
-                        error={errors.password_confirmation && errors.password_confirmation.message}
+                        error={errors.password && errors.password.message}
                     />
                 </div>
                 <div className="w-full mt-4">
@@ -90,7 +117,7 @@ export default function ResetPasswordWrapper() {
 
                     <PasswordInput
                         placeholder="Confirm password"
-                        {...register("password_confirmation", {
+                        {...register("passwordConfirmation", {
                             required: "Confirm Password is required",
                             minLength: {
                                 value: 6,
@@ -108,7 +135,7 @@ export default function ResetPasswordWrapper() {
                                 return true;
                             },
                         })}
-                        error={errors.password_confirmation && errors.password_confirmation.message}
+                        error={errors.passwordConfirmation && errors.passwordConfirmation.message}
                     />
                 </div>
 

+ 28 - 0
src/app/(public)/customer/reset-password/page.tsx

@@ -0,0 +1,28 @@
+import ResetPasswordWrapper from "./_components/ResetPasswordWrapper";
+
+export default async function ResetPasswordPage({
+    searchParams
+}: {
+    searchParams: Promise<{
+        email: string;
+        token: string;
+    }>;
+}) {
+    const resolvedParams = await searchParams; // resolvedParams可能是空对象
+    let errorMsg: string | null = null;
+    if(!resolvedParams.token || !resolvedParams.email) {
+        errorMsg = "token or email is undefined!"
+    }
+
+    return (<>
+        {errorMsg ?
+            <p className="mt-6 text-center text-ly-14">{errorMsg}</p>
+        :
+            <ResetPasswordWrapper 
+                token={resolvedParams.token}
+                email={resolvedParams.email}
+            />
+        }
+        
+    </>);
+}

+ 36 - 0
src/app/api/customer/check-email/route.ts

@@ -0,0 +1,36 @@
+import { NextResponse, NextRequest } from "next/server";
+import { restApiFetch } from "@/utils/bagisto";
+
+
+// http://nshop.test/api/customer/check-email?email=bb@tt.com
+export async function GET(request: NextRequest) {
+  try {
+    const searchParams = request.nextUrl.searchParams;
+    const email = searchParams.get('email');
+    const response = await restApiFetch<any>({
+      api: "/customer/check-email",
+      method: "GET",
+      cache: "no-store",
+      variables: {
+        email: email
+      }
+
+    });
+
+    return NextResponse.json(
+      response.body,
+      {status: response.status}
+    );
+
+  } catch (error) {
+
+
+    return NextResponse.json(
+      {
+        message: "Network error",
+        error: error instanceof Error ? error.message : error,
+      },
+      { status: 500 }
+    );
+  }
+}

+ 23 - 0
src/graphql/customer/mutations/ResetPassword.ts

@@ -0,0 +1,23 @@
+import { gql,TypedDocumentNode } from "@apollo/client";
+import { ResetPasswordData, ResetPasswordVariables } from "@/types/customer/type";
+
+
+export const RESET_PASSWORD: TypedDocumentNode<ResetPasswordData,ResetPasswordVariables> = gql`
+mutation createResetPassword(
+    $token: String!,
+    $email: String!,
+    $password: String!,
+    $passwordConfirmation: String!
+) { 
+    createResetPassword(input: { 
+        token: $token,
+        email: $email,
+        password: $password,
+        passwordConfirmation: $passwordConfirmation
+    }) { 
+        resetPassword { 
+            success 
+            message 
+        } 
+    } 
+}`;

+ 1 - 0
src/graphql/customer/mutations/index.ts

@@ -3,3 +3,4 @@ export { CUSTOMER_LOGIN} from "./CustomerLogin";
 export { CUSTOMER_LOGOUT} from "./CustomerLogout";
 export { VERIFY_CUSTOMER} from "./VerifyCustomer";
 export {FORGET_PASSWORD} from "./ForgetPassword";
+export {RESET_PASSWORD} from "./ResetPassword";

+ 1 - 1
src/lib/restApiClient.ts

@@ -1,7 +1,7 @@
 'use client';
 /**前端客户端组件调rest api 接口 */
 import { emitAuthExpired } from "@/utils/auth/auth-events";
-export async function clientFetch<T = any>(apiUrl: string, options: RequestInit = {}): Promise<T> {
+export async function clientFetch<T = any>(apiUrl: string | URL, options: RequestInit = {}): Promise<T> {
     // 请求的是nextjs的代理接口
 
     const headers = {

+ 23 - 0
src/types/customer/type.ts

@@ -12,6 +12,29 @@ export type {
     OrderAddressType
 } from "./order";
 
+export interface CheckEmailRegisteredData {
+    success: boolean;
+    message: string;
+    data:{
+        email: string;
+        exists: boolean;
+    }
+}
+export interface ResetPasswordData{
+    createResetPassword: {
+      resetPassword: {
+        success: boolean;
+        message: string;
+      }
+    }
+}
+export interface ResetPasswordVariables {
+    token: string;
+    email: string;
+    password: string;
+    passwordConfirmation: string;
+}
+
 export interface LoginFormData {
     username:string;
     password:string;