This commit is contained in:
MuslemRahimi 2025-03-04 19:10:39 +01:00
parent 94298ec33f
commit 946d144cc9
4 changed files with 162 additions and 97 deletions

View File

@ -3,6 +3,22 @@ import { redirect } from "@sveltejs/kit";
export const load = async ({ locals }) => {
const { pb } = locals;
if (pb.authStore.isValid) {
redirect(303, "/");
throw redirect(303, "/");
}
}
};
export const actions = {
reset: async ({ request, locals }) => {
const { pb } = locals;
const formData = await request.formData();
const email = formData.get("email");
if (!email) {
return { error: "Email is required" };
}
await pb.collection("users").requestPasswordReset(email as string);
throw redirect(303, "/login");
}
};

View File

@ -1,29 +1,51 @@
<script lang="ts">
import { toast } from "svelte-sonner";
import { enhance } from "$app/forms";
import { pb } from "$lib/pocketbase";
import { goto } from "$app/navigation";
import SEO from "$lib/components/SEO.svelte";
let email: string = "";
let loading = false;
let email: String;
let isClicked = false;
async function resetPassword(event) {
event.preventDefault();
try {
await pb.collection("users").requestPasswordReset(email);
toast.success("Password resetted. Check your emails!", {
style:
"border-radius: 5px; background: #fff; color: #000; border-color: #4B5563; font-size: 15px;",
});
goto("/login");
} catch (err) {
toast.error(err, {
style:
"border-radius: 5px; background: #fff; color: #000; border-color: #4B5563; font-size: 15px;",
});
}
}
const submitReset = () => {
loading = true;
return async ({ result, update }) => {
switch (result.type) {
case "success":
toast.success("Password resetted. Check your emails!", {
style:
"border-radius: 5px; background: #fff; color: #000; border-color: #4B5563; font-size: 15px;",
});
await update();
break;
case "redirect":
isClicked = true;
toast.success("Password resetted. Check your emails!", {
style:
"border-radius: 5px; background: #fff; color: #000; border-color: #4B5563; font-size: 15px;",
});
await update();
break;
case "failure":
toast.error("Invalid credentials", {
style:
"border-radius: 5px; background: #fff; color: #000; border-color: #4B5563; font-size: 15px;",
});
await update();
break;
case "error":
toast.error(result.error.message, {
style:
"border-radius: 5px; background: #fff; color: #000; border-color: #4B5563; font-size: 15px;",
});
break;
default:
await update();
}
loading = false;
};
};
</script>
<SEO
@ -41,23 +63,39 @@
We'll send you an email with a link to reset your password.
</p>
<form
on:submit={resetPassword}
action="?/reset"
method="POST"
use:enhance={submitReset}
class="flex flex-col items-center space-y-2 w-5/6 sm:w-full pt-4"
>
<input
class="input input-bordered w-full max-w-lg bg-[#242527] placeholder-gray-400 text-white whitespace-normal ring-2"
name="email"
class="py-2.5 rounded w-full border border-gray-600 focus:outline-none max-w-lg bg-[#242527] placeholder-gray-400 text-white whitespace-normal"
type="email"
required={true}
required
bind:value={email}
autocomplete="off"
/>
<div class="w-full max-w-lg pt-2">
<button
type="submit"
class="py-2.5 font-semibold rounded bg-white text-black w-full"
>
Request Password Reset
</button>
<div class="w-full max-w-lg">
<div class="w-full max-w-lg pt-2 m-auto pb-5">
{#if !loading && !isClicked}
<button
type="submit"
class="cursor-pointer py-2.5 bg-[#fff] border-none sm:hover:bg-gray-300 transition duration-100 btn-md w-full rounded m-auto text-black font-semibold text-[1rem]"
>
<span> Request Password Reset</span>
</button>
{:else}
<label
class="cursor-not-allowed btn bg-[#fff] opacity-[0.5] border border-gray-600 sm:hover:bg-gray-300 transition duration-100 btn-md w-full rounded-md m-auto text-black font-semibold text-[1rem]"
>
<div class="flex flex-row m-auto items-center">
<span class="loading loading-infinity"></span>
<span class=" ml-1.5">Resetting</span>
</div>
</label>
{/if}
</div>
</div>
</form>
</div>

View File

@ -1,8 +1,51 @@
import { redirect, error } from "@sveltejs/kit";
import { updatePasswordSchema } from "$lib/schemas";
import { fail } from "@sveltejs/kit";
import { z } from "zod";
export const load = async ({ locals }) => {
const { pb, user } = locals;
const { pb } = locals;
if (!pb.authStore.isValid) {
redirect(303, "/login");
}
}
}
export const actions = {
updatePassword: async ({ request, locals }) => {
const { pb, user } = locals;
const formData = await request.formData();
const postData: Record<string, string> = {};
// Build a plain object from the form data.
for (const [key, value] of formData.entries()) {
if (typeof value === "string") {
postData[key] = value;
}
}
try {
// Validate form data using your Zod schema.
const cleanedData = updatePasswordSchema.parse(postData);
await pb.collection("users").update(user?.id, cleanedData);
return { success: true };
} catch (error) {
console.log(error)
if (error instanceof z.ZodError) {
// Map Zod errors to individual error messages.
const errors = {
errorOldPassword:
error.errors?.find((err) => err.path[0] === "oldPassword")?.message || "You're password is wrong",
errorPassword:
error.errors?.find((err) => err.path[0] === "password")?.message || "",
errorPasswordConfirm:
error.errors?.find((err) => err.path[0] === "passwordConfirm")?.message || "",
};
return fail(400, { errors, zodErrors: error.errors });
}
console.error("Unexpected error during password update:", error);
return fail(500, { error: "An unexpected error occurred" });
}
},
};

