Add React editor project

This commit is contained in:
Rami Bitar
2026-08-09 16:00:10 -04:00
parent 909d99251a
commit 63ecc5e284
212 changed files with 20655 additions and 11571 deletions
+30
View File
@@ -0,0 +1,30 @@
import {
activateAccount,
toCustomerGid,
customerErrorMessage,
} from '@/services/shopify/customer';
import { setSessionToken } from '@/services/shopify/session';
export async function POST(req: Request) {
const { id, activationToken, password } = await req.json();
if (!id || !activationToken || !password) {
return Response.json(
{ error: 'This activation link is incomplete.' },
{ status: 400 }
);
}
const { token, errors } = await activateAccount(
toCustomerGid(id),
activationToken,
password
);
if (!token) {
return Response.json({ error: customerErrorMessage(errors) }, { status: 400 });
}
await setSessionToken(token.accessToken, token.expiresAt);
return Response.json({ ok: true });
}
+31
View File
@@ -0,0 +1,31 @@
import { login, customerErrorMessage } from '@/services/shopify/customer';
import { setSessionToken } from '@/services/shopify/session';
export async function POST(req: Request) {
const { email, password } = await req.json();
if (!email || !password) {
return Response.json(
{ error: 'Enter your email and password.' },
{ status: 400 }
);
}
const { token, errors } = await login(email, password);
if (!token) {
// Shopify distinguishes wrong-password from unknown-email; collapse both so
// the form can't be used to enumerate accounts.
return Response.json(
{
error: errors.length
? 'Incorrect email or password.'
: customerErrorMessage(errors),
},
{ status: 401 }
);
}
await setSessionToken(token.accessToken, token.expiresAt);
return Response.json({ ok: true });
}
+10
View File
@@ -0,0 +1,10 @@
import { logout } from '@/services/shopify/customer';
import { getSessionToken, clearSessionToken } from '@/services/shopify/session';
export async function POST() {
const token = await getSessionToken();
if (token) await logout(token);
await clearSessionToken();
return Response.json({ ok: true });
}
+19
View File
@@ -0,0 +1,19 @@
import { getSessionToken } from '@/services/shopify/session';
import { getCustomer } from '@/services/shopify/customer';
// Minimal session probe for the header menu — never returns the access token.
export async function GET() {
const token = await getSessionToken();
if (!token) return Response.json({ customer: null });
const customer = await getCustomer(token, 0);
if (!customer) return Response.json({ customer: null });
return Response.json({
customer: {
displayName: customer.displayName,
email: customer.email,
firstName: customer.firstName,
},
});
}
+26
View File
@@ -0,0 +1,26 @@
import { getSessionToken } from '@/services/shopify/session';
import { getCustomer } from '@/services/shopify/customer';
/**
* Full customer record including orders, for the client-rendered order-history
* block. `/api/account/me` stays the lightweight session probe the header uses
* — it asks for zero orders — so the two don't fight over payload size.
*
* The access token never leaves the server: it is read from the session cookie
* here and only the resolved customer is returned.
*/
export async function GET(request: Request) {
const token = await getSessionToken();
if (!token) return Response.json({ customer: null }, { status: 401 });
const { searchParams } = new URL(request.url);
const parsed = Number(searchParams.get('orders'));
const orderCount = Number.isFinite(parsed)
? Math.min(Math.max(Math.trunc(parsed), 1), 50)
: 20;
const customer = await getCustomer(token, orderCount);
if (!customer) return Response.json({ customer: null }, { status: 401 });
return Response.json({ customer });
}
+10
View File
@@ -0,0 +1,10 @@
import { recoverPassword } from '@/services/shopify/customer';
export async function POST(req: Request) {
const { email } = await req.json();
if (email) await recoverPassword(email);
// Always the same response, so the form can't reveal who has an account.
return Response.json({ ok: true });
}
+39
View File
@@ -0,0 +1,39 @@
import {
createCustomer,
login,
customerErrorMessage,
} from '@/services/shopify/customer';
import { setSessionToken } from '@/services/shopify/session';
export async function POST(req: Request) {
const { email, password, firstName, lastName } = await req.json();
if (!email || !password) {
return Response.json(
{ error: 'Enter your email and password.' },
{ status: 400 }
);
}
const { errors } = await createCustomer({
email,
password,
firstName,
lastName,
});
if (errors.length) {
return Response.json({ error: customerErrorMessage(errors) }, { status: 400 });
}
// Sign the new customer straight in. Accounts needing email confirmation
// won't return a token yet, which is not an error.
const { token } = await login(email, password);
if (token) {
await setSessionToken(token.accessToken, token.expiresAt);
return Response.json({ ok: true, signedIn: true });
}
return Response.json({ ok: true, signedIn: false });
}
+27
View File
@@ -0,0 +1,27 @@
import {
resetPassword,
toCustomerGid,
customerErrorMessage,
} from '@/services/shopify/customer';
import { setSessionToken } from '@/services/shopify/session';
export async function POST(req: Request) {
const { id, resetToken, password } = await req.json();
if (!id || !resetToken || !password) {
return Response.json({ error: 'This reset link is incomplete.' }, { status: 400 });
}
const { token, errors } = await resetPassword(
toCustomerGid(id),
resetToken,
password
);
if (!token) {
return Response.json({ error: customerErrorMessage(errors) }, { status: 400 });
}
await setSessionToken(token.accessToken, token.expiresAt);
return Response.json({ ok: true });
}