Compare commits
4 Commits
5ef7f58f5d
...
MED-122
| Author | SHA1 | Date | |
|---|---|---|---|
| 615dde52e6 | |||
| 7f2c6f2374 | |||
| 6368a5b5ff | |||
| 8e82736f09 |
5
app/home/(user)/(dashboard)/cart/loading.tsx
Normal file
5
app/home/(user)/(dashboard)/cart/loading.tsx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import SkeletonCartPage from '~/medusa/modules/skeletons/templates/skeleton-cart-page';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return <SkeletonCartPage />;
|
||||||
|
}
|
||||||
21
app/home/(user)/(dashboard)/cart/not-found.tsx
Normal file
21
app/home/(user)/(dashboard)/cart/not-found.tsx
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { Metadata } from 'next';
|
||||||
|
|
||||||
|
import InteractiveLink from '~/medusa/modules/common/components/interactive-link';
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: '404',
|
||||||
|
description: 'Something went wrong',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function NotFound() {
|
||||||
|
return (
|
||||||
|
<div className="flex min-h-[calc(100vh-64px)] flex-col items-center justify-center">
|
||||||
|
<h1 className="text-2xl-semi text-ui-fg-base">Page not found</h1>
|
||||||
|
<p className="text-small-regular text-ui-fg-base">
|
||||||
|
The cart you tried to access does not exist. Clear your cookies and try
|
||||||
|
again.
|
||||||
|
</p>
|
||||||
|
<InteractiveLink href="/">Go to frontpage</InteractiveLink>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
59
app/home/(user)/(dashboard)/cart/page.tsx
Normal file
59
app/home/(user)/(dashboard)/cart/page.tsx
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import { PageBody, PageHeader } from '@/packages/ui/src/makerkit/page';
|
||||||
|
import { Metadata } from 'next';
|
||||||
|
|
||||||
|
import { notFound } from 'next/navigation';
|
||||||
|
|
||||||
|
import { retrieveCart } from '~/medusa/lib/data/cart';
|
||||||
|
import { retrieveCustomer } from '~/medusa/lib/data/customer';
|
||||||
|
import CartTemplate from '~/medusa/modules/cart/templates';
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: 'Cart',
|
||||||
|
description: 'View your cart',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function Cart() {
|
||||||
|
const cart2 = await retrieveCart().catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
return notFound();
|
||||||
|
});
|
||||||
|
|
||||||
|
const customer = await retrieveCustomer();
|
||||||
|
|
||||||
|
const cart: NonNullable<typeof cart2> = {
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
quantity: 1,
|
||||||
|
cart: cart2!,
|
||||||
|
item_total: 100,
|
||||||
|
item_subtotal: 100,
|
||||||
|
item_tax_total: 100,
|
||||||
|
original_total: 100,
|
||||||
|
original_subtotal: 100,
|
||||||
|
original_tax_total: 100,
|
||||||
|
total: 100,
|
||||||
|
subtotal: 100,
|
||||||
|
tax_total: 100,
|
||||||
|
title: 'Test',
|
||||||
|
requires_shipping: true,
|
||||||
|
discount_total: 0,
|
||||||
|
discount_tax_total: 0,
|
||||||
|
metadata: {},
|
||||||
|
created_at: new Date(),
|
||||||
|
is_discountable: true,
|
||||||
|
is_tax_inclusive: true,
|
||||||
|
unit_price: 100,
|
||||||
|
cart_id: '1',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageBody>
|
||||||
|
<PageHeader title={`Ostukorv`} description={`Vali kalendrist sobiv kuupäev ja broneeri endale vastuvõtuaeg.`} />
|
||||||
|
|
||||||
|
<CartTemplate cart={cart} customer={customer} />
|
||||||
|
</PageBody>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
|
import Link from 'next/link';
|
||||||
|
import { ShoppingCart } from 'lucide-react';
|
||||||
|
|
||||||
import { Trans } from '@kit/ui/trans';
|
import { Trans } from '@kit/ui/trans';
|
||||||
|
|
||||||
import { AppLogo } from '~/components/app-logo';
|
import { AppLogo } from '~/components/app-logo';
|
||||||
import { ProfileAccountDropdownContainer } from '~/components/personal-account-dropdown-container';
|
import { ProfileAccountDropdownContainer } from '~/components/personal-account-dropdown-container';
|
||||||
import { Search } from '~/components/ui/search';
|
import { Search } from '~/components/ui/search';
|
||||||
|
import { SIDEBAR_WIDTH_PROPERTY } from '@/packages/ui/src/shadcn/constants';
|
||||||
|
import { Button } from '@kit/ui/button';
|
||||||
|
|
||||||
import { SIDEBAR_WIDTH_PROPERTY } from '../../../../packages/ui/src/shadcn/constants';
|
|
||||||
// home imports
|
|
||||||
import { UserNotifications } from '../_components/user-notifications';
|
import { UserNotifications } from '../_components/user-notifications';
|
||||||
import { type UserWorkspace } from '../_lib/server/load-user-workspace';
|
import { type UserWorkspace } from '../_lib/server/load-user-workspace';
|
||||||
import { Button } from '@kit/ui/button';
|
|
||||||
import { ShoppingCart } from 'lucide-react';
|
|
||||||
|
|
||||||
export function HomeMenuNavigation(props: { workspace: UserWorkspace }) {
|
export function HomeMenuNavigation(props: { workspace: UserWorkspace }) {
|
||||||
const { workspace, user, accounts } = props.workspace;
|
const { workspace, user, accounts } = props.workspace;
|
||||||
@@ -30,10 +29,12 @@ export function HomeMenuNavigation(props: { workspace: UserWorkspace }) {
|
|||||||
<Button className='relative px-4 py-2 h-10 border-1 mr-0 cursor-pointer' variant='ghost'>
|
<Button className='relative px-4 py-2 h-10 border-1 mr-0 cursor-pointer' variant='ghost'>
|
||||||
<span className='flex items-center text-nowrap'>€ 231,89</span>
|
<span className='flex items-center text-nowrap'>€ 231,89</span>
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="ghost" className='relative px-4 py-2 h-10 border-1 mr-0 cursor-pointer' >
|
<Link href='/home/cart'>
|
||||||
<ShoppingCart className="stroke-[1.5px]" />
|
<Button variant="ghost" className='relative px-4 py-2 h-10 border-1 mr-0 cursor-pointer' >
|
||||||
<Trans i18nKey="common:shoppingCart" /> (0)
|
<ShoppingCart className="stroke-[1.5px]" />
|
||||||
</Button>
|
<Trans i18nKey="common:shoppingCart" /> (0)
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
<UserNotifications userId={user.id} />
|
<UserNotifications userId={user.id} />
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -68,13 +68,11 @@ async function JoinTeamAccountPage(props: JoinTeamAccountPageProps) {
|
|||||||
const invitation = await api.getInvitation(adminClient, token);
|
const invitation = await api.getInvitation(adminClient, token);
|
||||||
|
|
||||||
// the invitation is not found or expired
|
// the invitation is not found or expired
|
||||||
if (!invitation) {
|
|
||||||
return (
|
return (
|
||||||
<AuthLayoutShell Logo={AppLogo}>
|
<AuthLayoutShell Logo={AppLogo}>
|
||||||
<InviteNotFoundOrExpired />
|
<InviteNotFoundOrExpired />
|
||||||
</AuthLayoutShell>
|
</AuthLayoutShell>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
// we need to verify the user isn't already in the account
|
// we need to verify the user isn't already in the account
|
||||||
// we do so by checking if the user can read the account
|
// we do so by checking if the user can read the account
|
||||||
|
|||||||
@@ -1,46 +1,117 @@
|
|||||||
import { Metadata } from 'next';
|
import { use } from 'react';
|
||||||
|
|
||||||
import { StoreCartShippingOption } from '@medusajs/types';
|
import { cookies } from 'next/headers';
|
||||||
|
|
||||||
import { listCartOptions, retrieveCart } from '~/medusa/lib/data/cart';
|
import { z } from 'zod';
|
||||||
import { retrieveCustomer } from '~/medusa/lib/data/customer';
|
|
||||||
import { getBaseURL } from '~/medusa/lib/util/env';
|
|
||||||
import CartMismatchBanner from '~/medusa/modules/layout/components/cart-mismatch-banner';
|
|
||||||
import Footer from '~/medusa/modules/layout/templates/footer';
|
|
||||||
import Nav from '~/medusa/modules/layout/templates/nav';
|
|
||||||
import FreeShippingPriceNudge from '~/medusa/modules/shipping/components/free-shipping-price-nudge';
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
import { UserWorkspaceContextProvider } from '@kit/accounts/components';
|
||||||
metadataBase: new URL(getBaseURL()),
|
import { Page, PageMobileNavigation, PageNavigation } from '@kit/ui/page';
|
||||||
};
|
import { SidebarProvider } from '@kit/ui/shadcn-sidebar';
|
||||||
|
|
||||||
export default async function PageLayout(props: { children: React.ReactNode }) {
|
import { AppLogo } from '~/components/app-logo';
|
||||||
const customer = await retrieveCustomer();
|
import { personalAccountNavigationConfig } from '~/config/personal-account-navigation.config';
|
||||||
const cart = await retrieveCart();
|
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||||
let shippingOptions: StoreCartShippingOption[] = [];
|
import { loadUserWorkspace } from '@/app/home/(user)/_lib/server/load-user-workspace';
|
||||||
|
import { HomeSidebar } from '@/app/home/(user)/_components/home-sidebar';
|
||||||
|
import { HomeMenuNavigation } from '@/app/home/(user)/_components/home-menu-navigation';
|
||||||
|
import { HomeMobileNavigation } from '@/app/home/(user)/_components/home-mobile-navigation';
|
||||||
|
|
||||||
if (cart) {
|
function UserHomeLayout({ children }: React.PropsWithChildren) {
|
||||||
const { shipping_options } = await listCartOptions();
|
const state = use(getLayoutState());
|
||||||
|
|
||||||
shippingOptions = shipping_options;
|
if (state.style === 'sidebar') {
|
||||||
|
return <SidebarLayout>{children}</SidebarLayout>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return <HeaderLayout>{children}</HeaderLayout>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withI18n(UserHomeLayout);
|
||||||
|
|
||||||
|
function SidebarLayout({ children }: React.PropsWithChildren) {
|
||||||
|
const workspace = use(loadUserWorkspace());
|
||||||
|
const state = use(getLayoutState());
|
||||||
|
|
||||||
|
return (
|
||||||
|
<UserWorkspaceContextProvider value={workspace}>
|
||||||
|
<SidebarProvider defaultOpen={state.open}>
|
||||||
|
<Page style={'sidebar'}>
|
||||||
|
<PageNavigation>
|
||||||
|
<HomeSidebar />
|
||||||
|
</PageNavigation>
|
||||||
|
|
||||||
|
<PageMobileNavigation className={'flex items-center justify-between'}>
|
||||||
|
<MobileNavigation workspace={workspace} />
|
||||||
|
</PageMobileNavigation>
|
||||||
|
|
||||||
|
{children}
|
||||||
|
</Page>
|
||||||
|
</SidebarProvider>
|
||||||
|
</UserWorkspaceContextProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function HeaderLayout({ children }: React.PropsWithChildren) {
|
||||||
|
const workspace = use(loadUserWorkspace());
|
||||||
|
|
||||||
|
return (
|
||||||
|
<UserWorkspaceContextProvider value={workspace}>
|
||||||
|
<Page style={'header'}>
|
||||||
|
<PageNavigation>
|
||||||
|
<HomeMenuNavigation workspace={workspace} />
|
||||||
|
</PageNavigation>
|
||||||
|
|
||||||
|
<PageMobileNavigation className={'flex items-center justify-between'}>
|
||||||
|
<MobileNavigation workspace={workspace} />
|
||||||
|
</PageMobileNavigation>
|
||||||
|
|
||||||
|
<SidebarProvider defaultOpen>
|
||||||
|
<Page style={'sidebar'}>
|
||||||
|
<PageNavigation>
|
||||||
|
<HomeSidebar />
|
||||||
|
</PageNavigation>
|
||||||
|
{children}
|
||||||
|
</Page>
|
||||||
|
</SidebarProvider>
|
||||||
|
</Page>
|
||||||
|
</UserWorkspaceContextProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function MobileNavigation({
|
||||||
|
workspace,
|
||||||
|
}: {
|
||||||
|
workspace: Awaited<ReturnType<typeof loadUserWorkspace>>;
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Nav />
|
<AppLogo />
|
||||||
{customer && cart && (
|
|
||||||
<CartMismatchBanner customer={customer} cart={cart} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
{cart && (
|
<HomeMobileNavigation workspace={workspace} />
|
||||||
<FreeShippingPriceNudge
|
|
||||||
variant="popup"
|
|
||||||
cart={cart}
|
|
||||||
shippingOptions={shippingOptions}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{props.children}
|
|
||||||
<Footer />
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getLayoutState() {
|
||||||
|
const cookieStore = await cookies();
|
||||||
|
|
||||||
|
const LayoutStyleSchema = z.enum(['sidebar', 'header', 'custom']);
|
||||||
|
|
||||||
|
const layoutStyleCookie = cookieStore.get('layout-style');
|
||||||
|
const sidebarOpenCookie = cookieStore.get('sidebar:state');
|
||||||
|
|
||||||
|
const sidebarOpen = sidebarOpenCookie
|
||||||
|
? sidebarOpenCookie.value === 'false'
|
||||||
|
: !personalAccountNavigationConfig.sidebarCollapsed;
|
||||||
|
|
||||||
|
const parsedStyle = LayoutStyleSchema.safeParse(layoutStyleCookie?.value);
|
||||||
|
|
||||||
|
const style = parsedStyle.success
|
||||||
|
? parsedStyle.data
|
||||||
|
: personalAccountNavigationConfig.style;
|
||||||
|
|
||||||
|
return {
|
||||||
|
open: sidebarOpen,
|
||||||
|
style,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
46
app/store/[countryCode]/(main)/layout2.tsx
Normal file
46
app/store/[countryCode]/(main)/layout2.tsx
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { Metadata } from 'next';
|
||||||
|
|
||||||
|
import { StoreCartShippingOption } from '@medusajs/types';
|
||||||
|
|
||||||
|
import { listCartOptions, retrieveCart } from '~/medusa/lib/data/cart';
|
||||||
|
import { retrieveCustomer } from '~/medusa/lib/data/customer';
|
||||||
|
import { getBaseURL } from '~/medusa/lib/util/env';
|
||||||
|
import CartMismatchBanner from '~/medusa/modules/layout/components/cart-mismatch-banner';
|
||||||
|
import Footer from '~/medusa/modules/layout/templates/footer';
|
||||||
|
import Nav from '~/medusa/modules/layout/templates/nav';
|
||||||
|
import FreeShippingPriceNudge from '~/medusa/modules/shipping/components/free-shipping-price-nudge';
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
metadataBase: new URL(getBaseURL()),
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function PageLayout(props: { children: React.ReactNode }) {
|
||||||
|
const customer = await retrieveCustomer();
|
||||||
|
const cart = await retrieveCart();
|
||||||
|
let shippingOptions: StoreCartShippingOption[] = [];
|
||||||
|
|
||||||
|
if (cart) {
|
||||||
|
const { shipping_options } = await listCartOptions();
|
||||||
|
|
||||||
|
shippingOptions = shipping_options;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Nav />
|
||||||
|
{customer && cart && (
|
||||||
|
<CartMismatchBanner customer={customer} cart={cart} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{cart && (
|
||||||
|
<FreeShippingPriceNudge
|
||||||
|
variant="popup"
|
||||||
|
cart={cart}
|
||||||
|
shippingOptions={shippingOptions}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{props.children}
|
||||||
|
<Footer />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -44,7 +44,7 @@ export const getRegion = async (countryCode: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const regions = await listRegions()
|
const regions = await listRegions()
|
||||||
|
console.log("regions", regions)
|
||||||
if (!regions) {
|
if (!regions) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,7 @@ export const getRegion = async (countryCode: string) => {
|
|||||||
|
|
||||||
const region = countryCode
|
const region = countryCode
|
||||||
? regionMap.get(countryCode)
|
? regionMap.get(countryCode)
|
||||||
: regionMap.get("us")
|
: regionMap.get("et")
|
||||||
|
|
||||||
return region
|
return region
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
|
|||||||
@@ -1,23 +1,6 @@
|
|||||||
import { Heading, Text } from "@medusajs/ui"
|
|
||||||
|
|
||||||
import InteractiveLink from "@modules/common/components/interactive-link"
|
|
||||||
|
|
||||||
const EmptyCartMessage = () => {
|
const EmptyCartMessage = () => {
|
||||||
return (
|
return (
|
||||||
<div className="py-48 px-2 flex flex-col justify-center items-start" data-testid="empty-cart-message">
|
<div className="py-48 px-2 flex flex-col justify-center items-start" data-testid="empty-cart-message">
|
||||||
<Heading
|
|
||||||
level="h1"
|
|
||||||
className="flex flex-row text-3xl-regular gap-x-2 items-baseline"
|
|
||||||
>
|
|
||||||
Cart
|
|
||||||
</Heading>
|
|
||||||
<Text className="text-base-regular mt-4 mb-6 max-w-[32rem]">
|
|
||||||
You don't have anything in your cart. Let's change that, use
|
|
||||||
the link below to start browsing our products.
|
|
||||||
</Text>
|
|
||||||
<div>
|
|
||||||
<InteractiveLink href="/store">Explore products</InteractiveLink>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ const CartTemplate = ({
|
|||||||
{cart?.items?.length ? (
|
{cart?.items?.length ? (
|
||||||
<div className="grid grid-cols-1 small:grid-cols-[1fr_360px] gap-x-40">
|
<div className="grid grid-cols-1 small:grid-cols-[1fr_360px] gap-x-40">
|
||||||
<div className="flex flex-col bg-white py-6 gap-y-6">
|
<div className="flex flex-col bg-white py-6 gap-y-6">
|
||||||
{!customer && (
|
{/* {!customer && (
|
||||||
<>
|
<>
|
||||||
<SignInPrompt />
|
<SignInPrompt />
|
||||||
<Divider />
|
<Divider />
|
||||||
</>
|
</>
|
||||||
)}
|
)} */}
|
||||||
<ItemsTemplate cart={cart} />
|
<ItemsTemplate cart={cart} />
|
||||||
</div>
|
</div>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ const ItemsTemplate = ({ cart }: ItemsTemplateProps) => {
|
|||||||
const items = cart?.items
|
const items = cart?.items
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="pb-3 flex items-center">
|
{/* <div className="pb-3 flex items-center">
|
||||||
<Heading className="text-[2rem] leading-[2.75rem]">Cart</Heading>
|
<Heading className="text-[2rem] leading-[2.75rem]">Cart</Heading>
|
||||||
</div>
|
</div> */}
|
||||||
<Table>
|
<Table>
|
||||||
<Table.Header className="border-t-0">
|
<Table.Header className="border-t-0">
|
||||||
<Table.Row className="text-ui-fg-subtle txt-medium-plus">
|
<Table.Row className="text-ui-fg-subtle txt-medium-plus">
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export function formatCurrency(params: {
|
|||||||
locale: string;
|
locale: string;
|
||||||
value: string | number;
|
value: string | number;
|
||||||
}) {
|
}) {
|
||||||
const [lang, region] = params.locale.split('-');
|
const [lang, region] = (params.locale ?? 'et-ET').split('-');
|
||||||
|
|
||||||
return new Intl.NumberFormat(region ?? lang, {
|
return new Intl.NumberFormat(region ?? lang, {
|
||||||
style: 'currency',
|
style: 'currency',
|
||||||
|
|||||||
Reference in New Issue
Block a user