summaryrefslogtreecommitdiff
path: root/src-migrate/pages
diff options
context:
space:
mode:
Diffstat (limited to 'src-migrate/pages')
-rw-r--r--src-migrate/pages/shop/cart/cart.module.css14
-rw-r--r--src-migrate/pages/shop/cart/index.tsx15
-rw-r--r--src-migrate/pages/shop/product/[slug].tsx62
3 files changed, 51 insertions, 40 deletions
diff --git a/src-migrate/pages/shop/cart/cart.module.css b/src-migrate/pages/shop/cart/cart.module.css
index b756fb15..af5a2abc 100644
--- a/src-migrate/pages/shop/cart/cart.module.css
+++ b/src-migrate/pages/shop/cart/cart.module.css
@@ -3,7 +3,7 @@
}
.content {
- @apply flex flex-wrap ;
+ @apply flex flex-wrap;
}
.item-wrapper {
@@ -33,3 +33,15 @@
.summary-buttons-step-approval {
@apply grid grid-cols-1 gap-y-3 mt-6;
}
+
+@media (max-width: 768px) {
+ .item-wrapper {
+ /* adjust if your bar is taller/shorter */
+ padding-bottom: calc(env(safe-area-inset-bottom) + 9rem);
+ }
+
+ .summary-wrapper {
+ @apply fixed inset-x-0 bottom-0 z-50 md:sticky w-full;
+ }
+
+} \ No newline at end of file
diff --git a/src-migrate/pages/shop/cart/index.tsx b/src-migrate/pages/shop/cart/index.tsx
index 795dfa72..031aa45b 100644
--- a/src-migrate/pages/shop/cart/index.tsx
+++ b/src-migrate/pages/shop/cart/index.tsx
@@ -301,9 +301,8 @@ const CartPage: React.FC = () => {
<>
{/* Sticky Header */}
<div
- className={`${
- isTop ? 'border-b-[0px]' : 'border-b-[1px]'
- } sticky md:top-[157px] flex-col bg-white py-4 border-gray-300 z-50 sm:w-full md:w-3/4`}
+ className={`${isTop ? 'border-b-[0px]' : 'border-b-[1px]'
+ } sticky md:top-[157px] flex-col bg-white py-4 border-gray-300 z-50 sm:w-full md:w-3/4`}
>
<div className='flex items-center justify-between mb-2'>
<h1 className={style.title}>Keranjang Belanja</h1>
@@ -392,13 +391,17 @@ const CartPage: React.FC = () => {
</div>
</div>
+ <div
+ className="md:hidden"
+ style={{ height: 'calc(var(--mobile-actions-h) + var(--mobile-total-h))' }}
+ />
+
{/* Cart Summary */}
<div
- className={`${style['summary-wrapper']} ${
- device.isMobile && (!cart || cart?.product_total === 0)
+ className={`${style['summary-wrapper']} ${device.isMobile && (!cart || cart?.product_total === 0)
? 'hidden'
: ''
- }`}
+ }`}
>
<div className={style.summary}>
{device.isMobile ? (
diff --git a/src-migrate/pages/shop/product/[slug].tsx b/src-migrate/pages/shop/product/[slug].tsx
index fc72a6b0..90658544 100644
--- a/src-migrate/pages/shop/product/[slug].tsx
+++ b/src-migrate/pages/shop/product/[slug].tsx
@@ -18,34 +18,41 @@ type PageProps = {
product: IProductDetail
}
-export const getServerSideProps: GetServerSideProps<PageProps> = (async (context) => {
- const { slug } = context.query
+export const getServerSideProps: GetServerSideProps<PageProps & { canonicalPath: string }> = async (context) => {
+ const { slug } = context.query;
const cookieString = context.req.headers.cookie;
const cookies = cookieString ? cookie.parse(cookieString) : {};
const auth = cookies?.auth ? JSON.parse(cookies.auth) : {};
- const tier = auth?.pricelist || ''
+ const tier = auth?.pricelist || '';
- const productId = getIdFromSlug(slug as string)
+ const productId = getIdFromSlug(slug as string);
+ const product = await getProductById(productId, tier);
- const product = await getProductById(productId, tier)
+ // ❌ produk tidak ada → 404
+ if (!product) return { notFound: true };
- if (!product) return { notFound: true }
+ // ❌ tidak ada variants atau tidak ada yang harga > 0 → 404
+ const hasValidVariant = Array.isArray(product.variants)
+ && product.variants.some(v => (v?.price?.price ?? 0) > 0);
+ if (!hasValidVariant) return { notFound: true };
+
+ // Canonical path aman untuk SSR (hindari router.asPath di server)
+ const canonicalPath = context.resolvedUrl || `/product/${slug}`;
+
+ return { props: { product, canonicalPath } };
+};
- return {
- props: { product }
- }
-})
const SELF_HOST = process.env.NEXT_PUBLIC_SELF_HOST
-const ProductDetailPage: NextPage<PageProps> = ({ product }) => {
+const ProductDetailPage: NextPage<PageProps & { canonicalPath: string }> = ({ product, canonicalPath }) => {
const router = useRouter();
-
const { setProduct } = useProductContext();
- useEffect(() => {
- if (product) setProduct(product);
- }, [product, setProduct]);
+ useEffect(() => { if (product) setProduct(product); }, [product, setProduct]);
+
+ const origin = process.env.NEXT_PUBLIC_SELF_HOST || '';
+ const url = origin + (canonicalPath?.startsWith('/') ? canonicalPath : `/${canonicalPath}`);
return (
<BasicLayout>
@@ -53,31 +60,20 @@ const ProductDetailPage: NextPage<PageProps> = ({ product }) => {
title={`${product.name} - Indoteknik.com`}
description='Temukan pilihan produk B2B Industri &amp; Alat Teknik untuk Perusahaan, UMKM &amp; Pemerintah dengan lengkap, mudah dan transparan.'
openGraph={{
- url: SELF_HOST + router.asPath,
- images: [
- {
- url: product?.image,
- width: 800,
- height: 800,
- alt: product?.name,
- },
- ],
+ url,
+ images: [{ url: product?.image, width: 800, height: 800, alt: product?.name }],
type: 'product',
}}
- additionalMetaTags={[
- {
- name: 'keywords',
- content: `${product?.name}, Harga ${product?.name}, Beli ${product?.name}, Spesifikasi ${product?.name}`,
- }
- ]}
- canonical={SELF_HOST + router.asPath}
+ additionalMetaTags={[{ name: 'keywords', content: `${product?.name}, Harga ${product?.name}, Beli ${product?.name}, Spesifikasi ${product?.name}` }]}
+ canonical={url}
/>
<div className='md:container pt-4 md:pt-6'>
<ProductDetail product={product} />
</div>
</BasicLayout>
- )
-}
+ );
+};
+
export default ProductDetailPage \ No newline at end of file