Skip to content

Commit

Permalink
Merge pull request medusajs#8 from medusajs/feat/categories-menus
Browse files Browse the repository at this point in the history
feat: add categories and menus
  • Loading branch information
VariableVic authored May 11, 2023
2 parents 52a1ddd + 904f9d7 commit a0901ad
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 41 deletions.
6 changes: 3 additions & 3 deletions app/search/[collection]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getCollection, getCollectionProducts } from 'lib/medusa';
import { getCategory, getCategoryProducts } from 'lib/medusa';
import { Metadata } from 'next';
import { notFound } from 'next/navigation';

Expand All @@ -12,7 +12,7 @@ export async function generateMetadata({
}: {
params: { collection: string };
}): Promise<Metadata> {
const collection = await getCollection(params.collection);
const collection = await getCategory(params.collection);

if (!collection) return notFound();

Expand All @@ -33,7 +33,7 @@ export async function generateMetadata({
}

export default async function CategoryPage({ params }: { params: { collection: string } }) {
const products = await getCollectionProducts(params.collection);
const products = await getCategoryProducts(params.collection);

return (
<section>
Expand Down
4 changes: 2 additions & 2 deletions app/sitemap.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getCollections, getProducts } from 'lib/medusa';
import { getCategories, getProducts } from 'lib/medusa';
import { MetadataRoute } from 'next';

const baseUrl = process.env.NEXT_PUBLIC_VERCEL_URL
Expand All @@ -11,7 +11,7 @@ export default async function sitemap(): Promise<Promise<Promise<MetadataRoute.S
lastModified: new Date().toISOString()
}));

