diff --git a/space/pages/accounts/password.tsx b/space/pages/accounts/password.tsx new file mode 100644 index 0000000000..335fba6193 --- /dev/null +++ b/space/pages/accounts/password.tsx @@ -0,0 +1,184 @@ +import { useCallback } from "react"; +import Image from "next/image"; +import Link from "next/link"; +import { useRouter } from "next/router"; +import { Lightbulb } from "lucide-react"; +import { Controller, useForm } from "react-hook-form"; +// services +import authService from "services/authentication.service"; + +// hooks +import useToast from "hooks/use-toast"; +// ui +import { Button, Input } from "@plane/ui"; +// images +import BluePlaneLogoWithoutText from "public/plane-logos/blue-without-text.png"; +import latestFeatures from "public/onboarding/onboarding-pages.svg"; +// type +import { useMobxStore } from "lib/mobx/store-provider"; +import { IUser } from "types/user"; + +// types + +type TResetPasswordFormValues = { + password: string; +}; + +const defaultValues: TResetPasswordFormValues = { + password: "", +}; + +const ForgotPasswordPage = () => { + // router + const router = useRouter(); + + const { next_path } = router.query as { next_path: string }; + const { uidb64, token, email } = router.query; + // toast + const { setToastAlert } = useToast(); + // mobx store + const { + user: { fetchCurrentUser }, + } = useMobxStore(); + // form info + const { + control, + formState: { errors, isSubmitting, isValid }, + handleSubmit, + } = useForm({ + defaultValues: { + ...defaultValues, + }, + }); + + const handleSignInRedirection = useCallback( + async (user: IUser) => { + const isOnboard = user?.is_onboarded || false; + + if (isOnboard) { + if (next_path) router.push(next_path); + else router.push("/login"); + } else { + if (next_path) router.push(`/onboarding?next_path=${next_path}`); + else router.push("/onboarding"); + } + }, + [router, next_path] + ); + + const mutateUserInfo = useCallback(async () => { + await fetchCurrentUser().then(async (user) => { + await handleSignInRedirection(user); + }); + }, [fetchCurrentUser, handleSignInRedirection]); + + const handleResetPassword = async (formData: TResetPasswordFormValues) => { + if (!uidb64 || !token || !email) return; + + const payload = { + new_password: formData.password, + }; + + await authService + .resetPassword(uidb64.toString(), token.toString(), payload) + .then(() => mutateUserInfo()) + .catch((err) => + setToastAlert({ + type: "error", + title: "Error!", + message: err?.error ?? "Something went wrong. Please try again.", + }) + ); + }; + + return ( +
+
+
+ Plane Logo + Plane +
+
+ +
+
+
+

+ Let{"'"}s get a new password +

+
+ +
+ ( + + )} + /> +

+ Whatever you choose now will be your account{"'"}s password until you change it. +

+
+ +

+ When you click the button above, you agree with our{" "} + + terms and conditions of service. + +

+
+
+
+ +

+ Try the latest features, like Tiptap editor, to write compelling responses.{" "} + + See new features + +

+
+
+
+ Plane Issues +
+
+
+
+
+ ); +}; + +export default ForgotPasswordPage; diff --git a/space/services/authentication.service.ts b/space/services/authentication.service.ts index 4befe0c33a..0a82d4b0d9 100644 --- a/space/services/authentication.service.ts +++ b/space/services/authentication.service.ts @@ -46,6 +46,26 @@ class AuthService extends APIService { }); } + async resetPassword( + uidb64: string, + token: string, + data: { + new_password: string; + } + ): Promise { + return this.post(`/api/reset-password/${uidb64}/${token}/`, data, { headers: {} }) + .then((response) => { + if (response?.status === 200) { + this.setAccessToken(response?.data?.access_token); + this.setRefreshToken(response?.data?.refresh_token); + return response?.data; + } + }) + .catch((error) => { + throw error?.response?.data; + }); + } + async emailLogin(data: any) { return this.post("/api/sign-in/", data, { headers: {} }) .then((response) => {