Skip to content

Commit

Permalink
Merge branch 'master' into feature/T-760-sf-update-product-image-gall…
Browse files Browse the repository at this point in the history
…ery-image-sizes
  • Loading branch information
anteprimorac committed Nov 13, 2024
2 parents 769ce00 + 671c1f7 commit 1714564
Show file tree
Hide file tree
Showing 30 changed files with 638 additions and 674 deletions.
40 changes: 40 additions & 0 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs

name: PR test

on:
pull_request:
branches: ['master']

jobs:
lint-storefront:
runs-on: ubuntu-latest

strategy:
matrix:
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
node-version: [20.x, 22.x]

steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
cache-dependency-path: 'storefront/yarn.lock'
- run: yarn install --frozen-lockfile
working-directory: storefront
- run: yarn lint
working-directory: storefront
env:
NODE_ENV: production
NEXT_PUBLIC_MEDUSA_BACKEND_URL: ${{ secrets.NEXT_PUBLIC_MEDUSA_BACKEND_URL }}
NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY }}
NEXT_PUBLIC_STRIPE_KEY: ${{ secrets.NEXT_PUBLIC_STRIPE_KEY }}
REVALIDATE_SECRET: ${{ secrets.REVALIDATE_SECRET }}
DISALLOW_ROBOTS: true
NEXT_PUBLIC_DEFAULT_REGION: us
NEXT_PUBLIC_FEATURE_SEARCH_ENABLED: false
NEXT_PUBLIC_BASE_URL: https://fashion-starter.agilo.com
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ This starter kit is an ideal solution for developers who need to set up a profes
- **Fully Responsive Design**: Optimized for mobile, tablet, and desktop devices, ensuring a smooth, consistent experience across all platforms.
- **Stripe Integration for Payments**: Accept payments effortlessly by integrating **Stripe**. Simply add your Stripe API key to `medusa/.env` and the publishable key to `storefront/.env` to get started.
- **Full E-commerce Functionality**: The starter includes all the essential e-commerce features you need, including product pages, a shopping cart, a checkout process, and order confirmation.
- **Next.js and Tailwind CSS**: Built with **Next.js** v14 app router and **Tailwind CSS**, the starter is highly performant, customizable, and easy to extend with additional features.
- **Next.js and Tailwind CSS**: Built with **Next.js** v15 app router and **Tailwind CSS**, the starter is highly performant, customizable, and easy to extend with additional features.

## Roadmap
- **Figma Design Templates**: This will enable you to easily customize the design of the storefront to match your brand.
Expand Down
1 change: 1 addition & 0 deletions storefront/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"@paypal/react-paypal-js": "^8.7.0",
"@stripe/react-stripe-js": "^2.8.1",
"@stripe/stripe-js": "^4.9.0",
"@vercel/speed-insights": "^1.0.14",
"algoliasearch": "^5.10.1",
"axios": "^1.7.7",
"embla-carousel-react": "^8.3.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Metadata } from "next"
import { notFound } from "next/navigation"
import { HttpTypes } from "@medusajs/types"

import { enrichLineItems, retrieveCart } from "@lib/data/cart"
import { retrieveCart } from "@lib/data/cart"
import { getCustomer } from "@lib/data/customer"
import Wrapper from "@modules/checkout/components/payment-wrapper"
import CheckoutForm from "@modules/checkout/templates/checkout-form"
Expand All @@ -21,11 +21,6 @@ const fetchCart = async () => {
return notFound()
}

if (cart?.items?.length) {
const enrichedItems = await enrichLineItems(cart?.items, cart?.region_id!)
cart.items = enrichedItems as HttpTypes.StoreCartLineItem[]
}

return cart
}

Expand Down
20 changes: 2 additions & 18 deletions storefront/src/app/[countryCode]/(main)/cart/page.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,16 @@
import { Metadata } from "next"
import CartTemplate from "@modules/cart/templates"

import { enrichLineItems, retrieveCart } from "@lib/data/cart"
import { HttpTypes } from "@medusajs/types"
import { retrieveCart } from "@lib/data/cart"
import { getCustomer } from "@lib/data/customer"

