Beginning of ecommerce
This commit is contained in:
@ -1,7 +1,13 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
output: 'export',
|
images: {
|
||||||
images: { unoptimized: true },
|
remotePatterns: [
|
||||||
|
{
|
||||||
|
protocol: 'https',
|
||||||
|
hostname: '**.amazonaws.com',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nextConfig;
|
export default nextConfig;
|
||||||
|
|||||||
@ -9,6 +9,9 @@
|
|||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@medusajs/medusa": "^1.20.10",
|
||||||
|
"@tanstack/react-query": "4.22",
|
||||||
|
"medusa-react": "^9.0.18",
|
||||||
"next": "14.2.13",
|
"next": "14.2.13",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.cls-1, .cls-2 {
|
.cls-1, .cls-2 {
|
||||||
fill: current;
|
fill: black;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</defs>
|
</defs>
|
||||||
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
52
public/images/logo-puce-red.svg
Normal file
52
public/images/logo-puce-red.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 22 KiB |
52
public/images/logo-white.svg
Normal file
52
public/images/logo-white.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 22 KiB |
@ -8,8 +8,8 @@ import italyPic from '/public/images/about-us/06-italy.jpg';
|
|||||||
|
|
||||||
export default function AboutUsPage() {
|
export default function AboutUsPage() {
|
||||||
return (
|
return (
|
||||||
<div className='overflow-x-hidden bg-white'>
|
<div className='overflow-x-hidden bg-white pt-28'>
|
||||||
<section className='flex flex-col items-center pt-20'>
|
<section className='flex flex-col items-center'>
|
||||||
{/* Left Column - Text with Header */}
|
{/* Left Column - Text with Header */}
|
||||||
<div className='w-full text-8xl font-normal text-center font-montera'>
|
<div className='w-full text-8xl font-normal text-center font-montera'>
|
||||||
Welcome to the World of Mozimo Magic
|
Welcome to the World of Mozimo Magic
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import './globals.css';
|
import '../globals.css';
|
||||||
// import './globalicons.css';
|
// import './globalicons.css';
|
||||||
|
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
87
src/app/(storefront)/cart/page.tsx.exclude
Normal file
87
src/app/(storefront)/cart/page.tsx.exclude
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useCart, useUpdateLineItem, useDeleteLineItem } from 'medusa-react';
|
||||||
|
import { useRouter } from 'next/navigation';
|
||||||
|
|
||||||
|
export default function CartPage() {
|
||||||
|
const { cart } = useCart();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
// Ensure cart is loaded
|
||||||
|
if (!cart?.id) {
|
||||||
|
return <p>Loading cart...</p>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hook for updating a cart line item
|
||||||
|
const {
|
||||||
|
mutate: updateLineItem,
|
||||||
|
isLoading: isUpdating,
|
||||||
|
error: updateError,
|
||||||
|
} = useUpdateLineItem(cart.id);
|
||||||
|
// Hook for deleting a cart line item
|
||||||
|
const {
|
||||||
|
mutate: deleteLineItem,
|
||||||
|
isLoading: isDeleting,
|
||||||
|
error: deleteError,
|
||||||
|
} = useDeleteLineItem(cart?.id);
|
||||||
|
|
||||||
|
if (!cart) return <p>Loading cart...</p>;
|
||||||
|
|
||||||
|
const handleUpdateItem = (lineId: string, quantity: number) => {
|
||||||
|
updateLineItem(
|
||||||
|
{ lineId, quantity },
|
||||||
|
{
|
||||||
|
onSuccess: () => {
|
||||||
|
// Optionally refetch cart or show a success message
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRemoveItem = (lineId: string) => {
|
||||||
|
deleteLineItem(
|
||||||
|
{ lineId },
|
||||||
|
{
|
||||||
|
onSuccess: () => {
|
||||||
|
// Optionally refetch cart or show a success message
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const proceedToCheckout = () => {
|
||||||
|
router.push('/checkout');
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Your Cart</h1>
|
||||||
|
{cart.items?.length ? (
|
||||||
|
cart.items.map((item) => (
|
||||||
|
<div key={item.id}>
|
||||||
|
<h2>{item.title}</h2>
|
||||||
|
<p>Quantity: {item.quantity}</p>
|
||||||
|
<button
|
||||||
|
onClick={() => handleUpdateItem(item.id, item.quantity + 1)}
|
||||||
|
disabled={isUpdating}
|
||||||
|
>
|
||||||
|
Increase Quantity
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => handleRemoveItem(item.id)}
|
||||||
|
disabled={isDeleting}
|
||||||
|
>
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
|
{updateError && <p>Error updating item: {updateError.message}</p>}
|
||||||
|
{deleteError && <p>Error removing item: {deleteError.message}</p>}
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<p>Your cart is empty.</p>
|
||||||
|
)}
|
||||||
|
<p>Total: {cart.total ? `$${(cart.total / 100).toFixed(2)}` : '$0.00'}</p>
|
||||||
|
<button onClick={proceedToCheckout}>Proceed to Checkout</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
21
src/app/(storefront)/layout.tsx
Normal file
21
src/app/(storefront)/layout.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import '../globals.css';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
import { Providers } from '../providers';
|
||||||
|
import { Footer } from '@/components/footer';
|
||||||
|
import { Navbar } from '@/components/navbar';
|
||||||
|
|
||||||
|
interface RootLayoutProps {
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function RootLayout({ children }: RootLayoutProps) {
|
||||||
|
return (
|
||||||
|
<html lang='en'>
|
||||||
|
<body>
|
||||||
|
<Navbar />
|
||||||
|
<Providers>{children}</Providers>
|
||||||
|
<Footer />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
79
src/app/(storefront)/products/[handle]/ProductDetails.tsx
Normal file
79
src/app/(storefront)/products/[handle]/ProductDetails.tsx
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { FC } from 'react';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { getProductByHandle } from '@/lib/product-by-handle';
|
||||||
|
import { PricedProduct } from '@medusajs/medusa/dist/types/pricing';
|
||||||
|
|
||||||
|
interface ProductDetailsProps {
|
||||||
|
handle: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProductDetails: FC<ProductDetailsProps> = ({ handle }) => {
|
||||||
|
const [product, setProduct] = useState<PricedProduct | null>(null);
|
||||||
|
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||||
|
const [error, setError] = useState<unknown>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchProduct = async () => {
|
||||||
|
try {
|
||||||
|
const { product } = await getProductByHandle(handle);
|
||||||
|
console.log(product);
|
||||||
|
if (!product) {
|
||||||
|
setProduct(null);
|
||||||
|
} else {
|
||||||
|
setProduct(product);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
setError(err);
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchProduct();
|
||||||
|
}, [handle]);
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return <div>Loading...</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return <div>Something went wrong: {error.message}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!product) {
|
||||||
|
return <div>Product not found.</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='container mx-auto p-4'>
|
||||||
|
<h1 className='text-4xl font-bold'>{product.title}</h1>
|
||||||
|
<div className='flex flex-col md:flex-row gap-6 mt-4'>
|
||||||
|
{/* Product Images */}
|
||||||
|
<div className='flex-1'>
|
||||||
|
{product?.images?.length > 0 && (
|
||||||
|
<img
|
||||||
|
src={product.images[0].url}
|
||||||
|
alt={product.title}
|
||||||
|
className='rounded-lg shadow-lg'
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Product Info */}
|
||||||
|
<div className='flex-1'>
|
||||||
|
<p className='text-lg font-semibold text-gray-500'>
|
||||||
|
Price: ${product.variants[0].prices[0].amount / 100}
|
||||||
|
</p>
|
||||||
|
<p className='text-lg text-gray-700'>{product.description}</p>
|
||||||
|
<button className='mt-4 px-6 py-2 bg-black text-white rounded hover:bg-gray-700'>
|
||||||
|
Add to Cart
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProductDetails;
|
||||||
37
src/app/(storefront)/products/[handle]/page.tsx
Normal file
37
src/app/(storefront)/products/[handle]/page.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { FC } from 'react';
|
||||||
|
import { getProductsList } from '@/lib/product';
|
||||||
|
import ProductDetails from './ProductDetails';
|
||||||
|
|
||||||
|
interface ProductPageProps {
|
||||||
|
params: {
|
||||||
|
handle: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateStaticParams() {
|
||||||
|
// Fetch the list of products
|
||||||
|
const products = await getProductsList({}).then(
|
||||||
|
({ response }) => response.products,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!products) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate static params based on product handles
|
||||||
|
const staticParams = products.map((product) => ({
|
||||||
|
handle: product.handle,
|
||||||
|
}));
|
||||||
|
return staticParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProductPage: FC<ProductPageProps> = ({ params }) => {
|
||||||
|
const { handle } = params; // Extract the handle from the params
|
||||||
|
|
||||||
|
return (
|
||||||
|
// Render the client component and pass necessary props
|
||||||
|
<ProductDetails handle={handle} />
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProductPage;
|
||||||
40
src/app/(storefront)/products/page.tsx
Normal file
40
src/app/(storefront)/products/page.tsx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useProducts } from 'medusa-react';
|
||||||
|
import Image from 'next/image';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default function ProductsPage() {
|
||||||
|
const { products, isLoading, error } = useProducts();
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return <div>Loading...</div>;
|
||||||
|
}
|
||||||
|
if (error) return <p>Error: {error.message}</p>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='container mx-auto py-12'>
|
||||||
|
<h1 className='text-3xl font-bold mb-8'>Handbags Collection</h1>
|
||||||
|
<div className='grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-8'>
|
||||||
|
{products?.map((product) => (
|
||||||
|
<Link key={product.id} href={`/products/${product.handle}`}>
|
||||||
|
<div className='border border-gray-200 p-4 rounded-lg shadow-lg'>
|
||||||
|
<Image
|
||||||
|
src={product.thumbnail}
|
||||||
|
alt={product.title}
|
||||||
|
width={300}
|
||||||
|
height={300}
|
||||||
|
className='object-cover rounded-md'
|
||||||
|
/>
|
||||||
|
<h2 className='mt-4 text-lg font-semibold'>{product.title}</h2>
|
||||||
|
<p className='mt-2 text-gray-600'>{product.description}</p>
|
||||||
|
<p className='mt-2 text-lg font-bold text-gray-900'>
|
||||||
|
${product.variants[0]?.prices[0].amount / 100}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
23
src/app/providers.tsx
Normal file
23
src/app/providers.tsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// src/app/providers.tsx
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import { ReactNode, useState } from 'react';
|
||||||
|
import { MedusaProvider, CartProvider } from 'medusa-react';
|
||||||
|
import { QueryClient } from '@tanstack/react-query';
|
||||||
|
|
||||||
|
interface ProvidersProps {
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Providers({ children }: ProvidersProps) {
|
||||||
|
const [queryClient] = useState(() => new QueryClient());
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MedusaProvider
|
||||||
|
baseUrl='http://localhost:9000' // Replace with your Medusa backend URL
|
||||||
|
queryClientProviderProps={{ client: queryClient }}
|
||||||
|
>
|
||||||
|
<CartProvider>{children}</CartProvider>
|
||||||
|
</MedusaProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -7,19 +7,14 @@ import {
|
|||||||
FaLinkedin,
|
FaLinkedin,
|
||||||
} from 'react-icons/fa';
|
} from 'react-icons/fa';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
|
import logoPic from '/public/images/logo-puce-red.svg';
|
||||||
|
|
||||||
export function Footer() {
|
export function Footer() {
|
||||||
return (
|
return (
|
||||||
<footer className='bg-[#f8f6f5] flex flex-col md:flex-row py-12 border-t-2 border-black max-w-7xl mx-auto gap-8 px-4'>
|
<footer className='bg-[#f8f6f5] flex flex-col md:flex-row py-12 border-t-2 border-black max-w-7xl mx-auto gap-8 px-4'>
|
||||||
{/* First Column: Logo and Description */}
|
{/* First Column: Logo and Description */}
|
||||||
<div className='space-y-4 flex flex-col basis-1/4'>
|
<div className='space-y-4 flex flex-col basis-1/4'>
|
||||||
<Image
|
<Image src={logoPic} alt='Mozimo Logo' width={100} height={100} />
|
||||||
src='/images/logo.png' // Update with your logo path
|
|
||||||
alt='Mozimo Logo'
|
|
||||||
className='h-10'
|
|
||||||
width={100}
|
|
||||||
height={100}
|
|
||||||
/>
|
|
||||||
<p className='text-sm'>
|
<p className='text-sm'>
|
||||||
India's Premier European style bean-to-bar chocolate experience.
|
India's Premier European style bean-to-bar chocolate experience.
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { InstagramPost, fetchInstagramPosts } from '@/app/lib/instagram';
|
import { InstagramPost, fetchInstagramPosts } from '@/lib/instagram';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
export function InstagramFeed() {
|
export function InstagramFeed() {
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
/* navbar.module.css */
|
|
||||||
|
|
||||||
.navBar {
|
.navBar {
|
||||||
@apply top-6 left-6 right-6 transition-all duration-300 z-50 h-16;
|
@apply top-6 left-6 right-6 transition-all duration-300 z-50 h-20;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@ -9,11 +7,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.navBarInitial {
|
.navBarInitial {
|
||||||
@apply bg-transparent text-white absolute;
|
@apply bg-white/30 text-black rounded-lg shadow-lg absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navBarScrolledUp {
|
.navBarScrolledUp {
|
||||||
@apply bg-white text-black rounded-lg shadow-lg fixed;
|
@apply bg-gradient-to-b from-black/30 to-black/10 text-white rounded-lg fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Custom style */
|
/* Custom style */
|
||||||
@ -24,3 +22,13 @@
|
|||||||
.cls-1, .cls-2 {
|
.cls-1, .cls-2 {
|
||||||
fill: #ffffff;
|
fill: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Transparent / almost transparent to white
|
||||||
|
.navBarInitial {
|
||||||
|
@apply bg-gradient-to-b from-black/50 to-black/30 text-white absolute rounded-lg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navBarScrolledUp {
|
||||||
|
@apply bg-white text-black rounded-lg shadow-lg fixed;
|
||||||
|
}
|
||||||
|
*/
|
||||||
@ -5,7 +5,8 @@ import { FiSearch, FiUser } from 'react-icons/fi';
|
|||||||
import { HiShoppingBag } from 'react-icons/hi2';
|
import { HiShoppingBag } from 'react-icons/hi2';
|
||||||
import styles from './navbar.module.css';
|
import styles from './navbar.module.css';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import logoPic from '/public/images/logo.svg';
|
import logoWhite from '/public/images/logo-white.svg';
|
||||||
|
import logoBlack from '/public/images/logo-black.svg';
|
||||||
|
|
||||||
// components/Navbar.tsx
|
// components/Navbar.tsx
|
||||||
export function Navbar() {
|
export function Navbar() {
|
||||||
@ -49,7 +50,7 @@ export function Navbar() {
|
|||||||
<div className='flex-shrink-0'>
|
<div className='flex-shrink-0'>
|
||||||
<Link href='/' className='text-lg font-bold'>
|
<Link href='/' className='text-lg font-bold'>
|
||||||
<Image
|
<Image
|
||||||
src={logoPic}
|
src={navBarStyle === 'scrolledUp' ? logoWhite : logoBlack}
|
||||||
alt='Logo'
|
alt='Logo'
|
||||||
className='logo text-white'
|
className='logo text-white'
|
||||||
width={100}
|
width={100}
|
||||||
|
|||||||
13
src/lib/config.ts
Normal file
13
src/lib/config.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import Medusa from '@medusajs/medusa-js';
|
||||||
|
|
||||||
|
// Defaults to standard port for Medusa server
|
||||||
|
let MEDUSA_BACKEND_URL = 'http://localhost:9000';
|
||||||
|
|
||||||
|
if (process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL) {
|
||||||
|
MEDUSA_BACKEND_URL = process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const medusaClient = new Medusa({
|
||||||
|
baseUrl: MEDUSA_BACKEND_URL,
|
||||||
|
maxRetries: 3,
|
||||||
|
});
|
||||||
16
src/lib/product-by-handle.tsx
Normal file
16
src/lib/product-by-handle.tsx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { cache } from 'react';
|
||||||
|
import { medusaClient } from '@/lib/config';
|
||||||
|
import { PricedProduct } from '@medusajs/medusa/dist/types/pricing';
|
||||||
|
|
||||||
|
export const getProductByHandle = cache(async function (
|
||||||
|
handle: string,
|
||||||
|
): Promise<{ product: PricedProduct }> {
|
||||||
|
const product = await medusaClient.products
|
||||||
|
.list({ handle })
|
||||||
|
.then(({ products }) => products[0])
|
||||||
|
.catch((err) => {
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
return { product };
|
||||||
|
});
|
||||||
39
src/lib/product.tsx
Normal file
39
src/lib/product.tsx
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { cache } from 'react';
|
||||||
|
import { medusaClient } from '@/lib/config';
|
||||||
|
import { PricedProduct } from '@medusajs/medusa/dist/types/pricing';
|
||||||
|
|
||||||
|
import { StoreGetProductsParams } from '@medusajs/medusa';
|
||||||
|
|
||||||
|
export const getProductsList = cache(async function ({
|
||||||
|
pageParam = 0,
|
||||||
|
queryParams,
|
||||||
|
}: {
|
||||||
|
pageParam?: number;
|
||||||
|
queryParams?: StoreGetProductsParams;
|
||||||
|
}): Promise<{
|
||||||
|
response: { products: PricedProduct[]; count: number };
|
||||||
|
nextPage: number | null;
|
||||||
|
queryParams?: StoreGetProductsParams;
|
||||||
|
}> {
|
||||||
|
const limit = queryParams?.limit || 12;
|
||||||
|
const { products, count } = await medusaClient.products
|
||||||
|
.list(
|
||||||
|
{
|
||||||
|
limit,
|
||||||
|
offset: pageParam,
|
||||||
|
...queryParams,
|
||||||
|
},
|
||||||
|
{ next: { tags: ['products'] } },
|
||||||
|
)
|
||||||
|
.then((res) => res)
|
||||||
|
.catch((err) => {
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
const nextPage = count > pageParam + 1 ? pageParam + 1 : null;
|
||||||
|
return {
|
||||||
|
response: { products: products, count },
|
||||||
|
nextPage,
|
||||||
|
queryParams,
|
||||||
|
};
|
||||||
|
});
|
||||||
@ -1,13 +0,0 @@
|
|||||||
import { AppProps } from 'next/app'; // Import the AppProps type
|
|
||||||
import { Layout } from '../components/layout';
|
|
||||||
import '../app/globals.css';
|
|
||||||
|
|
||||||
function MyApp({ Component, pageProps }: AppProps) {
|
|
||||||
return (
|
|
||||||
<Layout>
|
|
||||||
<Component {...pageProps} />
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default MyApp;
|
|
||||||
Reference in New Issue
Block a user