Commit 37a17b24 by Ravindra Kanojiya

updated layout type

1 parent 1d1d2075
......@@ -33,6 +33,7 @@ function splitAfterParagraphs(html = "", count = 2) {
}
const AboutInfo = ({ productData }) => {
console.log("productData-333", productData)
const [expanded, setExpanded] = useState(false);
const { preview, rest } = splitAfterParagraphs(productData?.description, 2);
......@@ -40,7 +41,7 @@ const AboutInfo = ({ productData }) => {
return (
<>
<section className="about-section about-info-section pb-0">
<section className="about-section about-info-section">
<div className="custom_container container">
<Row className="text-center justify-content-center">
<Col md={8}>
......
......@@ -5,7 +5,7 @@ import Image from "next/image";
import { cleanImage } from "../services/imageHandling";
const CompanyOverview = ({ companyOverviewData }) => {
console.log(companyOverviewData,"companyOverviewData")
return (
<>
<section className="about-section about-info-section p-0">
......
......@@ -15,6 +15,7 @@ const galleryData = [
];
const Gallery = ({ productData }) => {
console.log(productData,"productData-gallery")
useEffect(() => {
Fancybox.bind("[data-fancybox='gallery']", {
......
import React, { useRef, useEffect, useState } from "react";
import Image from "next/image";
import { cleanImage } from "../services/imageHandling";
const Video = ({ productData }) => {
const mediaRef = useRef(null);
const videoRef = useRef(null);
const [isVisible, setIsVisible] = useState(false);
const media = productData?.video;
const isVideo = media?.mime?.startsWith("video/");
const isImage = media?.mime?.startsWith("image/");
// ✅ Strapi default image path
const defaultImage = "/image/default.svg";
// ✅ 1. Hide component if no video
if (!media?.url) return null;
useEffect(() => {
// ✅ 2. Guard for SSR (Next.js safety)
if (typeof window === "undefined") return;
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setIsVisible(true);
observer.unobserve(entry.target);
// ✅ Stop observing after first trigger
if (videoRef.current) {
observer.unobserve(videoRef.current);
}
}
},
{ threshold: 0.5 }
);
if (mediaRef.current) observer.observe(mediaRef.current);
if (videoRef.current) {
observer.observe(videoRef.current);
}
return () => {
if (mediaRef.current) observer.unobserve(mediaRef.current);
if (videoRef.current) {
observer.unobserve(videoRef.current);
}
};
}, []);
return (
<section className="video_sec">
<div className="custom_containers">
{/* VIDEO */}
{isVideo && (
<video
ref={mediaRef}
autoPlay
muted
loop
playsInline
className={`w-100 video-animate ${isVisible ? "video-visible" : ""}`}
>
<source src={cleanImage(media?.url)} type={media?.mime || "video/mp4"} />
</video>
)}
{/* IMAGE */}
{isImage && (
<div
ref={mediaRef}
className={`w-100 video-animate ${isVisible ? "video-visible" : ""}`}
>
<Image
src={cleanImage(media?.url)}
alt={media?.alternativeText || "Media"}
width={media?.width || 868}
height={media?.height || 560}
className="w-100"
/>
</div>
)}
{/* DEFAULT IMAGE */}
{!media && (
<div
ref={mediaRef}
className={`w-100 video-animate ${isVisible ? "video-visible" : ""}`}
>
<Image
src={cleanImage()}
alt="Default Image"
width={868}
height={560}
className="w-100"
/>
</div>
)}
<video
ref={videoRef}
autoPlay
muted
loop
playsInline
className={`w-100 video-animate ${
isVisible ? "video-visible" : ""
}`}
>
<source
src={cleanImage(media.url)}
type={media.mime || "video/mp4"}
/>
Your browser does not support the video tag.
</video>
</div>
</section>
);
......
import React, { useState } from "react";
import { Col, Row } from "react-bootstrap";
import Heading from "@/components/Heading";
import Link from "next/link";
/**
* Splits an HTML string into:
* - the first `count` <p>…</p> blocks
* - everything that comes after them
*/
function splitAfterParagraphs(html = "", count = 2) {
if (!html) return { preview: "", rest: "" };
// Match each <p …>…</p> block (handles multiline content)
const regex = /<p[\s\S]*?<\/p>/gi;
const matches = [];
let match;
while ((match = regex.exec(html)) !== null) {
matches.push({ start: match.index, end: match.index + match[0].length });
}
if (matches.length <= count) {
// Not enough paragraphs to hide anything
return { preview: html, rest: "" };
}
const splitIndex = matches[count - 1].end;
return {
preview: html.slice(0, splitIndex),
rest: html.slice(splitIndex),
};
}
const AboutInfo = ({ productData }) => {
const [expanded, setExpanded] = useState(false);
const { preview, rest } = splitAfterParagraphs(productData?.description, 2);
const hasMore = rest.trim().length > 0;
return (
<>
<section className="about-section about-info-section">
<div className="custom_container container">
<Row className="text-center justify-content-center">
<Col md={8}>
<Heading el="h2" heading={productData?.title || ""} isHtml />
{/* Always-visible first 2 paragraphs */}
<div
className="mb-0 gray-text"
dangerouslySetInnerHTML={{ __html: preview }}
/>
{/* Hidden/shown extra content */}
{hasMore && (
<>
<div className={`expandable-content ${expanded ? "expanded" : ""}`}>
<div className="inner-content">
<div
className="mb-0 gray-text"
dangerouslySetInnerHTML={{ __html: rest }}
/>
</div>
</div>
<Link
href="#!"
onClick={(e) => {
e.preventDefault();
setExpanded((prev) => !prev);
}}
className="btn4 mt-3"
>
{expanded ? "Read Less" : "Read More"} <i className="fa-solid fa-arrow-right"></i>
</Link>
</>
)}
</Col>
</Row>
</div>
</section>
<style jsx>{`
.expandable-content {
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows 0.4s ease-in-out;
}
.expandable-content .inner-content {
overflow: hidden;
}
.expandable-content.expanded {
grid-template-rows: 1fr;
}
`}</style>
</>
);
};
export default AboutInfo;
import React from 'react'
import { Col, Row } from 'react-bootstrap'
import { cleanImage } from '../services/imageHandling'
const DetailsData = [
{
title: "",
description: "Thanks to the special technology of Valcucine’s Artematica® door, composed of an anodized aluminum structural frame and an aesthetic panel just 5 mm thick, we are able to offer the lightest natural stone kitchen on the market. The integration of a composite honeycomb panel with carbon fiber also ensures its solidity, increasing resistance to impacts.",
image:"/image/stain-resistance/01.png",
},
{
title: "Continuity of veining",
description: "For all surfaces of natural stone kitchens, an acceptance check is carried out to ensure integrity and, for all adjacent faces, vein continuity where possible. This check is repeated at the end of all processing stages to ensure full conformity of the product shipped",
image:"/image/stain-resistance/02.png",
},
{
title: "Care in the handling of materials",
description: "All the materials in Valcucine, including the natural stone doors, from the moment they are received to the moment they are packed, are handled with the utmost care and with special surfaces that preserve their integrity and aesthetic qualities.",
image:"/image/stain-resistance/03.png",
},
{
title: "Packaging and shipping",
description: "To ensure integrity during each stage of handling and shipping. All natural stone tops and doors are packed with special protective cages made of wood or chipboard, depending on the destination. The doors are additionally protected with perimeter protection and wrapped in bubble wrap.",
image:"/image/stain-resistance/04.png",
},
]
const Details = ({DetailsItem,bottomInfo}) => {
return (
<>
<section className="about-section about-info-section">
<div className="container">
<Row className="justify-content-center">
<Col md={12}>
{DetailsItem?.map((item, index) => {
const isEven = index % 2 === 0;
return (
<div className='stain-Details-item'>
<div className='row' key={index}>
{/* Content */}
<div className={`col-md-5 ${!isEven ? 'order-md-2' : ''}`}>
<div className='stain-Details-content'>
<h3>{item.title}</h3>
<div dangerouslySetInnerHTML={{ __html: item?.description || "" }} />
</div>
</div>
{/* Image */}
<div className={`col-md-7 ${!isEven ? 'order-md-1' : ''}`}>
<div className='stain-Details-image'>
<img className='img-fluid' src={cleanImage(item?.image?.url)} alt={item?.title || ''} />
</div>
</div>
</div>
</div>
);
})}
</Col>
</Row>
</div>
</section>
<section className="about-section about-info-section pt-0 mt-0">
<div className="container">
<Row className="justify-content-center text-center">
<Col md={12}>
<div className='mb-2 text-transform-uppercase'><strong>{bottomInfo?.title}</strong></div>
<div dangerouslySetInnerHTML={{ __html: bottomInfo?.description }} />
</Col>
</Row>
</div>
</section>
</>
)
}
export default Details
\ No newline at end of file
import React from 'react'
import { Col, Row } from 'react-bootstrap'
import AboutInfo from './AboutInfo'
import Details from './Details'
const StoneFinishCabinet = ({ StoneFinishCabinet }) => {
console.log(StoneFinishCabinet, "StoneFinishCabinet")
return (
<>
<AboutInfo productData={StoneFinishCabinet?.aboutInfo} />
{StoneFinishCabinet?.detailsItem?.length > 0 && (
<Details
DetailsItem={StoneFinishCabinet.detailsItem}
bottomInfo={StoneFinishCabinet.bottomInfo}
/>
)}
</>
)
}
export default StoneFinishCabinet
\ No newline at end of file
......@@ -13,9 +13,10 @@ import TechnicalDetails from "@/components/Collection/TechnicalDetails";
import Explore from "@/components/Collection/Explore";
import { Tab, Tabs } from "react-bootstrap";
import { useEffect, useState } from "react";
import StoneFinishCabinet from "@/components/StoneFinishCabinet/StoneFinishCabinet";
const ProductPage = ({ productData, cataloguesData }) => {
console.log("productData-new", productData)
const router = useRouter();
const { category, subCategory: subCategorySlug, productSlug } = router.query;
......@@ -46,13 +47,20 @@ const ProductPage = ({ productData, cataloguesData }) => {
setActiveTab(productTabs[0].title);
}
}, [productTabs]);
const layoutType = productData?.LayoutsType;
const isDoorLayout =
layoutType === "Tabs Products" || layoutType === true;
const isStoneLayout =
layoutType === "Stone Finish Cabinet";
return (
<>
<Breadcrumb breadcrumbData={breadcrumbData} />
<InnerBannerproduct productData={productData} />
{productData?.isDoorAndPartitionsLayouts == true ? (
{isDoorLayout ? (
<section className="details-tab-section">
<div className="custom_containers">
<div className="details-tab">
......@@ -63,12 +71,8 @@ const ProductPage = ({ productData, cataloguesData }) => {
className="tab-01"
>
{productTabs?.map((tab) => (
<Tab
key={tab.id}
eventKey={tab.title}
title={tab.title}
>
<AboutInfo productData={tab?.aboutInfo} />
<Tab key={tab.id} eventKey={tab.title} title={tab.title}>
<AboutInfo productData={tab?.aboutInfo} />
<CompanyOverview
companyOverviewData={tab?.companyOverview?.items}
......@@ -89,24 +93,37 @@ const ProductPage = ({ productData, cataloguesData }) => {
</div>
</div>
</section>
) : (<>
) : (
<>
{
!isStoneLayout && <AboutInfo productData={productData?.aboutInfo} />
}
{productData?.aboutInfo?.length > 0 && (
<CompanyOverview companyOverviewData={productData?.companyOverview} />
)}
{isStoneLayout && (
<StoneFinishCabinet StoneFinishCabinet={productData?.aboutInfoStone} />
)}
{productData?.video && (
<Video productData={productData.video} />
)}
{productData?.technicalDetails?.length > 0 && (
<TechnicalDetails productData={productData?.technicalDetails} />
)}
{productData?.gallery?.length > 0 && (
<Gallery productData={productData?.gallery} />
)}
{/* <Explore productData={productData?.explore} /> */}
</>
)}
<AboutInfo productData={productData?.aboutInfo} />
<CompanyOverview companyOverviewData={productData?.companyOverview} />
<Video productData={productData?.video} />
{productData?.technicalDetails?.length > 0 && (
<TechnicalDetails productData={productData?.technicalDetails} />
{isDoorLayout && (
<Explore productData={productData.exploreProducts} />
)}
<Gallery productData={productData?.gallery} />
{/* <Explore productData={productData?.explore} /> */}
</>)}
{productData?.isDoorAndPartitionsLayouts && (
<Explore productData={productData?.exploreProducts} />
)}
{!productData?.isDoorAndPartitionsLayouts && (
{!isDoorLayout && (
<Catalogues cataloguesData={cataloguesData} />
)}
......@@ -128,8 +145,6 @@ const ProductPage = ({ productData, cataloguesData }) => {
<Gallery productData={productData?.gallery} />
)} */}
<Contact />
</>
);
......@@ -142,8 +157,6 @@ export async function getServerSideProps({ params }) {
try {
const { productSlug } = params;
const productData = await getCollectionDetailCategoryData(productSlug);
const cataloguesData = await getCataloguesBySlug();
......
......@@ -56,12 +56,19 @@ const SubCategoryOrProductPage = ({
setActiveTab(productTabs[0].title);
}
}, [productTabs]);
const layoutType = productData?.LayoutsType;
const isDoorLayout =
layoutType === "Tabs Products" || layoutType === true;
const isStoneLayout =
layoutType === "Stone Finish Cabinet";
return (
<>
<Breadcrumb breadcrumbData={breadcrumbData} />
<InnerBannerproduct productData={productData} />
{productData?.isDoorAndPartitionsLayouts == true ? (
{isDoorLayout ? (
<section className="details-tab-section">
<div className="custom_containers">
<div className="details-tab">
......@@ -73,8 +80,7 @@ const SubCategoryOrProductPage = ({
>
{productTabs?.map((tab) => (
<Tab key={tab.id} eventKey={tab.title} title={tab.title}>
<AboutInfo productData={tab?.aboutInfo} />
<AboutInfo productData={tab?.aboutInfo} />
<CompanyOverview
companyOverviewData={tab?.companyOverview?.items}
/>
......@@ -96,27 +102,35 @@ const SubCategoryOrProductPage = ({
</section>
) : (
<>
{/* {
productData?.aboutInfo?.length > 0 && (
<AboutInfo productData={productData?.aboutInfo} />
)
} */}
<AboutInfo productData={productData?.aboutInfo} />
<CompanyOverview
companyOverviewData={productData?.companyOverview}
/>
{/* <Video productData={productData?.video} /> */}
<Video productData={productData?.video} />
{isStoneLayout && (
<StoneFinishCabinet StoneFinishCabinet={productData?.aboutInfoStone} />
)}
{productData?.technicalDetails?.length > 0 && (
<TechnicalDetails productData={productData?.technicalDetails} />
)}
<Gallery productData={productData?.gallery} />
<Gallery productData={productData?.gallery} />
{/* <Explore productData={productData?.explore} /> */}
</>
)}
{productData?.isDoorAndPartitionsLayouts && (
<Explore productData={productData?.exploreProducts} />
{isDoorLayout && (
<Explore productData={productData.exploreProducts} />
)}
{!productData?.isDoorAndPartitionsLayouts && (
<Catalogues cataloguesData={cataloguesData} />
)}
{!isDoorLayout && (
<Catalogues cataloguesData={cataloguesData} />
)}
{/* {productData?.isDoorAndPartitionsLayouts === false && (
<AboutInfo productData={productData?.aboutInfo} />
......
......@@ -14,65 +14,77 @@ export async function getCollectionDetailCategoryData(productSlug) {
collection_sub_category: {
populate: true,
},
gallery: {
populate:{
image: true,
},
populate: {
image: true,
},
},
aboutInfo: {
populate:true
populate: true,
},
video: {
populate:{
video:true
}
populate: {
video: true,
},
},
exploreProducts:{
populate:{
item:{
populate:{
image:true
}
}
}
},
productTabs: {
populate: {
companyOverview: {
populate: {
items: {
populate:{
image:true
}
},
},
},
videoSection: {
exploreProducts: {
populate: {
video:true
}
item: {
populate: {
image: true,
},
},
},
},
aboutInfo: true,
technicalDetails: {
productTabs: {
populate: {
image: true,
details:true
companyOverview: {
populate: {
items: {
populate: {
image: true,
},
},
},
},
videoSection: {
populate: {
video: true,
},
},
aboutInfo: true,
technicalDetails: {
populate: {
image: true,
details: true,
},
},
gallery: {
populate: {
image: true,
},
},
},
},
gallery: {
aboutInfoStone: {
populate: {
image: true,
aboutInfo: {
populate: "*",
},
detailsItem: {
populate: "*",
},
bottomInfo: {
populate: "*",
},
},
},
},
},
// productTabs:{
// populate: "*",
// },
// technicalDetails:{
// populate:"*"
......@@ -85,7 +97,7 @@ export async function getCollectionDetailCategoryData(productSlug) {
const response = await fetchFromStrapi(
"/api/collection-detail-categories",
query
query,
);
return response?.data || [];
......
......@@ -1213,6 +1213,17 @@ footer a:hover {
width: 100%;
object-fit: cover;
}
.stain-Details-item{
background: #F5F5F5;
padding: 2rem;
margin-bottom: 2rem;
}
.stain-Details-content h3{
font-size: 1.04vw;
font-weight: 400;
color: #000;
padding-bottom: 0.2rem;
}
@media only screen and (max-width: 1023px) {
body {
......@@ -1320,6 +1331,13 @@ footer a:hover {
}
/* ===Media query==== */
@media (max-width: 767px) {
.about-section.about-info-section {
padding-bottom: 2rem;
padding-top: 2rem;
}
.stain-Details-content h3 {
font-size: 21px;
}
.we-care-section .img-banner img{
max-height: 300px;
}
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!