View File

@ -1,74 +1,36 @@
<script ts="lang">
import { pb } from "$lib/pocketbase";
<script lang="ts">
import { enhance } from "$app/forms";
import { toast } from "svelte-sonner";
import Input from "$lib/components/Input.svelte";
import { updatePasswordSchema } from "$lib/schemas";
import { goto } from "$app/navigation";
import { z } from "zod";
import SEO from "$lib/components/SEO.svelte";
let zodErrors = [];
export let data;
let errorOldPassword = "";
let errorPassword = "";
let errorPasswordConfirm = "";
export let form;
let loading = false;
async function updatePassword(event) {
const submitUpdatePassword = () => {
loading = true;
event.preventDefault(); // prevent the default form submission behavior
errorOldPassword = "";
errorPassword = "";
errorPasswordConfirm = "";
const formData = new FormData(event.target); // create a FormData object from the form
const postData = {};
for (const [key, value] of formData.entries()) {
postData[key] = value;
}
try {
// Use Zod validation
const cleanedData = updatePasswordSchema.parse(postData);
await pb.collection("users").update(data?.user?.id, cleanedData);
toast.success("Password updated!", {
style: "border-radius: 200px; background: #2A2E39; color: #fff;",
});
} catch (error) {
if (error instanceof z.ZodError) {
// Handle Zod validation errors
zodErrors = error.errors;
errorOldPassword =
zodErrors?.find((err) => err.path[0] === "oldPassword")?.message ??
"";
errorPassword =
zodErrors?.find((err) => err.path[0] === "password")?.message ?? "";
errorPasswordConfirm =
zodErrors?.find((err) => err.path[0] === "passwordConfirm")
?.message ?? "";
return async ({ result, update }) => {
if (result.success) {
toast.success("Password updated!", {
style: "border-radius: 200px; background: #2A2E39; color: #fff;",
});
} else if (result.error || result.errors) {
toast.error("Invalid credentials", {
style:
"border-radius: 5px; background: #fff; color: #000; border-color: #4B5563; font-size: 15px;",
});
} else {
// Handle other errors
console.error("Unexpected error during registration:", error);
toast.error("An unexpected error occurred", {
style:
"border-radius: 5px; background: #fff; color: #000; border-color: #4B5563; font-size: 15px;",
});
}
}
loading = false;
}
await update();
loading = false;
};
};
</script>
<SEO title="Update Password" description="Update your account password" />
<section
class="w-full max-w-3xl sm:max-w-[1400px] overflow-hidden min-h-screen pb-20 pt-5 px-4 lg:px-3"
class="flex flex-col items-center min-h-screen w-full max-w-3xl m-auto"
>
<div class="w-full overflow-hidden m-auto mt-5">
<div class="sm:p-0 flex justify-center w-full m-auto overflow-hidden">
@ -77,43 +39,49 @@
>
<main class="w-full">
<form
on:submit={updatePassword}
action="?/updatePassword"
method="POST"
use:enhance={submitUpdatePassword}
class="flex flex-col space-y-2 w-full max-w-lg m-auto"
>
<h1
class="mb-1 text-white text-2xl sm:text-3xl font-bold mb-6 text-center"
>
Set a new password
Reset Your Password
</h1>
<Input
id="oldPassword"
name="oldPassword"
label="Old Password"
type="password"
required
errors={errorOldPassword}
errors={form?.errors?.errorOldPassword}
/>
<Input
id="password"
name="password"
label="New Password"
type="password"
required
errors={errorPassword}
errors={form?.errors?.errorPassword}
/>
<Input
id="passwordConfirm"
name="passwordConfirm"
label="Confirm New Password"
type="password"
required
errors={errorPasswordConfirm}
errors={form?.errors?.errorPasswordConfirm}
/>
<div class="w-full max-w-lg pt-3">
<button
type="submit"
class="btn bg-[#fff] text-black font-semibold sm:hover:bg-gray-300 w-full max-w-lg normal-case text-md"
>Update Password</button
class="py-2.5 cursor-pointer rounded bg-[#fff] text-black font-semibold sm:hover:bg-gray-300 w-full max-w-lg normal-case text-md"
>
{loading ? "Updating..." : "Update Password"}
</button>
</div>
</form>
</main>