Add : discount api fetching

This commit is contained in:
Wijayaac 2024-03-28 10:53:35 +07:00
parent 11b8711fca
commit de958dcdf3
10 changed files with 60 additions and 33 deletions

View File

@ -4,7 +4,7 @@ import { GridTileImage } from './grid/tile';
export async function Carousel() { export async function Carousel() {
// Collections that start with `hidden-*` are hidden from the search page. // Collections that start with `hidden-*` are hidden from the search page.
const products = await getCollectionProducts({ collection: 'boxes' }); const products = await getCollectionProducts({ collection: 'all' });
if (!products?.length) return null; if (!products?.length) return null;

View File

@ -1,7 +1,15 @@
'use server'; 'use server';
import { TAGS } from 'lib/constants'; import { TAGS } from 'lib/constants';
import { addToCart, createCart, getCart, removeFromCart, updateCart } from 'lib/shopify'; import {
addToCart,
createCart,
getCart,
getDiscountMetaobjects,
removeFromCart,
updateCart
} from 'lib/shopify';
import { formatDiscounts } from 'lib/utils';
import { revalidateTag } from 'next/cache'; import { revalidateTag } from 'next/cache';
import { cookies } from 'next/headers'; import { cookies } from 'next/headers';
@ -83,22 +91,13 @@ export async function updateItemQuantity(
} }
export async function calculateDiscounts(cart: any) { export async function calculateDiscounts(cart: any) {
const discountGroups = [ const metaobjects = await getDiscountMetaobjects('dynamic_discount');
{
name: 'Tier 2', const discountGroups = formatDiscounts(metaobjects);
discount: {
amount: 0.1, if (discountGroups === undefined) {
minimumSpent: 150 return;
} }
},
{
name: 'Tier 1',
discount: {
amount: 0.05,
minimumSpent: 120
}
}
];
const subTotal = cart?.cost.subtotalAmount.amount; const subTotal = cart?.cost.subtotalAmount.amount;
const currencyCode = cart?.cost.subtotalAmount.currencyCode; const currencyCode = cart?.cost.subtotalAmount.currencyCode;
@ -122,12 +121,15 @@ export async function calculateDiscounts(cart: any) {
: 0; : 0;
const nextDiscount = closestNextTier?.discount.amount; const nextDiscount = closestNextTier?.discount.amount;
const discountAmount = finalDiscount ? finalDiscount * 100 : 0; const discountAmount = finalDiscount ? finalDiscount * 100 : 0;
// get discount code from the final discount group
const discountCode = eligibleDiscount.length ? eligibleDiscount[0]?.code : '';
return { return {
discountAmount, discountAmount,
spentToNextDiscount, spentToNextDiscount,
nextDiscount, nextDiscount,
discountGroups: discountGroupsSorted, discountGroups: discountGroupsSorted,
discountCode,
minSpent, minSpent,
subTotal, subTotal,
currencyCode currencyCode

View File

@ -182,7 +182,7 @@ export default function CartModal({
</div> </div>
</div> </div>
<a <a
href={cart.checkoutUrl} href={`${cart.checkoutUrl}&discount=${tieredDiscount?.discountCode || ''}`}
className="block w-full rounded-full bg-blue-600 p-3 text-center text-sm font-medium text-white opacity-90 hover:opacity-100" className="block w-full rounded-full bg-blue-600 p-3 text-center text-sm font-medium text-white opacity-90 hover:opacity-100"
> >
Proceed to Checkout Proceed to Checkout

View File

@ -40,7 +40,7 @@ function ThreeItemGridItem({
export async function ThreeItemGrid() { export async function ThreeItemGrid() {
// Collections that start with `hidden-*` are hidden from the search page. // Collections that start with `hidden-*` are hidden from the search page.
const homepageItems = await getCollectionProducts({ const homepageItems = await getCollectionProducts({
collection: 'sale' collection: 'all'
}); });
if (!homepageItems[0] || !homepageItems[1] || !homepageItems[2]) return null; if (!homepageItems[0] || !homepageItems[1] || !homepageItems[2]) return null;

View File

@ -1,9 +1,9 @@
import Link from 'next/link'; import Link from 'next/link';
import FooterMenu from 'components/layout/footer-menu';
import LogoSquare from 'components/logo-square'; import LogoSquare from 'components/logo-square';
import { getMenu } from 'lib/shopify'; import { getMenu } from 'lib/shopify';
import { Suspense } from 'react'; import { Suspense } from 'react';
import FooterMenu from './footer-menu';
const { COMPANY_NAME, SITE_NAME } = process.env; const { COMPANY_NAME, SITE_NAME } = process.env;
@ -16,9 +16,9 @@ export default async function Footer() {
return ( return (
<footer className="text-sm text-neutral-500 dark:text-neutral-400"> <footer className="text-sm text-neutral-500 dark:text-neutral-400">
<div className="mx-auto flex w-full max-w-7xl flex-col gap-6 border-t border-neutral-200 px-6 py-12 text-sm dark:border-neutral-700 md:flex-row md:gap-12 md:px-4 min-[1320px]:px-0"> <div className="mx-auto flex w-full max-w-7xl flex-col gap-6 border-t border-neutral-200 px-6 py-12 text-sm md:flex-row md:gap-12 md:px-4 min-[1320px]:px-0 dark:border-neutral-700">
<div> <div>
<Link className="flex items-center gap-2 text-black dark:text-white md:pt-1" href="/"> <Link className="flex items-center gap-2 text-black md:pt-1 dark:text-white" href="/">
<LogoSquare size="sm" /> <LogoSquare size="sm" />
<span className="uppercase">{SITE_NAME}</span> <span className="uppercase">{SITE_NAME}</span>
</Link> </Link>

View File

@ -10,7 +10,7 @@ import Search from './search';
const { SITE_NAME } = process.env; const { SITE_NAME } = process.env;
export default async function Navbar() { export default async function Navbar() {
const menu = await getMenu('next-js-frontend-header-menu'); const menu = await getMenu('main-menu');
return ( return (
<nav className="relative flex items-center justify-between p-4 lg:px-6"> <nav className="relative flex items-center justify-between p-4 lg:px-6">

View File

@ -451,11 +451,13 @@ export async function revalidate(req: NextRequest): Promise<NextResponse> {
return NextResponse.json({ status: 200, revalidated: true, now: Date.now() }); return NextResponse.json({ status: 200, revalidated: true, now: Date.now() });
} }
export async function getDiscountMetaobjects() { export async function getDiscountMetaobjects(type: string) {
const res = await shopifyFetch<ShopifyDiscountMetaobjectsOperation>({ const res = await shopifyFetch<ShopifyDiscountMetaobjectsOperation>({
query: getDiscountMetaobjectsQuery, query: getDiscountMetaobjectsQuery,
cache: 'no-store' cache: 'no-store',
tags: ['metaobjects'],
variables: { type }
}); });
return res.body.data.metaobjects; return removeEdgesAndNodes(res.body.data.metaobjects);
} }

View File

@ -3,10 +3,12 @@ import discountMetaobject from '../fragments/discount-metaobject';
export const getDiscountMetaobjectsQuery = /* GraphQL */ ` export const getDiscountMetaobjectsQuery = /* GraphQL */ `
query getDiscountMetaobjects { query getDiscountMetaobjects {
metaobjects(type: "dynamic_discount", first: 10) { metaobjects(type: "dynamic_discount", first: 10) {
nodes { edges {
node {
...metaobject ...metaobject
} }
} }
} }
}
${discountMetaobject} ${discountMetaobject}
`; `;

View File

@ -61,7 +61,7 @@ export type Page = {
updatedAt: string; updatedAt: string;
}; };
type Field = { export type Field = {
key: string; key: string;
value: string; value: string;
}; };
@ -282,8 +282,6 @@ export type ShopifyDiscountMetaobjectsOperation = {
metaobjects: Connection<DiscountMetaobject>; metaobjects: Connection<DiscountMetaobject>;
}; };
variables: { variables: {
query?: string; type: string;
reverse?: boolean;
sortKey?: string;
}; };
}; };

View File

@ -1,4 +1,5 @@
import { ReadonlyURLSearchParams } from 'next/navigation'; import { ReadonlyURLSearchParams } from 'next/navigation';
import { DiscountMetaobject, Field } from './shopify/types';
export const createUrl = (pathname: string, params: URLSearchParams | ReadonlyURLSearchParams) => { export const createUrl = (pathname: string, params: URLSearchParams | ReadonlyURLSearchParams) => {
const paramsString = params.toString(); const paramsString = params.toString();
@ -37,3 +38,25 @@ export const validateEnvironmentVariables = () => {
); );
} }
}; };
export const formatDiscounts = (data: DiscountMetaobject[]) => {
const formattedData = data.map((item) => {
const fields = item.fields.reduce(
(acc, field: Field) => {
acc[field.key as string] = field.value;
return acc;
},
{} as Record<string, any>
);
return {
name: fields.name,
code: fields.discount_code,
discount: {
amount: parseFloat(fields.amount) / 100,
minimumSpent: parseFloat(fields.minimum_spent)
}
};
});
return formattedData;
};