export const metadata: Metadata = {
title: "Cart",
description: "View your cart",
}

const fetchCart = async () => {
const cart = await retrieveCart()

if (!cart) {
return null
}

if (cart?.items?.length) {
const enrichedItems = await enrichLineItems(cart?.items, cart?.region_id!)
cart.items = enrichedItems as HttpTypes.StoreCartLineItem[]
}

return cart
}

export default async function Cart() {
const cart = await fetchCart()
const cart = await retrieveCart()
const customer = await getCustomer()

return <CartTemplate cart={cart} customer={customer} />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,21 @@
import { Metadata } from "next"
import { notFound } from "next/navigation"

import OrderCompletedTemplate from "@modules/order/templates/order-completed-template"
import { notFound } from "next/navigation"
import { enrichLineItems } from "@lib/data/cart"
import { retrieveOrder } from "@lib/data/orders"
import { HttpTypes } from "@medusajs/types"

type Props = {
params: Promise<{ id: string }>
}

async function getOrder(id: string) {
const order = await retrieveOrder(id)

if (!order) {
return
}

const enrichedItems = await enrichLineItems(order.items, order.region_id!)

return {
...order,
items: enrichedItems,
} as unknown as HttpTypes.StoreOrder
}

export const metadata: Metadata = {
title: "Order Confirmed",
description: "You purchase was successful",
}

export default async function OrderConfirmedPage({ params }: Props) {
const { id } = await params
const order = await getOrder(id)
const order = await retrieveOrder(id)
if (!order) {
return notFound()
}
Expand Down
4 changes: 3 additions & 1 deletion storefront/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { getBaseURL } from "@lib/util/env"
import { Metadata } from "next"
import { SpeedInsights } from "@vercel/speed-insights/next"
import localFont from "next/font/local"
import { getBaseURL } from "@lib/util/env"

import "../styles/globals.css"

Expand Down Expand Up @@ -69,6 +70,7 @@ export default function RootLayout(props: { children: React.ReactNode }) {
<html lang="en" data-mode="light" className="antialiased">
<body className={`${monaSans.className}`}>
<main className="relative">{props.children}</main>
<SpeedInsights />
</body>
</html>
)
Expand Down
23 changes: 5 additions & 18 deletions storefront/src/components/Carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,23 @@ import { Icon } from "@/components/Icon"
import { IconCircle } from "@/components/IconCircle"
import { Layout, LayoutColumn } from "@/components/Layout"

// Utils
import useWindowSize from "@lib/hooks/useWindowSize"

export type CarouselProps = {
heading?: React.ReactNode
button?: React.ReactNode
arrows?: boolean
disableOnDesktop?: boolean
} & React.ComponentPropsWithRef<"div">

export const Carousel: React.FC<CarouselProps> = ({
heading,
button,
arrows = true,
disableOnDesktop = false,
children,
className,
}) => {
const { width } = useWindowSize()

const [emblaRef, emblaApi] = useEmblaCarousel({
containScroll: "trimSnaps",
skipSnaps: true,
active: disableOnDesktop ? (width > 768 ? false : true) : true,
active: true,
})
const [prevBtnDisabled, setPrevBtnDisabled] = React.useState(true)
const [nextBtnDisabled, setNextBtnDisabled] = React.useState(true)
Expand Down Expand Up @@ -66,15 +59,14 @@ export const Carousel: React.FC<CarouselProps> = ({
<LayoutColumn className="relative">
<div
className={twJoin(
"mb-8 md:mb-15 flex flex-wrap justify-between items-center gap-x-10 gap-y-2",
disableOnDesktop && "md:mb-8"
"mb-8 md:mb-15 flex flex-wrap justify-between items-center gap-x-10 gap-y-2"
)}
>
{heading}
{(arrows || button) && (
<div className={twJoin(!disableOnDesktop && "flex md:gap-6")}>
<div className={twJoin("flex md:gap-6")}>
{button}
{arrows && !disableOnDesktop && (
{arrows && (
<div className="flex gap-2">
<button
type="button"
Expand Down Expand Up @@ -114,12 +106,7 @@ export const Carousel: React.FC<CarouselProps> = ({
)}
</div>
<div ref={emblaRef}>
<div
className={twJoin(
"flex touch-pan-y gap-4 md:gap-10",
disableOnDesktop && "md:gap-6"
)}
>
<div className={twJoin("flex touch-pan-y gap-4 md:gap-10")}>
{children}
</div>
</div>
Expand Down
23 changes: 23 additions & 0 deletions storefront/src/components/CartIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Suspense } from "react"
import { getCartQuantity } from "@lib/data/cart"
import { Icon, IconProps } from "./Icon"

const CartIconWithQuantity: React.FC<
Omit<IconProps, "status" | "name">
> = async (props) => {
const quantity = await getCartQuantity()

return (
<Icon name="case" status={quantity > 0 ? quantity : undefined} {...props} />
)
}

export const CartIcon: React.FC<Omit<IconProps, "status" | "name">> = (
props
) => {
return (
<Suspense fallback={<Icon name="case" {...props} />}>
<CartIconWithQuantity {...props} />
</Suspense>
)
}
79 changes: 76 additions & 3 deletions storefront/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,83 @@ import * as React from "react"
import { listRegions } from "@lib/data/regions"

// Components
import InnerHeader from "./InnerHeader"
import { Layout, LayoutColumn } from "@/components/Layout"
import { LocalizedButtonLink, LocalizedLink } from "@/components/LocalizedLink"
import { CartIcon } from "./CartIcon"
import { HeaderDrawer } from "./HeaderDrawer"
import { RegionSwitcher } from "./RegionSwitcher"
import { HeaderWrapper } from "./HeaderWrapper"

export async function Header() {
export const Header: React.FC = async () => {
const regions = await listRegions()

return <InnerHeader regions={regions} />
const countryOptions = regions
.map((r) => {
return (r.countries ?? []).map((c) => ({
country: c.iso_2,
region: r.id,
label: c.display_name,
}))
})
.flat()
.sort((a, b) => (a?.label ?? "").localeCompare(b?.label ?? ""))

return (
<>
<HeaderWrapper>
<Layout>
<LayoutColumn>
<div className="flex justify-between items-center h-18 md:h-21">
<h1 className="font-medium text-md">
<LocalizedLink href="/">SofaSocietyCo.</LocalizedLink>
</h1>
<div className="flex items-center gap-8 max-md:hidden">
<LocalizedLink href="/about">About</LocalizedLink>
<LocalizedLink href="/inspiration">Inspiration</LocalizedLink>
<LocalizedLink href="/store">Shop</LocalizedLink>
</div>
<div className="flex items-center gap-3 lg:gap-6 max-md:hidden">
<RegionSwitcher
countryOptions={countryOptions}
className="w-16"
selectButtonClassName="bg-transparent border-0 h-auto !gap-0 !p-1 w-full"
selectIconClassName="text-current"
/>
{/* <Button
variant="ghost"
className="p-1 group-data-[light=true]:md:text-white group-data-[sticky=true]:md:text-black"
>
<Icon name="search" className="w-5 h-5" />
</Button> */}
{/* <Button
variant="ghost"
className="p-1 group-data-[light=true]:md:text-white"
>
<Icon name="user" className="w-6 h-6" />
</Button> */}

<LocalizedButtonLink
href="/cart"
variant="ghost"
className="p-1 group-data-[light=true]:md:text-white group-data-[sticky=true]:md:text-black"
>
<CartIcon className="w-6 h-6" />
</LocalizedButtonLink>
</div>
<div className="flex items-center gap-6 md:hidden">
<LocalizedButtonLink
href="/cart"
variant="ghost"
className="p-1 group-data-[light=true]:md:text-white"
>
<CartIcon className="w-6 h-6" wrapperClassName="w-6 h-6" />
</LocalizedButtonLink>
<HeaderDrawer countryOptions={countryOptions} />
</div>
</div>
</LayoutColumn>
</Layout>
</HeaderWrapper>
</>
)
}
Loading

0 comments on commit 1714564

Please sign in to comment.