update
This commit is contained in:
parent
94298ec33f
commit
946d144cc9
@ -3,6 +3,22 @@ import { redirect } from "@sveltejs/kit";
|
|||||||
export const load = async ({ locals }) => {
|
export const load = async ({ locals }) => {
|
||||||
const { pb } = locals;
|
const { pb } = locals;
|
||||||
if (pb.authStore.isValid) {
|
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");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@ -1,29 +1,51 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toast } from "svelte-sonner";
|
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";
|
import SEO from "$lib/components/SEO.svelte";
|
||||||
|
|
||||||
|
let email: string = "";
|
||||||
let loading = false;
|
let loading = false;
|
||||||
let email: String;
|
let isClicked = false;
|
||||||
|
|
||||||
async function resetPassword(event) {
|
const submitReset = () => {
|
||||||
event.preventDefault();
|
loading = true;
|
||||||
try {
|
return async ({ result, update }) => {
|
||||||
await pb.collection("users").requestPasswordReset(email);
|
switch (result.type) {
|
||||||
toast.success("Password resetted. Check your emails!", {
|
case "success":
|
||||||
style:
|
toast.success("Password resetted. Check your emails!", {
|
||||||
"border-radius: 5px; background: #fff; color: #000; border-color: #4B5563; font-size: 15px;",
|
style:
|
||||||
});
|
"border-radius: 5px; background: #fff; color: #000; border-color: #4B5563; font-size: 15px;",
|
||||||
goto("/login");
|
});
|
||||||
} catch (err) {
|
await update();
|
||||||
toast.error(err, {
|
break;
|
||||||
style:
|
case "redirect":
|
||||||
"border-radius: 5px; background: #fff; color: #000; border-color: #4B5563; font-size: 15px;",
|
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>
|
</script>
|
||||||
|
|
||||||
<SEO
|
<SEO
|
||||||
@ -41,23 +63,39 @@
|
|||||||
We'll send you an email with a link to reset your password.
|
We'll send you an email with a link to reset your password.
|
||||||
</p>
|
</p>
|
||||||
<form
|
<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"
|
class="flex flex-col items-center space-y-2 w-5/6 sm:w-full pt-4"
|
||||||
>
|
>
|
||||||
<input
|
<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"
|
type="email"
|
||||||
required={true}
|
required
|
||||||
bind:value={email}
|
bind:value={email}
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
/>
|
/>
|
||||||
<div class="w-full max-w-lg pt-2">
|
<div class="w-full max-w-lg">
|
||||||
<button
|
<div class="w-full max-w-lg pt-2 m-auto pb-5">
|
||||||
type="submit"
|
{#if !loading && !isClicked}
|
||||||
class="py-2.5 font-semibold rounded bg-white text-black w-full"
|
<button
|
||||||
>
|
type="submit"
|
||||||
Request Password Reset
|
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]"
|
||||||
</button>
|
>
|
||||||
|
<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>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,8 +1,51 @@
|
|||||||
import { redirect, error } from "@sveltejs/kit";
|
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 }) => {
|
export const load = async ({ locals }) => {
|
||||||
const { pb, user } = locals;
|
const { pb } = locals;
|
||||||
if (!pb.authStore.isValid) {
|
if (!pb.authStore.isValid) {
|
||||||
redirect(303, "/login");
|
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" });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|||||||
@ -1,74 +1,36 @@
|
|||||||
<script ts="lang">
|
<script lang="ts">
|
||||||
import { pb } from "$lib/pocketbase";
|
import { enhance } from "$app/forms";
|
||||||
import { toast } from "svelte-sonner";
|
import { toast } from "svelte-sonner";
|
||||||
|
|
||||||
import Input from "$lib/components/Input.svelte";
|
import Input from "$lib/components/Input.svelte";
|
||||||
import { updatePasswordSchema } from "$lib/schemas";
|
import SEO from "$lib/components/SEO.svelte";
|
||||||
import { goto } from "$app/navigation";
|
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
let zodErrors = [];
|
|
||||||
export let data;
|
export let data;
|
||||||
|
export let form;
|
||||||
let errorOldPassword = "";
|
|
||||||
let errorPassword = "";
|
|
||||||
let errorPasswordConfirm = "";
|
|
||||||
let loading = false;
|
let loading = false;
|
||||||
async function updatePassword(event) {
|
|
||||||
|
const submitUpdatePassword = () => {
|
||||||
loading = true;
|
loading = true;
|
||||||
event.preventDefault(); // prevent the default form submission behavior
|
return async ({ result, update }) => {
|
||||||
errorOldPassword = "";
|
if (result.success) {
|
||||||
errorPassword = "";
|
toast.success("Password updated!", {
|
||||||
errorPasswordConfirm = "";
|
style: "border-radius: 200px; background: #2A2E39; color: #fff;",
|
||||||
|
});
|
||||||
const formData = new FormData(event.target); // create a FormData object from the form
|
} else if (result.error || result.errors) {
|
||||||
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 ?? "";
|
|
||||||
|
|
||||||
toast.error("Invalid credentials", {
|
toast.error("Invalid credentials", {
|
||||||
style:
|
style:
|
||||||
"border-radius: 5px; background: #fff; color: #000; border-color: #4B5563; font-size: 15px;",
|
"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;",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
await update();
|
||||||
loading = false;
|
loading = false;
|
||||||
}
|
};
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<SEO title="Update Password" description="Update your account password" />
|
||||||
|
|
||||||
<section
|
<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="w-full overflow-hidden m-auto mt-5">
|
||||||
<div class="sm:p-0 flex justify-center w-full m-auto overflow-hidden">
|
<div class="sm:p-0 flex justify-center w-full m-auto overflow-hidden">
|
||||||
@ -77,43 +39,49 @@
|
|||||||
>
|
>
|
||||||
<main class="w-full">
|
<main class="w-full">
|
||||||
<form
|
<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"
|
class="flex flex-col space-y-2 w-full max-w-lg m-auto"
|
||||||
>
|
>
|
||||||
<h1
|
<h1
|
||||||
class="mb-1 text-white text-2xl sm:text-3xl font-bold mb-6 text-center"
|
class="mb-1 text-white text-2xl sm:text-3xl font-bold mb-6 text-center"
|
||||||
>
|
>
|
||||||
Set a new password
|
Reset Your Password
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
id="oldPassword"
|
id="oldPassword"
|
||||||
|
name="oldPassword"
|
||||||
label="Old Password"
|
label="Old Password"
|
||||||
type="password"
|
type="password"
|
||||||
required
|
required
|
||||||
errors={errorOldPassword}
|
errors={form?.errors?.errorOldPassword}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
id="password"
|
id="password"
|
||||||
|
name="password"
|
||||||
label="New Password"
|
label="New Password"
|
||||||
type="password"
|
type="password"
|
||||||
required
|
required
|
||||||
errors={errorPassword}
|
errors={form?.errors?.errorPassword}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
id="passwordConfirm"
|
id="passwordConfirm"
|
||||||
|
name="passwordConfirm"
|
||||||
label="Confirm New Password"
|
label="Confirm New Password"
|
||||||
type="password"
|
type="password"
|
||||||
required
|
required
|
||||||
errors={errorPasswordConfirm}
|
errors={form?.errors?.errorPasswordConfirm}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="w-full max-w-lg pt-3">
|
<div class="w-full max-w-lg pt-3">
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="btn bg-[#fff] text-black font-semibold sm:hover:bg-gray-300 w-full max-w-lg normal-case text-md"
|
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"
|
||||||
>Update Password</button
|
|
||||||
>
|
>
|
||||||
|
{loading ? "Updating..." : "Update Password"}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user