Add password reset, order confirmation email with editable templates, and fix missing account entry points
Password reset uses Payload's built-in forgot/reset-password flow, customized to link to this app instead of the Payload admin. Order confirmation email and the password-reset email's wording both come from a new Payload email-templates collection, editable without a deploy and previewable via Live Preview at /email-preview/[type] (same mechanism as Posts/LegalPages/Testimonials, sample data instead of a real document). Also: order numbers get a random suffix (prevents guessing, motivated by a considered-and-deferred guest order-lookup feature); the discount code field only shows in the cart when a code is actually active (codes now apply via a ?code= link instead of manual entry); and three navigation gaps found while testing — no reachable login link with an empty cart, no logout link anywhere, no way back from profile to order history. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -90,6 +90,52 @@ export async function loginCustomer(input: { email: string; password: string }):
|
||||
};
|
||||
}
|
||||
|
||||
// Always resolves — never throws or returns a distinguishable "email not
|
||||
// found" shape. Mirrors Payload's own forgot-password operation, which
|
||||
// fails silently on a non-existent email specifically to avoid leaking
|
||||
// which addresses are registered (see auth/operations/forgotPassword.js);
|
||||
// the caller (app/api/account/forgot-password/route.ts) must preserve that
|
||||
// by always responding the same way regardless of this call's outcome.
|
||||
export async function requestPasswordReset(email: string): Promise<void> {
|
||||
await fetch(`${PAYLOAD_URL}/api/customers/forgot-password`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ email }),
|
||||
}).catch(() => {
|
||||
// Best-effort — same "never reveal anything" reasoning as above.
|
||||
});
|
||||
}
|
||||
|
||||
// Payload's reset-password operation logs the customer in on success (see
|
||||
// auth/operations/resetPassword.js) and returns the same {token, user}
|
||||
// shape as login — reused here so the frontend route can set the session
|
||||
// cookie immediately, no separate login step needed after a reset.
|
||||
export async function resetPassword(token: string, newPassword: string): Promise<AuthResult> {
|
||||
const res = await fetch(`${PAYLOAD_URL}/api/customers/reset-password`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ token, password: newPassword }),
|
||||
});
|
||||
if (!res.ok) return { ok: false, reason: "Der Link ist ungültig oder abgelaufen." };
|
||||
|
||||
const data: {
|
||||
token: string;
|
||||
user: { id: number; customerNumber: string; firstName: string; lastName: string; email: string; emailVerified: boolean };
|
||||
} = await res.json();
|
||||
return {
|
||||
ok: true,
|
||||
token: data.token,
|
||||
customer: {
|
||||
id: data.user.id,
|
||||
customerNumber: data.user.customerNumber,
|
||||
firstName: data.user.firstName,
|
||||
lastName: data.user.lastName,
|
||||
email: data.user.email,
|
||||
emailVerified: data.user.emailVerified,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export async function getCustomerFromToken(token: string): Promise<CustomerSummary | null> {
|
||||
const res = await fetch(`${PAYLOAD_URL}/api/customers/me`, {
|
||||
headers: { Authorization: `JWT ${token}` },
|
||||
|
||||
Reference in New Issue
Block a user