const collections = await getCollections();
const collections = await getCategories();
const collectionsMap = collections.map((collection) => ({
url: `${baseUrl}${collection.path}`,
lastModified: collection.updatedAt
Expand Down
4 changes: 2 additions & 2 deletions components/carousel.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { getCollectionProducts } from 'lib/medusa';
import { getCategoryProducts } from 'lib/medusa';
import Image from 'next/image';
import Link from 'next/link';

export async function Carousel() {
// Collections that start with `hidden-*` are hidden from the search page.
const products = await getCollectionProducts('hidden-homepage-carousel');
const products = await getCategoryProducts('hidden-homepage-carousel');

if (!products?.length) return null;

Expand Down
4 changes: 2 additions & 2 deletions components/grid/three-items.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { GridTileImage } from 'components/grid/tile';
import { getCollectionProducts } from 'lib/medusa';
import { getCategoryProducts } from 'lib/medusa';
import type { Product } from 'lib/medusa/types';
import Link from 'next/link';

Expand Down Expand Up @@ -37,7 +37,7 @@ function ThreeItemGridItem({

export async function ThreeItemGrid() {
// Collections that start with `hidden-*` are hidden from the search page.
const homepageItems = await getCollectionProducts('hidden-homepage-featured-items');
const homepageItems = await getCategoryProducts('hidden-homepage-featured-items');

if (!homepageItems[0] || !homepageItems[1] || !homepageItems[2]) return null;

Expand Down
4 changes: 2 additions & 2 deletions components/layout/footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import Link from 'next/link';
import GitHubIcon from 'components/icons/github';
import LogoIcon from 'components/icons/logo';
import VercelIcon from 'components/icons/vercel';
import { getMenu } from 'lib/medusa';
import { Menu } from 'lib/medusa/types';

const { SITE_NAME } = process.env;

export default async function Footer() {
const currentYear = new Date().getFullYear();
const copyrightDate = 2023 + (currentYear > 2023 ? `-${currentYear}` : '');
// const menu = await getMenu('next-js-frontend-footer-menu');
const menu: any[] = [];
const menu = await getMenu('next-js-frontend-footer-menu');

return (
<footer className="border-t border-gray-700 bg-white text-black dark:bg-black dark:text-white">
Expand Down
4 changes: 2 additions & 2 deletions components/layout/navbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import Link from 'next/link';
import Cart from 'components/cart';
import CartIcon from 'components/icons/cart';
import LogoIcon from 'components/icons/logo';
import { getMenu } from 'lib/medusa';
import { Menu } from 'lib/medusa/types';
import { Suspense } from 'react';
import MobileMenu from './mobile-menu';
import Search from './search';

export default async function Navbar() {
const menu: any[] = [];
// const menu = await getMenu('next-js-frontend-header-menu');
const menu = await getMenu('next-js-frontend-header-menu');

return (
<nav className="relative flex items-center justify-between bg-white p-4 dark:bg-black lg:px-6">
Expand Down
4 changes: 2 additions & 2 deletions components/layout/search/collections.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import clsx from 'clsx';
import { Suspense } from 'react';

import { getCollections } from 'lib/medusa';
import { getCategories } from 'lib/medusa';
import FilterList from './filter';

async function CollectionList() {
const collections = await getCollections();
const collections = await getCategories();
return <FilterList list={collections} title="Collections" />;
}

Expand Down
92 changes: 67 additions & 25 deletions lib/medusa/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
MedusaProductOption,
MedusaProductVariant,
Product,
ProductCategory,
ProductCollection,
ProductOption,
ProductVariant,
Expand Down Expand Up @@ -184,6 +185,7 @@ const reshapeProduct = (product: MedusaProduct): Product => {
altText: product.images?.[0]?.id ?? ''
};
const availableForSale = product.variants?.[0]?.purchasable || true;

const variants = product.variants.map((variant) =>
reshapeProductVariant(variant, product.options)
);
Expand Down Expand Up @@ -243,18 +245,40 @@ const reshapeProductVariant = (
};

const reshapeCollection = (collection: MedusaProductCollection): ProductCollection => {
const description = collection.metadata?.description?.toString() ?? '';
const description = collection.description || collection.metadata?.description?.toString() || '';
const seo = {
title: collection?.metadata?.seo_title?.toString() ?? '',
description: collection?.metadata?.seo_description?.toString() ?? ''
title: collection?.metadata?.seo_title?.toString() || collection.title || '',
description: collection?.metadata?.seo_description?.toString() || collection.description || ''
};
const path = `/${collection.handle}`;
const updatedAt = collection.updated_at;
const title = collection.name;

return {
...collection,
description,
seo,
title,
path,
updatedAt
};
};

const reshapeCategory = (category: ProductCategory): ProductCollection => {
const description = category.description || category.metadata?.description?.toString() || '';
const seo = {
title: category?.metadata?.seo_title?.toString() || category.name || '',
description: category?.metadata?.seo_description?.toString() || category.description || ''
};
const path = `/search/${category.handle}`;
const updatedAt = category.updated_at;
const title = category.name;

return {
...category,
description,
seo,
title,
path,
updatedAt
};
Expand Down Expand Up @@ -302,42 +326,40 @@ export async function getCart(cartId: string): Promise<Cart | null> {
return reshapeCart(cart);
}

export async function getCollection(handle: string): Promise<ProductCollection | undefined> {
const res = await medusaRequest('GET', `/collections?handle[]=${handle}&limit=1`);
return res.body.collections[0];
export async function getCategories(): Promise<ProductCollection[]> {
const res = await medusaRequest('GET', '/product-categories');

// Reshape categories and hide categories starting with 'hidden'
const categories = res.body.product_categories
.map((collection: ProductCategory) => reshapeCategory(collection))
.filter((collection: MedusaProductCollection) => !collection.handle.startsWith('hidden'));

return categories;
}

export async function getCollectionProducts(handle: string): Promise<Product[]> {
const collection = await getCollection(handle);
export async function getCategory(handle: string): Promise<ProductCollection | undefined> {
const res = await medusaRequest('GET', `/product-categories?handle=${handle}&expand=products`);
return res.body.product_categories[0];
}

if (!collection) {
export async function getCategoryProducts(handle: string): Promise<Product[]> {
const res = await medusaRequest('GET', `/product-categories?handle=${handle}`);

if (!res) {
return [];
}

const res = await medusaRequest('GET', `/products?collection_id[]=${collection.id}`);
const category = res.body.product_categories[0];

if (!res.body?.products) {
return [];
}
const category_products = await medusaRequest('GET', `/products?category_id[]=${category.id}`);

const products: Product[] = res.body.products.map((product: MedusaProduct) =>
const products: Product[] = category_products.body.products.map((product: MedusaProduct) =>
reshapeProduct(product)
);

return products;
}

export async function getCollections(): Promise<ProductCollection[]> {
const res = await medusaRequest('GET', '/collections');

// Reshape collections and hide collections starting with 'hidden'
const collections = res.body.collections
.map((collection: MedusaProductCollection) => reshapeCollection(collection))
.filter((collection: MedusaProductCollection) => !collection.handle.startsWith('hidden'));

return collections;
}

export async function getProduct(handle: string): Promise<Product> {
const res = await medusaRequest('GET', `/products?handle=${handle}&limit=1`);
const product = res.body.products[0];
Expand Down Expand Up @@ -372,3 +394,23 @@ export async function getProducts({

return products;
}

export async function getMenu(menu: string): Promise<any[]> {
if (menu === 'next-js-frontend-header-menu') {
const categories = await getCategories();
return categories.map((cat) => ({
title: cat.title,
path: cat.path
}));
}

if (menu === 'next-js-frontend-footer-menu') {
return [
{ title: 'About', path: 'https://medusajs.com/' },
{ title: 'Docs', path: 'https://docs.medusajs.com/' },
{ title: 'Blog', path: 'https://medusajs.com/blog' }
];
}

return [];
}
5 changes: 4 additions & 1 deletion lib/medusa/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export type MedusaProductCollection = {
name: any;
description: string | undefined;
id: string;
title: string;
handle: string;
Expand All @@ -10,7 +12,6 @@ export type MedusaProductCollection = {
};

export type ProductCollection = MedusaProductCollection & {
description?: string;
seo?: {
title?: string;
description?: string;
Expand Down Expand Up @@ -115,6 +116,7 @@ export type ShippingProfile = {
export type ProductCategory = {
id: string;
name: string;
description: string;
handle: string;
mpath: string | null;
is_internal?: boolean;
Expand All @@ -126,6 +128,7 @@ export type ProductCategory = {
products?: Product[];
created_at: string;
updated_at: string;
metadata?: { [key: string]: string } | null;
};

export type MedusaProductVariant = {
Expand Down
5 changes: 5 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ module.exports = {
protocol: 'https',
hostname: 'medusa-public-images.s3.eu-west-1.amazonaws.com',
pathname: '/**'
},
{
protocol: 'https',
hostname: 'medusa-server-testing.s3.amazonaws.com',
pathname: '/**'
}
]
}
Expand Down

0 comments on commit a0901ad

Please sign in to comment.