From 5880b806760780d7337f0f6f219241a5dd6a7dcc Mon Sep 17 00:00:00 2001 From: paolosantarsiero Date: Fri, 27 Dec 2024 03:24:35 +0100 Subject: [PATCH] feat: add profile and orders customer --- app/[page]/page.tsx | 3 +- app/api/auth/[...nextauth]/route.ts | 70 +- app/api/cart/route.ts | 12 +- app/checkout/page.tsx | 2 +- app/collection/[name]/page.tsx | 8 +- app/layout.tsx | 9 +- app/login/page.tsx | 71 + app/page.tsx | 4 +- app/product/[name]/page.tsx | 19 +- app/profile/orders/[id]/page.tsx | 85 + app/profile/orders/page.tsx | 85 + app/profile/page.tsx | 156 ++ app/search/[collection]/opengraph-image.tsx | 1 - app/search/layout.tsx | 3 +- app/search/page.tsx | 2 +- app/sitemap.ts | 1 - components/button/logout.tsx | 14 + components/carousel.tsx | 4 +- components/cart/add-to-cart.tsx | 16 +- components/cart/cart-context.tsx | 20 +- components/cart/delete-item-button.tsx | 12 +- components/cart/edit-item-quantity-button.tsx | 17 +- components/cart/modal.tsx | 133 +- components/grid/three-items.tsx | 3 +- components/icons/UserIcon.tsx | 16 + components/layout/footer.tsx | 5 +- components/layout/navbar/index.tsx | 7 +- components/layout/product-grid-items.tsx | 2 +- components/layout/search/collections.tsx | 6 +- components/login/modal.tsx | 133 -- components/next-session-provider.tsx | 6 +- components/price.tsx | 2 +- components/product/gallery.tsx | 4 +- components/product/product-description.tsx | 5 +- lib/woocomerce/models/billing.ts | 24 +- lib/woocomerce/models/cart.ts | 389 +++-- lib/woocomerce/models/client.ts | 51 +- lib/woocomerce/models/clientOptions.ts | 48 +- lib/woocomerce/models/coupon.ts | 2 +- lib/woocomerce/models/item.ts | 34 +- lib/woocomerce/models/link.ts | 20 +- lib/woocomerce/models/orders.ts | 24 +- lib/woocomerce/models/product.ts | 11 +- lib/woocomerce/models/refund.ts | 60 +- lib/woocomerce/models/shipping.ts | 2 +- lib/woocomerce/models/taxes.ts | 2 +- lib/woocomerce/storeApi.ts | 18 +- lib/woocomerce/woocommerce.ts | 22 +- next.config.ts | 4 +- pnpm-lock.yaml | 1388 ++++++++++++----- tsconfig.json | 9 +- types/next-auth.d.ts | 9 +- 52 files changed, 2019 insertions(+), 1034 deletions(-) create mode 100644 app/login/page.tsx create mode 100644 app/profile/orders/[id]/page.tsx create mode 100644 app/profile/orders/page.tsx create mode 100644 app/profile/page.tsx create mode 100644 components/button/logout.tsx create mode 100644 components/icons/UserIcon.tsx delete mode 100644 components/login/modal.tsx diff --git a/app/[page]/page.tsx b/app/[page]/page.tsx index a7e8aac6e..3341e19ad 100644 --- a/app/[page]/page.tsx +++ b/app/[page]/page.tsx @@ -7,7 +7,6 @@ export async function generateMetadata(props: { }): Promise { const params = await props.params; - return { title: '', description: '', @@ -21,7 +20,7 @@ export async function generateMetadata(props: { export default async function Page(props: { params: Promise<{ page: string }> }) { const params = await props.params; - + return ( <>

{''}

diff --git a/app/api/auth/[...nextauth]/route.ts b/app/api/auth/[...nextauth]/route.ts index c67dad098..b01a0e33c 100644 --- a/app/api/auth/[...nextauth]/route.ts +++ b/app/api/auth/[...nextauth]/route.ts @@ -1,50 +1,50 @@ -import { woocommerce } from "lib/woocomerce/woocommerce"; -import { NextAuthOptions, Session, User } from "next-auth"; -import { JWT } from "next-auth/jwt"; -import NextAuth from "next-auth/next"; +import { woocommerce } from 'lib/woocomerce/woocommerce'; +import { NextAuthOptions, Session, User } from 'next-auth'; +import { JWT } from 'next-auth/jwt'; +import NextAuth from 'next-auth/next'; import CredentialsProvider from 'next-auth/providers/credentials'; export const authOptions = { secret: process.env.NEXTAUTH_SECRET, session: { - strategy: "jwt", // Use JWT for session handling + strategy: 'jwt' // Use JWT for session handling }, providers: [ CredentialsProvider({ - name: 'woocommerce', - credentials: { - username: { label: 'Username', type: 'text', placeholder: 'Username' }, - password: { label: 'Password', type: 'password', placeholder: 'Password' }, + name: 'woocommerce', + credentials: { + username: { label: 'Username', type: 'text', placeholder: 'Username' }, + password: { label: 'Password', type: 'password', placeholder: 'Password' } }, - async authorize(credentials, req) { - if (!credentials?.username || !credentials?.password) { - return null; - } - const user = await woocommerce.login(credentials.username, credentials.password); - // If no error and we have user data, return it - if (user) { - return user - } - // Return null if user data could not be retrieved - return null + async authorize(credentials, req) { + if (!credentials?.username || !credentials?.password) { + return null; } - }), - ], - callbacks: { - async jwt({ token, user }: { token: JWT, user: User }) { + const user = await woocommerce.login(credentials.username, credentials.password); + // If no error and we have user data, return it if (user) { - console.debug('Set token user', user); - token.user = user; + return user; } - return token; - }, - async session({ session, token }: {session: Session, token: JWT}) { - console.debug('Set session token', token.user); - session.user = token.user; - return session; - }, - }, + // Return null if user data could not be retrieved + return null; + } + }) + ], + callbacks: { + async jwt({ token, user }: { token: JWT; user: User }) { + if (user) { + console.debug('Set token user', user); + token.user = user; + } + return token; + }, + async session({ session, token }: { session: Session; token: JWT }) { + console.debug('Set session token', token.user); + session.user = token.user; + return session; + } + } } satisfies NextAuthOptions; -const handler = NextAuth(authOptions) +const handler = NextAuth(authOptions); export { handler as GET, handler as POST }; diff --git a/app/api/cart/route.ts b/app/api/cart/route.ts index 81580c68f..ce41d9faa 100644 --- a/app/api/cart/route.ts +++ b/app/api/cart/route.ts @@ -9,7 +9,7 @@ export async function GET(req: NextRequest) { if (session?.user?.token) { storeApi._setAuthorizationToken(session.user.token); } else { - storeApi._setAuthorizationToken(''); + storeApi._setAuthorizationToken(''); } const cart = await storeApi.getCart(); return NextResponse.json(cart, { status: 200 }); @@ -32,11 +32,11 @@ export async function PUT(req: NextRequest) { try { const { key, quantity } = await req.json(); if (quantity > 0) { - const cart = await storeApi.updateItem({ key, quantity }); - return NextResponse.json(cart, { status: 200 }); + const cart = await storeApi.updateItem({ key, quantity }); + return NextResponse.json(cart, { status: 200 }); } else { - const cart = await storeApi.removeFromCart({ key }); - return NextResponse.json(cart, { status: 200 }); + const cart = await storeApi.removeFromCart({ key }); + return NextResponse.json(cart, { status: 200 }); } } catch (error) { return NextResponse.json({ error: 'Failed to update cart item' }, { status: 500 }); @@ -51,4 +51,4 @@ export async function DELETE(req: NextRequest) { } catch (error) { return NextResponse.json({ error: 'Failed to remove item from cart' }, { status: 500 }); } -} \ No newline at end of file +} diff --git a/app/checkout/page.tsx b/app/checkout/page.tsx index 43fa7df81..599e897b5 100644 --- a/app/checkout/page.tsx +++ b/app/checkout/page.tsx @@ -6,4 +6,4 @@ export default async function CheckoutPage(props: { params: Promise<{ id: number

Checkout

); -} \ No newline at end of file +} diff --git a/app/collection/[name]/page.tsx b/app/collection/[name]/page.tsx index 5f27debc5..b36a4ffe9 100644 --- a/app/collection/[name]/page.tsx +++ b/app/collection/[name]/page.tsx @@ -1,18 +1,16 @@ - import { ThreeItemGridItem } from 'components/grid/three-items'; import { Product } from 'lib/woocomerce/models/product'; import { woocommerce } from 'lib/woocomerce/woocommerce'; - export default async function ProductPage(props: { params: Promise<{ name: string }> }) { const params = await props.params; - const products: Product[] = (await (woocommerce.get('products', { category: params.name }))); + const products: Product[] = await woocommerce.get('products', { category: params.name }); return (
- {products.map((product, index) => ( + {products.map((product, index) => ( ))}
); -} \ No newline at end of file +} diff --git a/app/layout.tsx b/app/layout.tsx index 469859939..a61c0153e 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,4 +1,3 @@ - import { CartProvider } from 'components/cart/cart-context'; import { Navbar } from 'components/layout/navbar'; import { NextAuthProvider } from 'components/next-session-provider'; @@ -39,20 +38,20 @@ export const metadata = { export default async function RootLayout({ children }: { children: ReactNode }) { const cart = await storeApi.getCart(); - + return ( - - + +
{children}
-
+ ); diff --git a/app/login/page.tsx b/app/login/page.tsx new file mode 100644 index 000000000..4dffb5264 --- /dev/null +++ b/app/login/page.tsx @@ -0,0 +1,71 @@ +'use client'; + +import { signIn } from 'next-auth/react'; +import { useRouter } from 'next/navigation'; +import { useState } from 'react'; + +export default function LoginPage() { + const [username, setUsername] = useState(''); + const [password, setPassword] = useState(''); + const { replace } = useRouter(); + + const handleLogin = async (event: React.FormEvent) => { + event.preventDefault(); + try { + await signIn('credentials', { username, password, redirect: false }); + replace('/'); + } catch (error) { + console.error(error); + } + }; + + return ( +
+

Login

+
+
+
+ + setUsername(e.target.value)} + className="mt-1 block w-full rounded-md border-gray-300 p-3 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-lg" + required + /> +
+
+ + setPassword(e.target.value)} + className="mt-1 block w-full rounded-md border-gray-300 p-3 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-lg" + required + /> +
+
+ +
+
+
+
+ ); +} diff --git a/app/page.tsx b/app/page.tsx index 57cec6345..0fad0ac28 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -9,10 +9,10 @@ export const metadata = { } }; -export default async function HomePage() { +export default async function HomePage() { return ( <> - +