feat: Add Landing Page CMS, enhance Navbar with Solutions dropdown, mobile sticky footer, and optimize homepage features visibility
This commit is contained in:
parent
32cc257c87
commit
85bc3359d7
|
|
@ -17,7 +17,7 @@
|
|||
<priority>0.8</priority>
|
||||
</url> -->
|
||||
<url>
|
||||
<loc>https://www.pozo.app/pricing-pozoapp</loc>
|
||||
<loc>https://www.pozo.app/pricing</loc>
|
||||
<lastmod>2025-10-13</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
ENV_BASE_URL='/'
|
||||
ENV_API_URL='http://192.168.1.37:8013'
|
||||
ENV_API_URL_TOKEN='http://192.168.1.37:8001'
|
||||
# ENV_API_URL_TOKEN='https://www.pozo.dev/JwtToken'
|
||||
# ENV_API_URL='https://www.pozo.dev/pozo-common-api'
|
||||
# ENV_API_URL='http://192.168.1.37:8013'
|
||||
# ENV_API_URL_TOKEN='http://192.168.1.37:8001'
|
||||
ENV_API_URL_TOKEN='https://www.pozo.dev/JwtToken'
|
||||
ENV_API_URL='https://www.pozo.dev/pozo-common-api'
|
||||
# ENV_IMAGE_UPLOAD_API_URL="https://api.pozo.app/pozo-common-image-api/"
|
||||
ENV_API_URL_RETAIL='http://192.168.1.37:8012/'
|
||||
# ENV_API_URL_TOKEN='https://api.pozo.app/JwtToken'
|
||||
|
|
|
|||
|
|
@ -1,31 +1,6 @@
|
|||
#221 server
|
||||
|
||||
# ENV_BASE_URL='/home/'
|
||||
# ENV_API_URL='http://api.pozo.co.in/Pozocommonapi_UnderTest'
|
||||
# # ENV_API_URL='http://api.pozo.co.in/Pozocommonapi'
|
||||
# ENV_IMAGE_UPLOAD_API_URL="https://api.pozo.app/pozo-common-image-api"
|
||||
# ENV_SECRET_KEY="3a939a2eed2cca4b64cd47f51b23b135b2b9b765273f695d47682ea803c8429d"
|
||||
# ENV_URL_SECRET_KEY="f2ef79b8b2d4fc1cc569726a5a753552257b4ff2872d6a71cf3119bce3f07c1b"
|
||||
# ENV_MAIN_BASE_URL='http://pozo.co.in/'
|
||||
# ENV_MAIN_REDIRECT_URL='/apps/retail/app-page/home'
|
||||
|
||||
# live server(#173 server)
|
||||
# ENV_BASE_URL='/home/'
|
||||
# ENV_API_URL_TOKEN='https://api.pozo.app/JwtToken'
|
||||
# ENV_API_URL='https://api.pozo.app/pozo-common-api'
|
||||
# ENV_IMAGE_UPLOAD_API_URL="https://api.pozo.app/pozo-common-image-api"
|
||||
# ENV_SECRET_KEY="3a939a2eed2cca4b64cd47f51b23b135b2b9b765273f695d47682ea803c8429d"
|
||||
# ENV_URL_SECRET_KEY="f2ef79b8b2d4fc1cc569726a5a753552257b4ff2872d6a71cf3119bce3f07c1b"
|
||||
# ENV_MAIN_BASE_URL='https://www.pozo.app'
|
||||
# ENV_MAIN_REDIRECT_URL='/apps/retail/app-page/home'
|
||||
# ENV_PAYMENT_URL='https://pozo.app/paymentgateway/PozoPaymentGateway'
|
||||
# ENV_CUSTOM_PAYMENT_URL='https://pozo.app/CustomPaymentGateway/CustomPaymentGateway'
|
||||
# ENV_EMAIL_API='https://api.pozo.app/pozo-sms-email-template-api'
|
||||
# ENV_API_URL_RETAIL='https://api.pozo.app/pozo-retail-api'
|
||||
|
||||
#172 server
|
||||
|
||||
ENV_BASE_URL='/home/'
|
||||
ENV_BASE_URL='/'
|
||||
ENV_API_URL_TOKEN='https://www.pozo.dev/JwtToken'
|
||||
ENV_API_URL='https://www.pozo.dev/pozo-common-api'
|
||||
ENV_API_URL_RETAIL='https://www.pozo.dev/pozo-retail-api'
|
||||
|
|
@ -37,5 +12,3 @@ ENV_MAIN_REDIRECT_URL='/apps/retail/app-page/home'
|
|||
ENV_PAYMENT_URL='https://pozo.app/paymentgateway/PozoPaymentGateway'
|
||||
ENV_CUSTOM_PAYMENT_URL='https://pozo.app/CustomPaymentGateway/CustomPaymentGateway'
|
||||
ENV_EMAIL_API='https://www.pozo.dev/pozo-sms-email-template-api'
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -811,3 +811,23 @@
|
|||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.filterAssDcc {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
button {
|
||||
width: max-content;
|
||||
padding: 8px 16px;
|
||||
border: none;
|
||||
font-family: "Poppins", sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
background-color: #e0ecff;
|
||||
color: #1e6ae4;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
23
src/App.jsx
23
src/App.jsx
|
|
@ -69,6 +69,7 @@ import { useEffect } from "react";
|
|||
import { checkSession, GenerateLogout } from "./features/signInPage/signInPage.js";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { clearSession, getSession } from "./Services/others.js";
|
||||
import { PostToken } from "./features/publicHome/publicHome.js";
|
||||
import LoyaltysettingList from "./Pages/LoyaltySetting/LoyaltysettingList.jsx"
|
||||
import LoyaltysettingsForm from "./Pages/LoyaltySetting/LoyaltysettingsForm.jsx"
|
||||
import ActivationkeyGeneration from "./Pages/ActivationkeyGeneration/ActivationkeyGeneration.jsx";
|
||||
|
|
@ -128,10 +129,28 @@ const App = () => {
|
|||
const navigate = useNavigate();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
// 🔑 Global token generation for direct URL access
|
||||
useEffect(() => {
|
||||
sessionCheckFun()
|
||||
const ensureToken = async () => {
|
||||
const existingToken = sessionStorage.getItem("auth");
|
||||
|
||||
}, [navigate]);
|
||||
if (!existingToken) {
|
||||
try {
|
||||
console.log("🔑 App: Generating global auth token...");
|
||||
await dispatch(PostToken({
|
||||
username: "1000000001",
|
||||
password: "1234"
|
||||
})).unwrap();
|
||||
console.log("✅ App: Token generated successfully");
|
||||
} catch (error) {
|
||||
console.error("❌ App: Token generation failed:", error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ensureToken();
|
||||
sessionCheckFun();
|
||||
}, [navigate, dispatch]);
|
||||
|
||||
const sessionCheckFun=async()=>{
|
||||
const UserId = getSession('UserId')
|
||||
|
|
|
|||
|
|
@ -0,0 +1,271 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import "./LandingPageCMS.scss";
|
||||
import {
|
||||
FaHome,
|
||||
FaHeading,
|
||||
FaImage,
|
||||
FaQuestionCircle,
|
||||
FaArrowLeft,
|
||||
FaSave,
|
||||
FaEye,
|
||||
FaLock,
|
||||
FaMoon,
|
||||
FaSun,
|
||||
FaBars,
|
||||
FaTimes
|
||||
} from "react-icons/fa";
|
||||
import { MdDashboard, MdEdit } from "react-icons/md";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { message } from "antd";
|
||||
import { getAdminPanel, postAdminPanel, putAdminPanel } from "../features/AdminPanel/AdminPanel";
|
||||
import { getSession } from "../Services/others";
|
||||
|
||||
// Section Components
|
||||
import HeroContentEditor from "./Sections/HeroContentEditor";
|
||||
import OfferingsEditor from "./Sections/OfferingsEditor";
|
||||
import FeaturesEditor from "./Sections/FeaturesEditor";
|
||||
import FAQEditor from "./Sections/FAQEditor";
|
||||
|
||||
const subDirectory = import.meta.env.ENV_BASE_URL;
|
||||
|
||||
const LandingPageCMS = () => {
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useDispatch();
|
||||
const [activeSection, setActiveSection] = useState("hero");
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [hasChanges, setHasChanges] = useState(false);
|
||||
const [isAuthorized, setIsAuthorized] = useState(false);
|
||||
const [isCheckingAuth, setIsCheckingAuth] = useState(true);
|
||||
const [isDarkMode, setIsDarkMode] = useState(true);
|
||||
const [isMobileSidebarOpen, setIsMobileSidebarOpen] = useState(false);
|
||||
|
||||
// Load theme preference from localStorage
|
||||
useEffect(() => {
|
||||
const savedTheme = localStorage.getItem("landing-cms-theme");
|
||||
if (savedTheme) {
|
||||
setIsDarkMode(savedTheme === "dark");
|
||||
}
|
||||
}, []);
|
||||
|
||||
const toggleTheme = () => {
|
||||
const newTheme = !isDarkMode;
|
||||
setIsDarkMode(newTheme);
|
||||
localStorage.setItem("landing-cms-theme", newTheme ? "dark" : "light");
|
||||
};
|
||||
|
||||
// 📱 Prevent body scroll when mobile sidebar is open
|
||||
useEffect(() => {
|
||||
if (isMobileSidebarOpen && window.innerWidth <= 900) {
|
||||
document.body.style.overflow = "hidden";
|
||||
} else {
|
||||
document.body.style.overflow = "";
|
||||
}
|
||||
return () => {
|
||||
document.body.style.overflow = "";
|
||||
};
|
||||
}, [isMobileSidebarOpen]);
|
||||
|
||||
// 🔒 Authentication Check
|
||||
useEffect(() => {
|
||||
const checkAuthentication = () => {
|
||||
const userType = getSession("UserType");
|
||||
const userId = getSession("UserId");
|
||||
const authToken = sessionStorage.getItem("auth");
|
||||
|
||||
// Allow only Marketing, Super Admin, or Admin
|
||||
const allowedUserTypes = ["Marketing", "Super Admin", "Admin", "Super Admin User"];
|
||||
|
||||
if (!authToken || !userId || !allowedUserTypes.includes(userType)) {
|
||||
message.error("Unauthorized access! Please login first.");
|
||||
navigate(`${subDirectory}signin`);
|
||||
return;
|
||||
}
|
||||
|
||||
setIsAuthorized(true);
|
||||
setIsCheckingAuth(false);
|
||||
};
|
||||
|
||||
checkAuthentication();
|
||||
}, [navigate]);
|
||||
|
||||
const sections = [
|
||||
{
|
||||
id: "hero",
|
||||
name: "Hero Section",
|
||||
icon: <FaHeading />,
|
||||
description: "Main headline, subtext, and CTA button",
|
||||
component: HeroContentEditor
|
||||
},
|
||||
{
|
||||
id: "offerings",
|
||||
name: "Offerings",
|
||||
icon: <FaImage />,
|
||||
description: "3 key features (Experience, Innovation, Cost)",
|
||||
component: OfferingsEditor
|
||||
},
|
||||
{
|
||||
id: "features",
|
||||
name: "Features",
|
||||
icon: <MdDashboard />,
|
||||
description: "Product features and benefits",
|
||||
component: FeaturesEditor
|
||||
},
|
||||
{
|
||||
id: "faq",
|
||||
name: "FAQ Section",
|
||||
icon: <FaQuestionCircle />,
|
||||
description: "Frequently asked questions",
|
||||
component: FAQEditor
|
||||
}
|
||||
];
|
||||
|
||||
const currentSection = sections.find(s => s.id === activeSection);
|
||||
const CurrentComponent = currentSection?.component;
|
||||
|
||||
const handlePreview = () => {
|
||||
window.open(`${subDirectory}`, '_blank');
|
||||
};
|
||||
|
||||
const handleSaveAll = async () => {
|
||||
setIsSaving(true);
|
||||
try {
|
||||
// Save logic will be implemented in each section component
|
||||
message.success("All changes saved successfully!");
|
||||
setHasChanges(false);
|
||||
} catch (error) {
|
||||
message.error("Failed to save changes");
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Show loading while checking auth
|
||||
if (isCheckingAuth) {
|
||||
return (
|
||||
<div className="landing-cms-auth-loading">
|
||||
<div className="auth-loading-spinner"></div>
|
||||
<p>Verifying access...</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Don't render if not authorized (will redirect)
|
||||
if (!isAuthorized) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`landing-cms-container ${isDarkMode ? 'dark-mode' : 'light-mode'}`}>
|
||||
{/* Top Header */}
|
||||
<div className="landing-cms-header">
|
||||
<div className="landing-cms-header-left">
|
||||
<button
|
||||
className="landing-cms-mobile-menu-btn"
|
||||
onClick={() => setIsMobileSidebarOpen(!isMobileSidebarOpen)}
|
||||
aria-label="Toggle mobile menu"
|
||||
>
|
||||
{isMobileSidebarOpen ? <FaTimes /> : <FaBars />}
|
||||
</button>
|
||||
<button
|
||||
className="landing-cms-back-btn"
|
||||
onClick={() => navigate(`${subDirectory}`)}
|
||||
>
|
||||
<FaArrowLeft /> <span>Back to Home</span>
|
||||
</button>
|
||||
<div className="landing-cms-title-section">
|
||||
<h1>Landing Page CMS</h1>
|
||||
<p>Manage your homepage content dynamically</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="landing-cms-header-right">
|
||||
<button
|
||||
className="landing-cms-theme-toggle"
|
||||
onClick={toggleTheme}
|
||||
aria-label={isDarkMode ? "Switch to Light Mode" : "Switch to Dark Mode"}
|
||||
title={isDarkMode ? "Switch to Light Mode" : "Switch to Dark Mode"}
|
||||
>
|
||||
{isDarkMode ? <FaSun /> : <FaMoon />}
|
||||
</button>
|
||||
<button
|
||||
className="landing-cms-preview-btn"
|
||||
onClick={handlePreview}
|
||||
>
|
||||
<FaEye /> <span>Preview</span>
|
||||
</button>
|
||||
<button
|
||||
className={`landing-cms-save-btn ${hasChanges ? 'has-changes' : ''}`}
|
||||
onClick={handleSaveAll}
|
||||
disabled={isSaving || !hasChanges}
|
||||
>
|
||||
<FaSave /> <span>{isSaving ? 'Saving...' : 'Save All Changes'}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="landing-cms-main">
|
||||
{/* Mobile Overlay */}
|
||||
{isMobileSidebarOpen && (
|
||||
<div
|
||||
className="landing-cms-mobile-overlay"
|
||||
onClick={() => setIsMobileSidebarOpen(false)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Sidebar Navigation */}
|
||||
<div className={`landing-cms-sidebar ${isMobileSidebarOpen ? 'mobile-open' : ''}`}>
|
||||
<div className="landing-cms-sidebar-header">
|
||||
<FaHome />
|
||||
<span>Content Sections</span>
|
||||
</div>
|
||||
<div className="landing-cms-nav-items">
|
||||
{sections.map((section) => (
|
||||
<button
|
||||
key={section.id}
|
||||
className={`landing-cms-nav-item ${activeSection === section.id ? 'active' : ''}`}
|
||||
onClick={() => {
|
||||
setActiveSection(section.id);
|
||||
setIsMobileSidebarOpen(false); // Close on mobile after selection
|
||||
}}
|
||||
>
|
||||
<div className="landing-cms-nav-icon">{section.icon}</div>
|
||||
<div className="landing-cms-nav-content">
|
||||
<div className="landing-cms-nav-title">{section.name}</div>
|
||||
<div className="landing-cms-nav-desc">{section.description}</div>
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content Area */}
|
||||
<div className="landing-cms-content">
|
||||
<div className="landing-cms-content-header">
|
||||
<div className="landing-cms-breadcrumb">
|
||||
<span>Landing Page</span>
|
||||
<span>/</span>
|
||||
<span>{currentSection?.name}</span>
|
||||
</div>
|
||||
{hasChanges && (
|
||||
<div className="landing-cms-unsaved-badge">
|
||||
Unsaved changes
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="landing-cms-content-body">
|
||||
{CurrentComponent && (
|
||||
<CurrentComponent
|
||||
onDataChange={() => setHasChanges(true)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LandingPageCMS;
|
||||
|
||||
|
|
@ -0,0 +1,627 @@
|
|||
// 🎨 Landing Page CMS - Clean Minimal Design
|
||||
|
||||
.landing-cms-container {
|
||||
min-height: 100vh;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||
transition: background 0.3s ease;
|
||||
|
||||
// Dark Mode
|
||||
&.dark-mode {
|
||||
background: #000;
|
||||
color: #e5e5e5;
|
||||
}
|
||||
|
||||
// Light Mode
|
||||
&.light-mode {
|
||||
background: #fafafa;
|
||||
color: #171717;
|
||||
}
|
||||
}
|
||||
|
||||
// Auth Loading
|
||||
.landing-cms-auth-loading {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
background: #000;
|
||||
|
||||
.auth-loading-spinner {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 2px solid #333;
|
||||
border-top-color: #fff;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.6s linear infinite;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 1rem;
|
||||
color: #888;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
// Header
|
||||
.landing-cms-header {
|
||||
padding: 1rem 1.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1002;
|
||||
|
||||
.dark-mode & {
|
||||
background: #111;
|
||||
border-color: #222;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
background: #fff;
|
||||
border-color: #e5e5e5;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
padding: 0.875rem 1rem;
|
||||
}
|
||||
|
||||
.landing-cms-header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.landing-cms-mobile-menu-btn {
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: transparent;
|
||||
border: 1px solid;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
font-size: 18px;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
flex-shrink: 0;
|
||||
|
||||
.dark-mode & {
|
||||
border-color: #333;
|
||||
color: #e5e5e5;
|
||||
|
||||
&:hover, &:active {
|
||||
border-color: #0ea5e9;
|
||||
background: #1a1a1a;
|
||||
color: #0ea5e9;
|
||||
}
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
border-color: #d4d4d4;
|
||||
color: #171717;
|
||||
|
||||
&:hover, &:active {
|
||||
border-color: #0969da;
|
||||
background: #f5f5f5;
|
||||
color: #0969da;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.landing-cms-back-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem 1rem;
|
||||
background: transparent;
|
||||
border: 1px solid;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
font-family: inherit;
|
||||
|
||||
.dark-mode & {
|
||||
border-color: #333;
|
||||
color: #e5e5e5;
|
||||
|
||||
&:hover {
|
||||
border-color: #666;
|
||||
background: #1a1a1a;
|
||||
}
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
border-color: #d4d4d4;
|
||||
color: #171717;
|
||||
|
||||
&:hover {
|
||||
border-color: #999;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
padding: 0.5rem 0.75rem;
|
||||
|
||||
span {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.landing-cms-title-section h1 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
|
||||
.dark-mode & {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.landing-cms-title-section p {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.landing-cms-header-right {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.landing-cms-theme-toggle {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: transparent;
|
||||
border: 1px solid;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
font-size: 18px;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
flex-shrink: 0;
|
||||
|
||||
.dark-mode & {
|
||||
border-color: #333;
|
||||
color: #fbbf24;
|
||||
|
||||
&:hover, &:active {
|
||||
border-color: #fbbf24;
|
||||
background: #1a1a1a;
|
||||
}
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
border-color: #d4d4d4;
|
||||
color: #f59e0b;
|
||||
|
||||
&:hover, &:active {
|
||||
border-color: #f59e0b;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.landing-cms-preview-btn,
|
||||
.landing-cms-save-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.625rem 1.25rem;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
font-family: inherit;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
padding: 0.625rem 0.875rem;
|
||||
|
||||
span {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.landing-cms-preview-btn {
|
||||
background: transparent;
|
||||
border: 1px solid;
|
||||
|
||||
.dark-mode & {
|
||||
border-color: #333;
|
||||
color: #e5e5e5;
|
||||
|
||||
&:hover {
|
||||
border-color: #666;
|
||||
background: #1a1a1a;
|
||||
}
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
border-color: #d4d4d4;
|
||||
color: #171717;
|
||||
|
||||
&:hover {
|
||||
border-color: #999;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.landing-cms-save-btn {
|
||||
border: none;
|
||||
|
||||
.dark-mode & {
|
||||
background: #fff;
|
||||
color: #000;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
background: #e5e5e5;
|
||||
}
|
||||
|
||||
&.has-changes {
|
||||
background: #10b981;
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
background: #059669;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
background: #000;
|
||||
color: #fff;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
background: #333;
|
||||
}
|
||||
|
||||
&.has-changes {
|
||||
background: #10b981;
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
background: #059669;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Main
|
||||
.landing-cms-main {
|
||||
display: flex;
|
||||
min-height: calc(100vh - 60px);
|
||||
|
||||
@media (max-width: 900px) {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
// Sidebar
|
||||
.landing-cms-sidebar {
|
||||
width: 280px;
|
||||
padding: 1.5rem 0;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
border-right: 1px solid;
|
||||
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
.dark-mode & {
|
||||
background: #111;
|
||||
border-color: #222;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
background: #fff;
|
||||
border-color: #e5e5e5;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
position: fixed !important;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 1001 !important;
|
||||
transform: translateX(-100%);
|
||||
box-shadow: 4px 0 24px rgba(0, 0, 0, 0.6);
|
||||
padding-top: 70px;
|
||||
width: 85%;
|
||||
max-width: 320px;
|
||||
|
||||
&.mobile-open {
|
||||
transform: translateX(0) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.landing-cms-sidebar-header {
|
||||
padding: 0 1.25rem 1rem;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
.dark-mode & {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
svg {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.landing-cms-nav-items {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.375rem;
|
||||
padding: 0 0.75rem;
|
||||
}
|
||||
|
||||
.landing-cms-nav-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 0.875rem 1rem;
|
||||
background: transparent;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
text-align: left;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
user-select: none;
|
||||
|
||||
@media (max-width: 900px) {
|
||||
padding: 1rem 1.25rem;
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
.landing-cms-nav-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
font-size: 20px;
|
||||
flex-shrink: 0;
|
||||
transition: color 0.2s;
|
||||
|
||||
.dark-mode & {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.landing-cms-nav-content {
|
||||
flex: 1;
|
||||
|
||||
.landing-cms-nav-title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 0.25rem;
|
||||
transition: color 0.2s;
|
||||
|
||||
.dark-mode & {
|
||||
color: #e5e5e5;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
color: #171717;
|
||||
}
|
||||
}
|
||||
|
||||
.landing-cms-nav-desc {
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
|
||||
.dark-mode & {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dark-mode &:hover {
|
||||
background: #1a1a1a;
|
||||
border-color: #333;
|
||||
}
|
||||
|
||||
.light-mode &:hover {
|
||||
background: #f5f5f5;
|
||||
border-color: #e5e5e5;
|
||||
}
|
||||
|
||||
&.active {
|
||||
.dark-mode & {
|
||||
background: #1a1a1a;
|
||||
border-color: #0ea5e9;
|
||||
|
||||
.landing-cms-nav-icon {
|
||||
color: #10b981;
|
||||
}
|
||||
|
||||
.landing-cms-nav-title {
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
background: #f0f9ff;
|
||||
border-color: #0ea5e9;
|
||||
|
||||
.landing-cms-nav-icon {
|
||||
color: #10b981;
|
||||
}
|
||||
|
||||
.landing-cms-nav-title {
|
||||
color: #000;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.landing-cms-nav-desc {
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mobile Overlay
|
||||
.landing-cms-mobile-overlay {
|
||||
display: none;
|
||||
|
||||
@media (max-width: 900px) {
|
||||
display: block;
|
||||
position: fixed !important;
|
||||
inset: 0;
|
||||
top: 0;
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
z-index: 1000 !important;
|
||||
animation: fadeIn 0.25s ease;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
// Content
|
||||
.landing-cms-content {
|
||||
flex: 1;
|
||||
padding: 2rem 2.5rem;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
.dark-mode & {
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
padding: 1.5rem 1rem;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.landing-cms-content-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 2rem;
|
||||
|
||||
.landing-cms-breadcrumb {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 12px;
|
||||
|
||||
.dark-mode & {
|
||||
color: #888;
|
||||
|
||||
span:last-child {
|
||||
color: #e5e5e5;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
color: #999;
|
||||
|
||||
span:last-child {
|
||||
color: #171717;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.landing-cms-unsaved-badge {
|
||||
padding: 0.375rem 0.875rem;
|
||||
background: #fbbf24;
|
||||
color: #000;
|
||||
border-radius: 16px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.landing-cms-content-body {
|
||||
border-radius: 8px;
|
||||
padding: 2.5rem;
|
||||
border: 1px solid;
|
||||
|
||||
.dark-mode & {
|
||||
background: #111;
|
||||
border-color: #222;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
background: #fff;
|
||||
border-color: #e5e5e5;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import React from "react";
|
||||
import "./SectionEditor.scss";
|
||||
import { FaQuestionCircle } from "react-icons/fa";
|
||||
|
||||
const FAQEditor = ({ onDataChange }) => {
|
||||
return (
|
||||
<div className="section-editor">
|
||||
<div className="section-editor-header">
|
||||
<div className="section-editor-icon">
|
||||
<FaQuestionCircle />
|
||||
</div>
|
||||
<div>
|
||||
<h2>FAQ Section</h2>
|
||||
<p>Manage frequently asked questions (Coming Soon)</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="info-box">
|
||||
<strong>Coming Soon:</strong>
|
||||
FAQ editor will allow you to add, edit, and organize frequently asked questions.
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FAQEditor;
|
||||
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import React from "react";
|
||||
import "./SectionEditor.scss";
|
||||
import { MdDashboard } from "react-icons/md";
|
||||
|
||||
const FeaturesEditor = ({ onDataChange }) => {
|
||||
return (
|
||||
<div className="section-editor">
|
||||
<div className="section-editor-header">
|
||||
<div className="section-editor-icon">
|
||||
<MdDashboard />
|
||||
</div>
|
||||
<div>
|
||||
<h2>Features Section</h2>
|
||||
<p>Manage product features and benefits (Coming Soon)</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="info-box">
|
||||
<strong>Coming Soon:</strong>
|
||||
Features editor will allow you to manage the product features section dynamically.
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FeaturesEditor;
|
||||
|
||||
|
|
@ -0,0 +1,216 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { message } from "antd";
|
||||
import { getAdminPanel, postAdminPanel, putAdminPanel } from "../../features/AdminPanel/AdminPanel";
|
||||
import "./SectionEditor.scss";
|
||||
import { FaRegLightbulb, FaSave } from "react-icons/fa";
|
||||
import { MdTitle, MdDescription } from "react-icons/md";
|
||||
|
||||
const HeroContentEditor = ({ onDataChange }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
// Form fields
|
||||
const [mainHeadline, setMainHeadline] = useState("Retail ERP & POS built for Indian MSMEs — fast billing, smart inventory, GST-ready.");
|
||||
const [description, setDescription] = useState("A SaaS platform that empowers Small and Medium Businesses by digitizing operations and reducing Total Cost of Ownership with minimal investment.");
|
||||
const [ctaButtonText, setCtaButtonText] = useState("Experience Now");
|
||||
const [ctaButtonLink, setCtaButtonLink] = useState("/signin");
|
||||
|
||||
useEffect(() => {
|
||||
fetchHeroData();
|
||||
}, []);
|
||||
|
||||
const fetchHeroData = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const res = await dispatch(
|
||||
getAdminPanel({ sectionName: "HeroSection" })
|
||||
).unwrap();
|
||||
|
||||
if (res?.data?.statusCode === 1 && res?.data?.data?.length > 0) {
|
||||
const heroData = res.data.data[0];
|
||||
if (heroData.Content) {
|
||||
const content = JSON.parse(heroData.Content);
|
||||
setMainHeadline(content.mainHeadline || mainHeadline);
|
||||
setDescription(content.description || description);
|
||||
setCtaButtonText(content.ctaButtonText || ctaButtonText);
|
||||
setCtaButtonLink(content.ctaButtonLink || ctaButtonLink);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("No existing hero data, using defaults");
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSave = async () => {
|
||||
if (!mainHeadline.trim() || !description.trim()) {
|
||||
message.error("Headline and description are required!");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setIsSaving(true);
|
||||
|
||||
const data = {
|
||||
SectionName: "HeroSection",
|
||||
Content: JSON.stringify({
|
||||
mainHeadline: mainHeadline.trim(),
|
||||
description: description.trim(),
|
||||
ctaButtonText: ctaButtonText.trim(),
|
||||
ctaButtonLink: ctaButtonLink.trim()
|
||||
}),
|
||||
ActiveStatus: "A",
|
||||
CreatedBy: 1,
|
||||
ModifiedBy: 1
|
||||
};
|
||||
|
||||
await dispatch(postAdminPanel(data)).unwrap();
|
||||
message.success("Hero section saved successfully!");
|
||||
onDataChange?.();
|
||||
} catch (error) {
|
||||
console.error("Save error:", error);
|
||||
message.error("Failed to save. Please try again.");
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="section-editor-loading">
|
||||
<div className="loading-spinner"></div>
|
||||
<p>Loading hero section...</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="section-editor">
|
||||
<div className="section-editor-header">
|
||||
<div className="section-editor-icon">
|
||||
<MdTitle />
|
||||
</div>
|
||||
<div>
|
||||
<h2>Hero Section Content</h2>
|
||||
<p>Manage the main headline, description, and CTA button on your landing page</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="section-editor-form">
|
||||
{/* Main Headline */}
|
||||
<div className="form-group">
|
||||
<label htmlFor="mainHeadline">
|
||||
Main Headline
|
||||
<span className="label-hint">First thing visitors see</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="mainHeadline"
|
||||
value={mainHeadline}
|
||||
onChange={(e) => {
|
||||
setMainHeadline(e.target.value);
|
||||
onDataChange?.();
|
||||
}}
|
||||
placeholder="Enter main headline (press Enter for new line)"
|
||||
rows={4}
|
||||
className="form-textarea headline-input"
|
||||
/>
|
||||
<div className="input-help">
|
||||
Tip: Press Enter to add line breaks
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Description */}
|
||||
<div className="form-group">
|
||||
<label htmlFor="description">
|
||||
Description
|
||||
<span className="label-hint">Supporting text</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="description"
|
||||
value={description}
|
||||
onChange={(e) => {
|
||||
setDescription(e.target.value);
|
||||
onDataChange?.();
|
||||
}}
|
||||
placeholder="Enter description"
|
||||
rows={3}
|
||||
className="form-textarea"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* CTA Button */}
|
||||
<div className="form-row">
|
||||
<div className="form-group">
|
||||
<label htmlFor="ctaButtonText">Button Text</label>
|
||||
<input
|
||||
type="text"
|
||||
id="ctaButtonText"
|
||||
value={ctaButtonText}
|
||||
onChange={(e) => {
|
||||
setCtaButtonText(e.target.value);
|
||||
onDataChange?.();
|
||||
}}
|
||||
placeholder="e.g., Get Started"
|
||||
className="form-input"
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label htmlFor="ctaButtonLink">Button Link</label>
|
||||
<input
|
||||
type="text"
|
||||
id="ctaButtonLink"
|
||||
value={ctaButtonLink}
|
||||
onChange={(e) => {
|
||||
setCtaButtonLink(e.target.value);
|
||||
onDataChange?.();
|
||||
}}
|
||||
placeholder="e.g., /signin"
|
||||
className="form-input"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Single Combined Preview */}
|
||||
<div className="form-group">
|
||||
<label>Live Preview</label>
|
||||
<div className="input-preview">
|
||||
<div className="preview-text headline-preview">
|
||||
{mainHeadline.split('\n').map((line, i) => (
|
||||
<React.Fragment key={i}>
|
||||
{line}
|
||||
{i < mainHeadline.split('\n').length - 1 && <br />}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
<div className="preview-text" style={{ marginTop: '1rem', fontSize: '14px', color: '#666' }}>
|
||||
{description}
|
||||
</div>
|
||||
<div className="button-preview">
|
||||
<button className="preview-cta-btn">
|
||||
{ctaButtonText}
|
||||
<div className="preview-icon">→</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Save Button */}
|
||||
<div className="section-editor-actions">
|
||||
<button
|
||||
onClick={handleSave}
|
||||
disabled={isSaving}
|
||||
className="save-section-btn"
|
||||
>
|
||||
<FaSave /> {isSaving ? "Saving..." : "Save Changes"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default HeroContentEditor;
|
||||
|
||||
|
|
@ -0,0 +1,212 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { message } from "antd";
|
||||
import { getAdminPanel, postAdminPanel } from "../../features/AdminPanel/AdminPanel";
|
||||
import "./SectionEditor.scss";
|
||||
import { FaSave, FaLightbulb, FaCog, FaDollarSign } from "react-icons/fa";
|
||||
import { MdStar } from "react-icons/md";
|
||||
|
||||
const OfferingsEditor = ({ onDataChange }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
const defaultOfferings = [
|
||||
{
|
||||
id: 1,
|
||||
title: "Experience",
|
||||
description: "Proven expertise delivering real value",
|
||||
icon: "experience"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Innovation",
|
||||
description: "Smarter intelligence for better outcomes",
|
||||
icon: "innovation"
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "Cost Efficiency",
|
||||
description: "Maximum value with minimal cost",
|
||||
icon: "cost"
|
||||
}
|
||||
];
|
||||
|
||||
const [offerings, setOfferings] = useState(defaultOfferings);
|
||||
|
||||
useEffect(() => {
|
||||
fetchOfferingsData();
|
||||
}, []);
|
||||
|
||||
const fetchOfferingsData = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const res = await dispatch(
|
||||
getAdminPanel({ sectionName: "Offerings" })
|
||||
).unwrap();
|
||||
|
||||
if (res?.data?.statusCode === 1 && res?.data?.data?.length > 0) {
|
||||
const offeringsData = res.data.data[0];
|
||||
if (offeringsData.Content) {
|
||||
const content = JSON.parse(offeringsData.Content);
|
||||
setOfferings(content.offerings || defaultOfferings);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("No existing offerings data, using defaults");
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleOfferingChange = (id, field, value) => {
|
||||
setOfferings(offerings.map(offering =>
|
||||
offering.id === id ? { ...offering, [field]: value } : offering
|
||||
));
|
||||
onDataChange?.();
|
||||
};
|
||||
|
||||
const handleSave = async () => {
|
||||
// Validation
|
||||
for (const offering of offerings) {
|
||||
if (!offering.title.trim() || !offering.description.trim()) {
|
||||
message.error(`Please fill all fields for ${offering.title || 'offering'}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
setIsSaving(true);
|
||||
|
||||
const data = {
|
||||
SectionName: "Offerings",
|
||||
Content: JSON.stringify({
|
||||
offerings: offerings.map(o => ({
|
||||
id: o.id,
|
||||
title: o.title.trim(),
|
||||
description: o.description.trim(),
|
||||
icon: o.icon
|
||||
}))
|
||||
}),
|
||||
ActiveStatus: "A",
|
||||
CreatedBy: 1,
|
||||
ModifiedBy: 1
|
||||
};
|
||||
|
||||
await dispatch(postAdminPanel(data)).unwrap();
|
||||
message.success("Offerings saved successfully!");
|
||||
onDataChange?.();
|
||||
} catch (error) {
|
||||
console.error("Save error:", error);
|
||||
message.error("Failed to save. Please try again.");
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
const getIconComponent = (iconName) => {
|
||||
switch(iconName) {
|
||||
case "experience": return <MdStar />;
|
||||
case "innovation": return <FaCog />;
|
||||
case "cost": return <FaDollarSign />;
|
||||
default: return <FaLightbulb />;
|
||||
}
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="section-editor-loading">
|
||||
<div className="loading-spinner"></div>
|
||||
<p>Loading offerings...</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="section-editor">
|
||||
<div className="section-editor-header">
|
||||
<div className="section-editor-icon">
|
||||
<FaLightbulb />
|
||||
</div>
|
||||
<div>
|
||||
<h2>Offerings Section</h2>
|
||||
<p>Manage the 3 key value propositions displayed on your landing page</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="info-box">
|
||||
<strong>About Offerings:</strong>
|
||||
These 3 features appear below the main headline showing your key value propositions:
|
||||
Experience, Innovation, and Cost Efficiency.
|
||||
</div>
|
||||
|
||||
<div className="section-editor-form">
|
||||
{offerings.map((offering, index) => (
|
||||
<div key={offering.id} className="offering-card">
|
||||
<div className="offering-card-header">
|
||||
<div className="offering-icon-preview">
|
||||
{getIconComponent(offering.icon)}
|
||||
</div>
|
||||
<h3>Offering {index + 1}</h3>
|
||||
</div>
|
||||
|
||||
<div className="form-row">
|
||||
<div className="form-group">
|
||||
<label htmlFor={`title-${offering.id}`}>Title</label>
|
||||
<input
|
||||
type="text"
|
||||
id={`title-${offering.id}`}
|
||||
value={offering.title}
|
||||
onChange={(e) => handleOfferingChange(offering.id, 'title', e.target.value)}
|
||||
placeholder="e.g., Experience, Innovation"
|
||||
className="form-input"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label htmlFor={`icon-${offering.id}`}>Icon Type</label>
|
||||
<select
|
||||
id={`icon-${offering.id}`}
|
||||
value={offering.icon}
|
||||
onChange={(e) => handleOfferingChange(offering.id, 'icon', e.target.value)}
|
||||
className="form-input"
|
||||
>
|
||||
<option value="experience">Experience (Star)</option>
|
||||
<option value="innovation">Innovation (Cog)</option>
|
||||
<option value="cost">Cost (Dollar)</option>
|
||||
<option value="lightbulb">Light Bulb</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label htmlFor={`desc-${offering.id}`}>Description</label>
|
||||
<textarea
|
||||
id={`desc-${offering.id}`}
|
||||
value={offering.description}
|
||||
onChange={(e) => handleOfferingChange(offering.id, 'description', e.target.value)}
|
||||
placeholder="Brief description of this offering"
|
||||
rows={2}
|
||||
className="form-textarea"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Save Button */}
|
||||
<div className="section-editor-actions">
|
||||
<button
|
||||
onClick={handleSave}
|
||||
disabled={isSaving}
|
||||
className="save-section-btn"
|
||||
>
|
||||
<FaSave /> {isSaving ? "Saving..." : "Save Offerings"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default OfferingsEditor;
|
||||
|
||||
|
|
@ -0,0 +1,494 @@
|
|||
// Section Editor - Clean & Simple
|
||||
|
||||
.section-editor {
|
||||
max-width: 720px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.section-editor-header {
|
||||
margin-bottom: 2.5rem;
|
||||
|
||||
.section-editor-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
|
||||
.dark-mode & {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
|
||||
.dark-mode & {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.section-editor-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
// Form Group
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.625rem;
|
||||
|
||||
label {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
|
||||
.dark-mode & {
|
||||
color: #e5e5e5;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
color: #171717;
|
||||
}
|
||||
|
||||
svg {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.label-hint {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
|
||||
.dark-mode & {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1.5rem;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
// Inputs
|
||||
.form-input,
|
||||
.form-textarea {
|
||||
width: 100%;
|
||||
padding: 0.875rem 1rem;
|
||||
border: 1px solid;
|
||||
border-radius: 6px;
|
||||
font-size: 15px;
|
||||
font-family: inherit;
|
||||
transition: all 0.2s;
|
||||
|
||||
.dark-mode & {
|
||||
background: #000;
|
||||
border-color: #333;
|
||||
color: #e5e5e5;
|
||||
|
||||
&::placeholder {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: #444;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: #0ea5e9;
|
||||
background: #0a0a0a;
|
||||
}
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
background: #fafafa;
|
||||
border-color: #d4d4d4;
|
||||
color: #000;
|
||||
|
||||
&::placeholder {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: #999;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: #0ea5e9;
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&.error {
|
||||
border-color: #ef4444 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.form-textarea {
|
||||
resize: vertical;
|
||||
min-height: 100px;
|
||||
line-height: 1.6;
|
||||
|
||||
&.headline-input {
|
||||
font-size: 17px;
|
||||
font-weight: 600;
|
||||
min-height: 130px;
|
||||
}
|
||||
}
|
||||
|
||||
// Help
|
||||
.input-help {
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
|
||||
.dark-mode & {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
// Preview - Single Combined
|
||||
.input-preview {
|
||||
margin-top: 1.5rem;
|
||||
padding: 2.5rem;
|
||||
border: 1px solid;
|
||||
border-radius: 8px;
|
||||
|
||||
.dark-mode & {
|
||||
background: #0a0a0a;
|
||||
border-color: #222;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
background: #f5f5f5;
|
||||
border-color: #e5e5e5;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
padding: 1.75rem;
|
||||
}
|
||||
|
||||
strong {
|
||||
display: block;
|
||||
font-size: 11px;
|
||||
margin-bottom: 1.5rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
font-weight: 600;
|
||||
|
||||
.dark-mode & {
|
||||
color: #0ea5e9;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
color: #0969da;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-text {
|
||||
font-size: 15px;
|
||||
line-height: 1.7;
|
||||
|
||||
.dark-mode & {
|
||||
color: #cbd5e1;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
&.headline-preview {
|
||||
font-size: 40px;
|
||||
font-weight: 700;
|
||||
line-height: 1.15;
|
||||
margin-bottom: 1.25rem;
|
||||
letter-spacing: -1px;
|
||||
|
||||
.dark-mode & {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
font-size: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.button-preview {
|
||||
margin-top: 2rem;
|
||||
|
||||
.preview-cta-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem 2rem;
|
||||
background: #10b981;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
font-family: inherit;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
padding: 0.875rem 1.75rem;
|
||||
}
|
||||
|
||||
.preview-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: #059669;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Actions
|
||||
.section-editor-actions {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
padding-top: 2rem;
|
||||
border-top: 1px solid;
|
||||
|
||||
.dark-mode & {
|
||||
border-color: #222;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
border-color: #e5e5e5;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.save-section-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.625rem;
|
||||
padding: 1rem 2.5rem;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
font-family: inherit;
|
||||
|
||||
.dark-mode & {
|
||||
background: #0ea5e9;
|
||||
color: #fff;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
background: #0284c7;
|
||||
}
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
background: #0969da;
|
||||
color: #fff;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
background: #0550ae;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
svg {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
// Loading
|
||||
.section-editor-loading {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 450px;
|
||||
|
||||
.loading-spinner {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 2px solid;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.6s linear infinite;
|
||||
|
||||
.dark-mode & {
|
||||
border-color: #333;
|
||||
border-top-color: #0ea5e9;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
border-color: #e5e5e5;
|
||||
border-top-color: #0969da;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 1rem;
|
||||
font-size: 13px;
|
||||
|
||||
.dark-mode & {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Info Box
|
||||
.info-box {
|
||||
padding: 1.125rem 1.375rem;
|
||||
border-left: 3px solid;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
|
||||
.dark-mode & {
|
||||
background: rgba(14, 165, 233, 0.1);
|
||||
border-color: #0ea5e9;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
background: rgba(9, 105, 218, 0.05);
|
||||
border-color: #0969da;
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
strong {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
|
||||
.dark-mode & {
|
||||
color: #0ea5e9;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
color: #0969da;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Offering Cards
|
||||
.offering-card {
|
||||
padding: 1.75rem;
|
||||
border: 1px solid;
|
||||
border-radius: 8px;
|
||||
transition: all 0.2s;
|
||||
|
||||
.dark-mode & {
|
||||
background: #0a0a0a;
|
||||
border-color: #333;
|
||||
|
||||
&:hover {
|
||||
border-color: #0ea5e9;
|
||||
background: #0f0f0f;
|
||||
}
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
background: #fafafa;
|
||||
border-color: #d4d4d4;
|
||||
|
||||
&:hover {
|
||||
border-color: #0969da;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.offering-card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
|
||||
.offering-icon-preview {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
background: #10b981;
|
||||
border-radius: 6px;
|
||||
color: #fff;
|
||||
font-size: 22px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
|
||||
.dark-mode & {
|
||||
color: #e5e5e5;
|
||||
}
|
||||
|
||||
.light-mode & {
|
||||
color: #171717;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
select.form-input {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
@ -95,7 +95,6 @@ const ApplicationForm = ({ formType }) => {
|
|||
postData["AppURLType"] = SelectedCategory == categoryData?.filter(item => item?.ConfigName == "Retail")[0]?.ConfigId ? 'I' : 'E';;
|
||||
postData["AppLogo"] = imageUrl;
|
||||
postData["AppName"] = values.AppName;
|
||||
postData["NavigationURL"] = values.NavigationURL;
|
||||
postData["AppURL"] = SelectedCategory == categoryData?.filter(item => item?.ConfigName == "Retail")[0]?.ConfigId ? URLToggle ? homepageurl : values.AppURL : values.AppURL;
|
||||
postData["CateId"] = values.CateId;
|
||||
postData["CreatedBy"] = getSession('UserId')
|
||||
|
|
@ -328,31 +327,7 @@ const ApplicationForm = ({ formType }) => {
|
|||
/>
|
||||
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="NavigationURL"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
pattern: /^(?!\s*$).+/,
|
||||
message: "Please Enter Navigation URL",
|
||||
},
|
||||
{
|
||||
validator: async (_, value) => {
|
||||
await validateSafeInput(value);
|
||||
return Promise.resolve();
|
||||
},
|
||||
},
|
||||
]}>
|
||||
<InputField
|
||||
field="NavigationURL"
|
||||
autoComplete="off"
|
||||
label={<label className="required">Navigation URL</label>}
|
||||
fieldState={true}
|
||||
fieldApi={true}
|
||||
isOnChange={formType == "edit" ? true : false}
|
||||
defaultValue={editstate?.NavigationURL}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
|
||||
<div className="upload_btn">
|
||||
<p>Upload Logo</p>
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ const AllTemplates = () => {
|
|||
{/* <nav 1 */}
|
||||
|
||||
{templateData?.Navbar?.[0] === "Navbar1" && (
|
||||
<div className="applayout1" style={{ display: "flex", flexDirection: "row", columnGap: '2rem' ,flexDirection:"column"}}>
|
||||
<div className="applayout1" style={{ display: "flex", flexDirection: "column", columnGap: '2rem' }}>
|
||||
<div className="Appsidenav" >
|
||||
<div id="Navbar">
|
||||
{templateData["Navbar"]?.[0] == "Navbar1" && (
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useEffect, useRef, useState } from "react";
|
||||
import React, { useEffect, useRef, useState, lazy, Suspense, useCallback } from "react";
|
||||
import { useLocation, useParams } from "react-router-dom";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { Skeleton } from "antd";
|
||||
|
|
@ -9,42 +9,49 @@ import {
|
|||
getTemplate,
|
||||
getTemplateData,
|
||||
} from "../../features/themeChange/themeChange";
|
||||
import { PostToken } from "../../features/publicHome/publicHome";
|
||||
|
||||
// ✅ Critical imports - Load immediately (above fold)
|
||||
import HomeNav from "../publichome/PublicNavBar/NavBar";
|
||||
import Navbar3 from "../themeTemplate/TemplateComps/NavBars/NavBars/NavBar3HorizontalPreview";
|
||||
import Navbar2 from "../themeTemplate/TemplateComps/NavBars/NavBars/NavBarHorizontalPreview";
|
||||
import Navbar1 from "../themeTemplate/TemplateComps/NavBars/SideNav/SideNavBarPreview";
|
||||
import OverView1 from "../themeTemplate/TemplateComps/OverVIews/OverView1";
|
||||
import OverView2 from "../themeTemplate/TemplateComps/OverVIews/OverView2";
|
||||
import Features1 from "../themeTemplate/TemplateComps/Features/Features1";
|
||||
import Features2 from "../themeTemplate/TemplateComps/Features/Feature2";
|
||||
import Pricing1 from "../themeTemplate/TemplateComps/Pricing/Pricing1";
|
||||
import Pricing2 from "../themeTemplate/TemplateComps/Pricing/Pricing2";
|
||||
import Pricing3 from "../themeTemplate/TemplateComps/Pricing/Pricing3";
|
||||
import OverviewTemp3 from "./TemplateComps/OverVIews/OverViewTemplate3";
|
||||
import HeroSection from "./TemplateComps/OverVIews/OverView3";
|
||||
import Loader from "../../Components/Loader/Loader";
|
||||
|
||||
import Faq1 from "../themeTemplate/TemplateComps/Faq/FaqPreview1";
|
||||
import Faq2 from "../themeTemplate/TemplateComps/Faq/FaqPreview2";
|
||||
import DownloadSource from "../themeTemplate/TemplateComps/downloadsource/downloadSource";
|
||||
import Contact from "../themeTemplate/TemplateComps/contact/contact";
|
||||
import Footer1 from "../themeTemplate/TemplateComps/Footer/FooterTemplate1";
|
||||
import Footer2 from "../themeTemplate/TemplateComps/Footer/FooterTemplate2";
|
||||
import Footer3 from "../themeTemplate/TemplateComps/Footer/FooterTemplate3";
|
||||
import HomeNav from "../publichome/PublicNavBar/NavBar";
|
||||
// 🚀 Lazy imports - Below fold components
|
||||
const Features1 = lazy(() => import("../themeTemplate/TemplateComps/Features/Features1"));
|
||||
const Features2 = lazy(() => import("../themeTemplate/TemplateComps/Features/Feature2"));
|
||||
const Feature3 = lazy(() => import("./TemplateComps/Features/Feature3"));
|
||||
|
||||
const Pricing1 = lazy(() => import("../themeTemplate/TemplateComps/Pricing/Pricing1"));
|
||||
const Pricing2 = lazy(() => import("../themeTemplate/TemplateComps/Pricing/Pricing2"));
|
||||
const Pricing3 = lazy(() => import("../themeTemplate/TemplateComps/Pricing/Pricing3"));
|
||||
|
||||
const Faq1 = lazy(() => import("../themeTemplate/TemplateComps/Faq/FaqPreview1"));
|
||||
const Faq2 = lazy(() => import("../themeTemplate/TemplateComps/Faq/FaqPreview2"));
|
||||
const FaqTemplate3 = lazy(() => import("./TemplateComps/Faq/FaqTemplate3"));
|
||||
const FAQSection = lazy(() => import("./TemplateComps/Faq/FaqPreview3"));
|
||||
const CommonFaq = lazy(() => import("./TemplateComps/Faq/CommonFaq"));
|
||||
|
||||
const Footer1 = lazy(() => import("../themeTemplate/TemplateComps/Footer/FooterTemplate1"));
|
||||
const Footer2 = lazy(() => import("../themeTemplate/TemplateComps/Footer/FooterTemplate2"));
|
||||
const Footer3 = lazy(() => import("../themeTemplate/TemplateComps/Footer/FooterTemplate3"));
|
||||
const FooterTemplate3 = lazy(() => import("../themeTemplate/TemplateComps/Footer/FooterTemplate3"));
|
||||
|
||||
const DownloadSource = lazy(() => import("../themeTemplate/TemplateComps/downloadsource/downloadSource"));
|
||||
const Contact = lazy(() => import("../themeTemplate/TemplateComps/contact/contact"));
|
||||
const CTAPreview = lazy(() => import("./TemplateComps/CTASection/CTASectionPreview"));
|
||||
const ShowcasePreview = lazy(() => import("./TemplateComps/Showcase/showcasepreviw"));
|
||||
const TestimonialTemplate = lazy(() => import("./TemplateComps/Testimonial/TestimonialTemplate"));
|
||||
const TestimonialPreView = lazy(() => import("./TemplateComps/Testimonial/TestimonialPreView"));
|
||||
|
||||
import "../../styles/template/template/template.css";
|
||||
import Feature3 from "./TemplateComps/Features/Feature3";
|
||||
import { getSession } from "../../Services/others";
|
||||
import OverviewTemp3 from "./TemplateComps/OverVIews/OverViewTemplate3";
|
||||
import FaqTemplate3 from "./TemplateComps/Faq/FaqTemplate3";
|
||||
import NavBar3HorizontalPreview from "../themeTemplate/TemplateComps/NavBars/NavBars/NavBar3HorizontalPreview";
|
||||
import FooterTemplate3 from "../themeTemplate/TemplateComps/Footer/FooterTemplate3";
|
||||
import CTAPreview from "./TemplateComps/CTASection/CTASectionPreview";
|
||||
import ShowcasePreview from "./TemplateComps/Showcase/showcasepreviw";
|
||||
import TestimonialTemplate from "./TemplateComps/Testimonial/TestimonialTemplate";
|
||||
import { getCustomertestimonials } from "../../features/testimonials/testimonials";
|
||||
import HeroSection from "./TemplateComps/OverVIews/OverView3";
|
||||
import FAQSection from "./TemplateComps/Faq/FaqPreview3";
|
||||
import Loader from "../../Components/Loader/Loader";
|
||||
import TestimonialPreView from "./TemplateComps/Testimonial/TestimonialPreView";
|
||||
import CommonFaq from "./TemplateComps/Faq/CommonFaq";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { LuMousePointerClick } from "react-icons/lu";
|
||||
const subDirectory = import.meta.env.ENV_BASE_URL
|
||||
|
|
@ -62,11 +69,60 @@ const Template = () => {
|
|||
|
||||
const changeCurrentColorValues = useSelector(changeCurrentColorValue);
|
||||
console.log("templateData", templateData)
|
||||
|
||||
// 🔑 Auto-generate token for direct URL access
|
||||
useEffect(() => {
|
||||
dispatch(getTemplate(params.appName)).unwrap();
|
||||
const initializeAuth = async () => {
|
||||
try {
|
||||
// Check if token already exists
|
||||
const existingToken = sessionStorage.getItem("auth");
|
||||
|
||||
if (!existingToken) {
|
||||
console.log("🔑 Generating token for direct URL access...");
|
||||
// Generate token
|
||||
const tokenData = {
|
||||
username: "1000000001",
|
||||
password: "1234",
|
||||
};
|
||||
await dispatch(PostToken(tokenData)).unwrap();
|
||||
console.log("✅ Token generated successfully");
|
||||
}
|
||||
|
||||
// Convert clean URL slug back to proper app name for API call
|
||||
// URL: salon-spa-and-beauty-parlour → API: Salon, Spa and Beauty Parlour
|
||||
// URL: beauty-and-cosmetics-shop → API: Beauty and Cosmetics Shop
|
||||
const appNameForApi = params.appName
|
||||
.split('-')
|
||||
.map((word, index, arr) => {
|
||||
// Keep 'and' lowercase unless it's the first word
|
||||
if (word === 'and' && index > 0 && index < arr.length - 1) {
|
||||
return 'and';
|
||||
}
|
||||
// Capitalize first letter
|
||||
return word.charAt(0).toUpperCase() + word.slice(1);
|
||||
})
|
||||
.join(' ');
|
||||
|
||||
console.log("📦 URL slug:", params.appName);
|
||||
console.log("📦 Loading template for:", appNameForApi);
|
||||
|
||||
// Fetch template data with proper app name
|
||||
await dispatch(getTemplate(appNameForApi)).unwrap();
|
||||
} catch (error) {
|
||||
console.error("❌ Error initializing template:", error);
|
||||
}
|
||||
};
|
||||
|
||||
initializeAuth();
|
||||
}, [params.appName, dispatch]);
|
||||
|
||||
// Separate useEffect for scroll tracking with throttle
|
||||
useEffect(() => {
|
||||
let ticking = false;
|
||||
|
||||
const trackPosition = () => {
|
||||
const divElement = navbarRef?.current;
|
||||
if (!divElement) return; // Ensure divElement exists before proceeding
|
||||
if (!divElement) return;
|
||||
|
||||
const { top } = divElement.getBoundingClientRect();
|
||||
|
||||
|
|
@ -75,12 +131,20 @@ const changeCurrentColorValues = useSelector(changeCurrentColorValue);
|
|||
} else {
|
||||
divElement.classList.remove("navBarHover");
|
||||
}
|
||||
ticking = false;
|
||||
};
|
||||
|
||||
window.addEventListener("scroll", trackPosition);
|
||||
const handleScroll = () => {
|
||||
if (!ticking) {
|
||||
window.requestAnimationFrame(trackPosition);
|
||||
ticking = true;
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("scroll", handleScroll, { passive: true });
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("scroll", trackPosition); // Pass the same event handler function here
|
||||
window.removeEventListener("scroll", handleScroll);
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
|
@ -108,16 +172,22 @@ const changeCurrentColorValues = useSelector(changeCurrentColorValue);
|
|||
}, [location?.state]);
|
||||
|
||||
const [Testimonialsdata, setTestimonialsdata] = useState([]);
|
||||
useEffect(() => {
|
||||
apicall()
|
||||
}, [])
|
||||
|
||||
const apicall = async () => {
|
||||
let res = await dispatch(getCustomertestimonials()).unwrap();
|
||||
if (res?.data?.statusCode === 1) {
|
||||
setTestimonialsdata(res?.data?.data);
|
||||
// 🚀 Memoized API call
|
||||
const apicall = useCallback(async () => {
|
||||
try {
|
||||
const res = await dispatch(getCustomertestimonials()).unwrap();
|
||||
if (res?.data?.statusCode === 1) {
|
||||
setTestimonialsdata(res?.data?.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching testimonials:", error);
|
||||
}
|
||||
}
|
||||
}, [dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
apicall();
|
||||
}, [apicall]);
|
||||
useEffect(() => {
|
||||
if (location?.state?.scrollToId) {
|
||||
scrollToSection(location.state.scrollToId);
|
||||
|
|
@ -314,71 +384,72 @@ useEffect(() => {
|
|||
<HeroSection data={templateData["Overview"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<div id="ShowCase">
|
||||
{templateData["Showcase"]?.[0] == "Showcase1" && (
|
||||
<ShowcasePreview data={templateData["Showcase"][1]?.[0]?.FieldValue} key={"ShowCase"} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Appview">
|
||||
{templateData["Appview"]?.[0] == "Appview1" && (
|
||||
<ShowcasePreview data={templateData["Appview"][1]?.[0]?.FieldValue} key={"Appview"} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Testimonials">
|
||||
{templateData["Testimonials"]?.[0] == "Testimonials1" && (
|
||||
<TestimonialPreView isDefault={false} />
|
||||
|
||||
)}
|
||||
</div>
|
||||
<div id="Features">
|
||||
{templateData["Features"]?.[0] == "Features1" && (
|
||||
<Features1 data={templateData["Features"][1]} />
|
||||
)}
|
||||
{templateData["Features"]?.[0] == "Features2" && (
|
||||
<Features2 data={templateData["Features"][1]} />
|
||||
)}
|
||||
{templateData["Features"]?.[0] == "Features3" && (
|
||||
<Feature3 data={templateData["Features"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Pricing">
|
||||
{templateData["Pricing"]?.[0] == "Pricing1" && (
|
||||
<Pricing1 data={templateData["Pricing"][1]} AdminId={AdminId ? AdminId : location?.state?.AdminId} />
|
||||
)}
|
||||
{templateData["Pricing"]?.[0] == "Pricing2" && (
|
||||
<Pricing2 data={templateData["Pricing"][1]} AdminId={AdminId ? AdminId : location?.state?.AdminId} />
|
||||
)}
|
||||
{templateData["Pricing"]?.[0] == "Pricing3" && (
|
||||
<Pricing3 data={templateData["Pricing"][1]} AdminId={AdminId ? AdminId : location?.state?.AdminId} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Faq">
|
||||
{templateData["Faq"]?.[0] == "Faq1" && (
|
||||
<Faq1 data={templateData["Faq"][1]} />
|
||||
)}
|
||||
{templateData["Faq"]?.[0] == "Faq2" && (
|
||||
<Faq2 data={templateData["Faq"][1]} />
|
||||
)}
|
||||
{templateData["Faq"]?.[0] == "Faq3" && (
|
||||
<FAQSection data={templateData["Faq"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<div id="CTA">
|
||||
{templateData["CTA"]?.[0] == "CTA1" && (
|
||||
<CTAPreview data={templateData["CTA"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Footer">
|
||||
{templateData["Footer"]?.[0] == "Footer1" && (
|
||||
<Footer1 data={templateData["Footer"][1]} />
|
||||
)}
|
||||
{templateData["Footer"]?.[0] == "Footer2" && (
|
||||
<Footer2 data={templateData["Footer"][1]} />
|
||||
)}
|
||||
{templateData["Footer"]?.[0] == "Footer3" && (
|
||||
<FooterTemplate3 data={templateData["Footer"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<Suspense fallback={null}>
|
||||
<div id="ShowCase">
|
||||
{templateData["Showcase"]?.[0] == "Showcase1" && (
|
||||
<ShowcasePreview data={templateData["Showcase"][1]?.[0]?.FieldValue} key={"ShowCase"} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Appview">
|
||||
{templateData["Appview"]?.[0] == "Appview1" && (
|
||||
<ShowcasePreview data={templateData["Appview"][1]?.[0]?.FieldValue} key={"Appview"} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Testimonials">
|
||||
{templateData["Testimonials"]?.[0] == "Testimonials1" && (
|
||||
<TestimonialPreView isDefault={false} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Features">
|
||||
{templateData["Features"]?.[0] == "Features1" && (
|
||||
<Features1 data={templateData["Features"][1]} />
|
||||
)}
|
||||
{templateData["Features"]?.[0] == "Features2" && (
|
||||
<Features2 data={templateData["Features"][1]} />
|
||||
)}
|
||||
{templateData["Features"]?.[0] == "Features3" && (
|
||||
<Feature3 data={templateData["Features"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Pricing">
|
||||
{templateData["Pricing"]?.[0] == "Pricing1" && (
|
||||
<Pricing1 data={templateData["Pricing"][1]} AdminId={AdminId ? AdminId : location?.state?.AdminId} />
|
||||
)}
|
||||
{templateData["Pricing"]?.[0] == "Pricing2" && (
|
||||
<Pricing2 data={templateData["Pricing"][1]} AdminId={AdminId ? AdminId : location?.state?.AdminId} />
|
||||
)}
|
||||
{templateData["Pricing"]?.[0] == "Pricing3" && (
|
||||
<Pricing3 data={templateData["Pricing"][1]} AdminId={AdminId ? AdminId : location?.state?.AdminId} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Faq">
|
||||
{templateData["Faq"]?.[0] == "Faq1" && (
|
||||
<Faq1 data={templateData["Faq"][1]} />
|
||||
)}
|
||||
{templateData["Faq"]?.[0] == "Faq2" && (
|
||||
<Faq2 data={templateData["Faq"][1]} />
|
||||
)}
|
||||
{templateData["Faq"]?.[0] == "Faq3" && (
|
||||
<FAQSection data={templateData["Faq"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<div id="CTA">
|
||||
{templateData["CTA"]?.[0] == "CTA1" && (
|
||||
<CTAPreview data={templateData["CTA"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Footer">
|
||||
{templateData["Footer"]?.[0] == "Footer1" && (
|
||||
<Footer1 data={templateData["Footer"][1]} />
|
||||
)}
|
||||
{templateData["Footer"]?.[0] == "Footer2" && (
|
||||
<Footer2 data={templateData["Footer"][1]} />
|
||||
)}
|
||||
{templateData["Footer"]?.[0] == "Footer3" && (
|
||||
<FooterTemplate3 data={templateData["Footer"][1]} />
|
||||
)}
|
||||
</div>
|
||||
</Suspense>
|
||||
</div>
|
||||
)}
|
||||
{templateData?.Navbar?.[0] === "Navbar1" && (
|
||||
|
|
@ -408,70 +479,72 @@ useEffect(() => {
|
|||
<HeroSection data={templateData["Overview"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<div id="ShowCase">
|
||||
{templateData["Showcase"]?.[0] == "Showcase1" && (
|
||||
<ShowcasePreview data={templateData["Showcase"][1]?.[0]?.FieldValue} key={"ShowCase"} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Appview">
|
||||
{templateData["Appview"]?.[0] == "Appview1" && (
|
||||
<ShowcasePreview data={templateData["Appview"][1]?.[0]?.FieldValue} key={"Appview"} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Testimonials">
|
||||
{templateData["Testimonials"]?.[0] == "Testimonials1" && (
|
||||
<TestimonialPreView isDefault={false} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Features">
|
||||
{templateData["Features"]?.[0] == "Features1" && (
|
||||
<Features1 data={templateData["Features"][1]} />
|
||||
)}
|
||||
{templateData["Features"]?.[0] == "Features2" && (
|
||||
<Features2 data={templateData["Features"][1]} />
|
||||
)}
|
||||
{templateData["Features"]?.[0] == "Features3" && (
|
||||
<Feature3 data={templateData["Features"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Pricing">
|
||||
{templateData["Pricing"]?.[0] == "Pricing1" && (
|
||||
<Pricing1 data={templateData["Pricing"][1]} AdminId={AdminId ? AdminId : location?.state?.AdminId} />
|
||||
)}
|
||||
{templateData["Pricing"]?.[0] == "Pricing2" && (
|
||||
<Pricing2 data={templateData["Pricing"][1]} AdminId={AdminId ? AdminId : location?.state?.AdminId} />
|
||||
)}
|
||||
{templateData["Pricing"]?.[0] == "Pricing3" && (
|
||||
<Pricing3 data={templateData["Pricing"][1]} AdminId={AdminId ? AdminId : location?.state?.AdminId} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Faq">
|
||||
{templateData["Faq"]?.[0] == "Faq1" && (
|
||||
<Faq1 data={templateData["Faq"][1]} />
|
||||
)}
|
||||
{templateData["Faq"]?.[0] == "Faq2" && (
|
||||
<Faq2 data={templateData["Faq"][1]} />
|
||||
)}
|
||||
{templateData["Faq"]?.[0] == "Faq3" && (
|
||||
<FAQSection data={templateData["Faq"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<div id="CTA">
|
||||
{templateData["CTA"]?.[0] == "CTA1" && (
|
||||
<CTAPreview data={templateData["CTA"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Footer">
|
||||
{templateData["Footer"]?.[0] == "Footer1" && (
|
||||
<Footer1 data={templateData["Footer"][1]} />
|
||||
)}
|
||||
{templateData["Footer"]?.[0] == "Footer2" && (
|
||||
<Footer2 data={templateData["Footer"][1]} />
|
||||
)}
|
||||
{templateData["Footer"]?.[0] == "Footer3" && (
|
||||
<FooterTemplate3 data={templateData["Footer"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<Suspense fallback={null}>
|
||||
<div id="ShowCase">
|
||||
{templateData["Showcase"]?.[0] == "Showcase1" && (
|
||||
<ShowcasePreview data={templateData["Showcase"][1]?.[0]?.FieldValue} key={"ShowCase"} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Appview">
|
||||
{templateData["Appview"]?.[0] == "Appview1" && (
|
||||
<ShowcasePreview data={templateData["Appview"][1]?.[0]?.FieldValue} key={"Appview"} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Testimonials">
|
||||
{templateData["Testimonials"]?.[0] == "Testimonials1" && (
|
||||
<TestimonialPreView isDefault={false} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Features">
|
||||
{templateData["Features"]?.[0] == "Features1" && (
|
||||
<Features1 data={templateData["Features"][1]} />
|
||||
)}
|
||||
{templateData["Features"]?.[0] == "Features2" && (
|
||||
<Features2 data={templateData["Features"][1]} />
|
||||
)}
|
||||
{templateData["Features"]?.[0] == "Features3" && (
|
||||
<Feature3 data={templateData["Features"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Pricing">
|
||||
{templateData["Pricing"]?.[0] == "Pricing1" && (
|
||||
<Pricing1 data={templateData["Pricing"][1]} AdminId={AdminId ? AdminId : location?.state?.AdminId} />
|
||||
)}
|
||||
{templateData["Pricing"]?.[0] == "Pricing2" && (
|
||||
<Pricing2 data={templateData["Pricing"][1]} AdminId={AdminId ? AdminId : location?.state?.AdminId} />
|
||||
)}
|
||||
{templateData["Pricing"]?.[0] == "Pricing3" && (
|
||||
<Pricing3 data={templateData["Pricing"][1]} AdminId={AdminId ? AdminId : location?.state?.AdminId} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Faq">
|
||||
{templateData["Faq"]?.[0] == "Faq1" && (
|
||||
<Faq1 data={templateData["Faq"][1]} />
|
||||
)}
|
||||
{templateData["Faq"]?.[0] == "Faq2" && (
|
||||
<Faq2 data={templateData["Faq"][1]} />
|
||||
)}
|
||||
{templateData["Faq"]?.[0] == "Faq3" && (
|
||||
<FAQSection data={templateData["Faq"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<div id="CTA">
|
||||
{templateData["CTA"]?.[0] == "CTA1" && (
|
||||
<CTAPreview data={templateData["CTA"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Footer">
|
||||
{templateData["Footer"]?.[0] == "Footer1" && (
|
||||
<Footer1 data={templateData["Footer"][1]} />
|
||||
)}
|
||||
{templateData["Footer"]?.[0] == "Footer2" && (
|
||||
<Footer2 data={templateData["Footer"][1]} />
|
||||
)}
|
||||
{templateData["Footer"]?.[0] == "Footer3" && (
|
||||
<FooterTemplate3 data={templateData["Footer"][1]} />
|
||||
)}
|
||||
</div>
|
||||
</Suspense>
|
||||
</div>
|
||||
)}
|
||||
{templateData?.Navbar?.[0] === "Navbar3" && (
|
||||
|
|
@ -501,94 +574,96 @@ useEffect(() => {
|
|||
<HeroSection data={templateData["Overview"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<div id="ShowCase">
|
||||
{templateData["Showcase"]?.[0] == "Showcase1" && (
|
||||
<ShowcasePreview data={templateData["Showcase"][1]?.[0]?.FieldValue} key={"ShowCase"} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Appview">
|
||||
{templateData["Appview"]?.[0] == "Appview1" && (
|
||||
<ShowcasePreview data={templateData["Appview"][1]?.[0]?.FieldValue} key={"Appview"} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Testimonials">
|
||||
{templateData["Testimonials"]?.[0] == "Testimonials1" && (
|
||||
<TestimonialPreView isDefault={false} />)}
|
||||
</div>
|
||||
<div id="Features">
|
||||
{templateData["Features"]?.[0] == "Features1" && (
|
||||
<Features1 data={templateData["Features"][1]} />
|
||||
)}
|
||||
{templateData["Features"]?.[0] == "Features2" && (
|
||||
<Features2 data={templateData["Features"][1]} />
|
||||
)}
|
||||
{templateData["Features"]?.[0] == "Features3" && (
|
||||
<Feature3 data={templateData["Features"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Pricing">
|
||||
{templateData["Pricing"]?.[0] == "Pricing1" && (
|
||||
<Pricing1 data={templateData["Pricing"][1]} AdminId={AdminId ? AdminId : location?.state?.AdminId} />
|
||||
)}
|
||||
{templateData["Pricing"]?.[0] == "Pricing2" && (
|
||||
<Pricing2 data={templateData["Pricing"][1]} AdminId={AdminId ? AdminId : location?.state?.AdminId} />
|
||||
)}
|
||||
{templateData["Pricing"]?.[0] == "Pricing3" && (
|
||||
<Pricing3 data={templateData["Pricing"][1]} AdminId={AdminId ? AdminId : location?.state?.AdminId} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Faq">
|
||||
{templateData["Faq"]?.[0] == "Faq1" && (
|
||||
<Faq1 data={templateData["Faq"][1]} />
|
||||
)}
|
||||
{templateData["Faq"]?.[0] == "Faq2" && (
|
||||
<Faq2 data={templateData["Faq"][1]} />
|
||||
)}
|
||||
{/* {templateData["Faq"]?.[0] == "Faq3" && (
|
||||
<FAQSection data={templateData["Faq"][1]} />
|
||||
</div>
|
||||
)} */}
|
||||
{templateData["Faq"]?.[0] === "Faq3" && (
|
||||
<div style={{
|
||||
margin:"0 0 2rem 0", width:"100%",
|
||||
display:"flex", alignItems:"center", flexDirection:"row", justifyContent:"center", gap:"1rem"
|
||||
}}>
|
||||
<div style={{fontSize:"16px",fontWeight:"600", margin:"1rem 0",
|
||||
fontFamily: CurrentText?.head ? CurrentText?.head : '',
|
||||
}}>View complete FAQ list</div>
|
||||
<button
|
||||
scrollToId="backFaq"
|
||||
onClick={() => navigate( `${subDirectory}Faq`,
|
||||
{ state: { faqData: templateData["Faq"][1], from: location.pathname, } }
|
||||
)}
|
||||
style={{
|
||||
fontFamily: CurrentText?.para ? CurrentText?.para : '', gap:"10px", border:"none",
|
||||
backgroundColor: 'unset', display:"flex", alignItems:"center",
|
||||
color:"#000", cursor:"pointer" , borderBottom:"1px solid #000"
|
||||
}}
|
||||
>
|
||||
See all FAQs <LuMousePointerClick size={24}/>
|
||||
</button>
|
||||
{/* <FAQSection data={templateData["Faq"][1]} /> */}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div id="CTA">
|
||||
{templateData["CTA"]?.[0] == "CTA1" && (
|
||||
<CTAPreview data={templateData["CTA"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Footer">
|
||||
{templateData["Footer"]?.[0] == "Footer1" && (
|
||||
<Footer1 data={templateData["Footer"][1]} />
|
||||
)}
|
||||
{templateData["Footer"]?.[0] == "Footer2" && (
|
||||
<Footer2 data={templateData["Footer"][1]} />
|
||||
)}
|
||||
{templateData["Footer"]?.[0] == "Footer3" && (
|
||||
<FooterTemplate3 data={templateData["Footer"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<Suspense fallback={null}>
|
||||
<div id="ShowCase">
|
||||
{templateData["Showcase"]?.[0] == "Showcase1" && (
|
||||
<ShowcasePreview data={templateData["Showcase"][1]?.[0]?.FieldValue} key={"ShowCase"} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Appview">
|
||||
{templateData["Appview"]?.[0] == "Appview1" && (
|
||||
<ShowcasePreview data={templateData["Appview"][1]?.[0]?.FieldValue} key={"Appview"} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Testimonials">
|
||||
{templateData["Testimonials"]?.[0] == "Testimonials1" && (
|
||||
<TestimonialPreView isDefault={false} />)}
|
||||
</div>
|
||||
<div id="Features">
|
||||
{templateData["Features"]?.[0] == "Features1" && (
|
||||
<Features1 data={templateData["Features"][1]} />
|
||||
)}
|
||||
{templateData["Features"]?.[0] == "Features2" && (
|
||||
<Features2 data={templateData["Features"][1]} />
|
||||
)}
|
||||
{templateData["Features"]?.[0] == "Features3" && (
|
||||
<Feature3 data={templateData["Features"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Pricing">
|
||||
{templateData["Pricing"]?.[0] == "Pricing1" && (
|
||||
<Pricing1 data={templateData["Pricing"][1]} AdminId={AdminId ? AdminId : location?.state?.AdminId} />
|
||||
)}
|
||||
{templateData["Pricing"]?.[0] == "Pricing2" && (
|
||||
<Pricing2 data={templateData["Pricing"][1]} AdminId={AdminId ? AdminId : location?.state?.AdminId} />
|
||||
)}
|
||||
{templateData["Pricing"]?.[0] == "Pricing3" && (
|
||||
<Pricing3 data={templateData["Pricing"][1]} AdminId={AdminId ? AdminId : location?.state?.AdminId} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Faq">
|
||||
{templateData["Faq"]?.[0] == "Faq1" && (
|
||||
<Faq1 data={templateData["Faq"][1]} />
|
||||
)}
|
||||
{templateData["Faq"]?.[0] == "Faq2" && (
|
||||
<Faq2 data={templateData["Faq"][1]} />
|
||||
)}
|
||||
{/* {templateData["Faq"]?.[0] == "Faq3" && (
|
||||
<FAQSection data={templateData["Faq"][1]} />
|
||||
</div>
|
||||
)} */}
|
||||
{templateData["Faq"]?.[0] === "Faq3" && (
|
||||
<div style={{
|
||||
margin:"0 0 2rem 0", width:"100%",
|
||||
display:"flex", alignItems:"center", flexDirection:"row", justifyContent:"center", gap:"1rem"
|
||||
}}>
|
||||
<div style={{fontSize:"16px",fontWeight:"600", margin:"1rem 0",
|
||||
fontFamily: CurrentText?.head ? CurrentText?.head : '',
|
||||
}}>View complete FAQ list</div>
|
||||
<button
|
||||
scrollToId="backFaq"
|
||||
onClick={() => navigate( `${subDirectory}Faq`,
|
||||
{ state: { faqData: templateData["Faq"][1], from: location.pathname, } }
|
||||
)}
|
||||
style={{
|
||||
fontFamily: CurrentText?.para ? CurrentText?.para : '', gap:"10px", border:"none",
|
||||
backgroundColor: 'unset', display:"flex", alignItems:"center",
|
||||
color:"#000", cursor:"pointer" , borderBottom:"1px solid #000"
|
||||
}}
|
||||
>
|
||||
See all FAQs <LuMousePointerClick size={24}/>
|
||||
</button>
|
||||
{/* <FAQSection data={templateData["Faq"][1]} /> */}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div id="CTA">
|
||||
{templateData["CTA"]?.[0] == "CTA1" && (
|
||||
<CTAPreview data={templateData["CTA"][1]} />
|
||||
)}
|
||||
</div>
|
||||
<div id="Footer">
|
||||
{templateData["Footer"]?.[0] == "Footer1" && (
|
||||
<Footer1 data={templateData["Footer"][1]} />
|
||||
)}
|
||||
{templateData["Footer"]?.[0] == "Footer2" && (
|
||||
<Footer2 data={templateData["Footer"][1]} />
|
||||
)}
|
||||
{templateData["Footer"]?.[0] == "Footer3" && (
|
||||
<FooterTemplate3 data={templateData["Footer"][1]} />
|
||||
)}
|
||||
</div>
|
||||
</Suspense>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
|
|||
|
|
@ -152,6 +152,15 @@ const ContactUs = () => {
|
|||
if (industry) {
|
||||
handleIndustry();
|
||||
}
|
||||
// Clean URL: Remove special chars, convert spaces to hyphens
|
||||
const cleanUrl = AppName
|
||||
.replace(/[,]/g, '') // Remove commas
|
||||
.replace(/\s+/g, '-') // Spaces to hyphens
|
||||
.replace(/&/g, 'and') // & to 'and'
|
||||
.replace(/[^a-z0-9-]/gi, '') // Remove other special chars
|
||||
.toLowerCase();
|
||||
navigate(`${subDirectory}${cleanUrl}`);
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
import React, { useEffect, useRef, useState } from "react";
|
||||
import React, { useEffect, useRef, useState, useMemo } from "react";
|
||||
import "../Styles/Footer.scss";
|
||||
import pozominilogo from "../Images/pozominilogo.webp";
|
||||
import { PiInstagramLogoFill } from "react-icons/pi";
|
||||
import { FaFacebook } from "react-icons/fa";
|
||||
import { RiTwitterXFill } from "react-icons/ri";
|
||||
import { FaYoutube } from "react-icons/fa";
|
||||
import { getApplicationData } from "../../features/publicHome/publicHome";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { BiSearch } from "react-icons/bi";
|
||||
import { gsap } from "gsap";
|
||||
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
|
@ -14,46 +13,24 @@ import { sessionStore } from "../../Services/others";
|
|||
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
const subDirectory = import.meta.env.ENV_BASE_URL
|
||||
const Footer = () => {
|
||||
const Footer = ({ AppCategory = [] }) => {
|
||||
const navigate = useNavigate();
|
||||
const logoRef = useRef(null);
|
||||
const productsRef = useRef(null);
|
||||
const footerRef = useRef(null);
|
||||
const dispatch = useDispatch();
|
||||
const [email, setEmail] = useState("");
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [message, setMessage] = useState("");
|
||||
const [messageType, setMessageType] = useState("");
|
||||
const [appList, setAppList] = useState([]);
|
||||
const [isFooterVisible, setIsFooterVisible] = useState(false);
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [filteredApps, setFilteredApps] = useState([]);
|
||||
const [currentCategoryPage, setCurrentCategoryPage] = useState(0);
|
||||
|
||||
const scrollToTop = () => {
|
||||
window.scrollTo({ top: 0, behavior: "smooth" });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// Intersection Observer for lazy loading
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
console.log("👁️ Footer visibility:", entry.isIntersecting);
|
||||
if (entry.isIntersecting && !isFooterVisible) {
|
||||
console.log("🎯 Footer is visible! Loading apps...");
|
||||
setIsFooterVisible(true);
|
||||
fetchApplicationData();
|
||||
}
|
||||
});
|
||||
},
|
||||
{ threshold: 0.1 }
|
||||
);
|
||||
|
||||
if (footerRef.current) {
|
||||
console.log("✅ Observer attached to footer");
|
||||
observer.observe(footerRef.current);
|
||||
} else {
|
||||
console.log("❌ footerRef is null");
|
||||
}
|
||||
|
||||
// Logo animation
|
||||
if (logoRef.current) {
|
||||
gsap.fromTo(
|
||||
|
|
@ -92,36 +69,159 @@ const Footer = () => {
|
|||
},
|
||||
);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (footerRef.current) {
|
||||
observer.unobserve(footerRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const fetchApplicationData = async () => {
|
||||
try {
|
||||
console.log("🔥 Footer: Fetching apps data...");
|
||||
const res = await dispatch(getApplicationData())?.unwrap();
|
||||
console.log("📦 Footer API Response:", res?.data);
|
||||
if (res?.data?.statusCode === 1) {
|
||||
const activeApps = res?.data?.data?.filter(app => app.ActiveStatus === "A") || [];
|
||||
console.log("✅ Footer Active Apps:", activeApps.length, activeApps);
|
||||
setAppList(activeApps);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("❌ Error fetching apps:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const redirectApp = (appName, appId) => {
|
||||
sessionStore("AppId", appId);
|
||||
sessionStore("AppName", appName);
|
||||
navigate(`${subDirectory}${appName}`);
|
||||
// Clean URL: Remove special chars, convert spaces to hyphens
|
||||
const cleanUrl = appName
|
||||
.replace(/[,]/g, '') // Remove commas
|
||||
.replace(/\s+/g, '-') // Spaces to hyphens
|
||||
.replace(/&/g, 'and') // & to 'and'
|
||||
.replace(/[^a-z0-9-]/gi, '') // Remove other special chars
|
||||
.toLowerCase();
|
||||
navigate(`${subDirectory}${cleanUrl}`);
|
||||
window.scrollTo(0, 0);
|
||||
};
|
||||
|
||||
// Categorize apps (EXACT same logic as IndustriesList)
|
||||
const categorizeApps = (apps) => {
|
||||
const categories = {
|
||||
// Consumer (Retail Universe)
|
||||
foodBeverages: [],
|
||||
wellness: [],
|
||||
fashion: [],
|
||||
electronics: [],
|
||||
grocery: [],
|
||||
services: [],
|
||||
others: [],
|
||||
// Manufacturing & Healthcare
|
||||
healthcare: [],
|
||||
manufacturing: [],
|
||||
// Transportation & Hospitality
|
||||
transportation: [],
|
||||
hospitality: []
|
||||
};
|
||||
|
||||
apps.forEach(app => {
|
||||
const name = app.AppName?.toLowerCase() || "";
|
||||
const category = app.CategoryName?.toLowerCase() || "";
|
||||
|
||||
// Consumer categories
|
||||
if (/(consumer)/i.test(category)) {
|
||||
if (/(bakery|restaurant|dairy|food|cafe|coffee|ice|pickle|pozoresto|resto|eatery|diner|bistro|pizz|burger|juice|sweet|snack)/i.test(name)) {
|
||||
categories.foodBeverages.push(app);
|
||||
} else if (/(salon|spa|beauty|cosmetics|fitness|gym|yoga|wellness|massage|parlour|parlor)/i.test(name)) {
|
||||
categories.wellness.push(app);
|
||||
} else if (/(fashion|jewellery|jewelry|footwear|lifestyle|apparel|textile|cloth|garment|shoe|sandal|accessory)/i.test(name)) {
|
||||
categories.fashion.push(app);
|
||||
} else if (/(electronic|mobile|computer|appliance|laptop|phone|device|gadget|tech)/i.test(name)) {
|
||||
categories.electronics.push(app);
|
||||
} else if (/(grocery|departmental|wholesale|supermarket|mart|retail|store)/i.test(name)) {
|
||||
categories.grocery.push(app);
|
||||
} else if (/(stationery|xerox|print|coaching|cement|tuition|education|training|class)/i.test(name)) {
|
||||
categories.services.push(app);
|
||||
} else {
|
||||
categories.others.push(app);
|
||||
}
|
||||
}
|
||||
// Healthcare & Pharma
|
||||
else if (/(healthcare|pharma)/i.test(category) || /(health|optical)/i.test(name)) {
|
||||
categories.healthcare.push(app);
|
||||
}
|
||||
// Manufacturing
|
||||
else if (/(manufacturing)/i.test(category) || /(manufacturer)/i.test(name)) {
|
||||
categories.manufacturing.push(app);
|
||||
}
|
||||
// Transportation & Logistics
|
||||
else if (/(transportation|logistics)/i.test(category) || /(parking|boating)/i.test(name)) {
|
||||
categories.transportation.push(app);
|
||||
}
|
||||
// Hospitality & Entertainment
|
||||
else if (/(hospitality|entertainment)/i.test(category) || /(hotel|resort)/i.test(name)) {
|
||||
categories.hospitality.push(app);
|
||||
}
|
||||
});
|
||||
|
||||
return categories;
|
||||
};
|
||||
|
||||
// 🚀 Memoize categorization - Only recalculate when AppCategory changes
|
||||
const categorizedApps = useMemo(() => categorizeApps(AppCategory), [AppCategory]);
|
||||
|
||||
// 🔍 Search/Filter logic
|
||||
useEffect(() => {
|
||||
if (searchTerm.trim() === "") {
|
||||
setFilteredApps([]);
|
||||
} else {
|
||||
const filtered = AppCategory.filter(app =>
|
||||
app.AppName?.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
);
|
||||
setFilteredApps(filtered);
|
||||
}
|
||||
}, [searchTerm, AppCategory]);
|
||||
|
||||
const handleSearchChange = (e) => {
|
||||
setSearchTerm(e.target.value);
|
||||
};
|
||||
|
||||
const clearSearch = () => {
|
||||
setSearchTerm("");
|
||||
};
|
||||
|
||||
// Organize all categories for pagination
|
||||
const allCategories = useMemo(() => {
|
||||
const cats = [];
|
||||
if (categorizedApps.foodBeverages.length > 0) {
|
||||
cats.push({ title: "Food & Beverages", apps: categorizedApps.foodBeverages });
|
||||
}
|
||||
if (categorizedApps.wellness.length > 0) {
|
||||
cats.push({ title: "Wellness & Beauty", apps: categorizedApps.wellness });
|
||||
}
|
||||
if (categorizedApps.fashion.length > 0) {
|
||||
cats.push({ title: "Fashion & Lifestyle", apps: categorizedApps.fashion });
|
||||
}
|
||||
if (categorizedApps.electronics.length > 0) {
|
||||
cats.push({ title: "Electronics & Tech", apps: categorizedApps.electronics });
|
||||
}
|
||||
if (categorizedApps.grocery.length > 0) {
|
||||
cats.push({ title: "Grocery & Retail", apps: categorizedApps.grocery });
|
||||
}
|
||||
if (categorizedApps.services.length > 0) {
|
||||
cats.push({ title: "Services", apps: categorizedApps.services });
|
||||
}
|
||||
if (categorizedApps.healthcare.length > 0) {
|
||||
cats.push({ title: "Healthcare & Pharma", apps: categorizedApps.healthcare });
|
||||
}
|
||||
if (categorizedApps.manufacturing.length > 0) {
|
||||
cats.push({ title: "Manufacturing", apps: categorizedApps.manufacturing });
|
||||
}
|
||||
if (categorizedApps.transportation.length > 0) {
|
||||
cats.push({ title: "Transportation", apps: categorizedApps.transportation });
|
||||
}
|
||||
if (categorizedApps.hospitality.length > 0) {
|
||||
cats.push({ title: "Hospitality", apps: categorizedApps.hospitality });
|
||||
}
|
||||
if (categorizedApps.others.length > 0) {
|
||||
cats.push({ title: "More Industries", apps: categorizedApps.others });
|
||||
}
|
||||
return cats;
|
||||
}, [categorizedApps]);
|
||||
|
||||
const categoriesPerPage = 3;
|
||||
const totalPages = Math.ceil(allCategories.length / categoriesPerPage);
|
||||
const startIndex = currentCategoryPage * categoriesPerPage;
|
||||
const visibleCategories = allCategories.slice(startIndex, startIndex + categoriesPerPage);
|
||||
|
||||
const handlePrevPage = () => {
|
||||
setCurrentCategoryPage((prev) => Math.max(0, prev - 1));
|
||||
};
|
||||
|
||||
const handleNextPage = () => {
|
||||
setCurrentCategoryPage((prev) => Math.min(totalPages - 1, prev + 1));
|
||||
};
|
||||
|
||||
const handleSubscribe = async () => {
|
||||
if (!email) {
|
||||
setMessage("Please enter your email address");
|
||||
|
|
@ -177,7 +277,7 @@ const Footer = () => {
|
|||
</div>
|
||||
|
||||
<div className="clutter">
|
||||
Stay informed with only what matters <br /> —no spam, no clutter.
|
||||
Stay informed with only what matters <br />—no spam, no clutter.
|
||||
</div>
|
||||
|
||||
{/* <div className="inputOfFooter">
|
||||
|
|
@ -201,42 +301,118 @@ const Footer = () => {
|
|||
|
||||
<div className="footerRight">
|
||||
<div className="footerProducts" ref={productsRef}>
|
||||
<div>Products</div>
|
||||
{(() => {
|
||||
console.log("🔍 Rendering Footer Products:");
|
||||
console.log(" - isFooterVisible:", isFooterVisible);
|
||||
console.log(" - appList.length:", appList.length);
|
||||
console.log(" - Showing:", isFooterVisible && appList.length > 0 ? "Dynamic" : "Static");
|
||||
return null;
|
||||
})()}
|
||||
{isFooterVisible && appList.length > 0 ? (
|
||||
appList.slice(0, 15).map((app) => (
|
||||
<p
|
||||
key={app.AppId}
|
||||
onClick={() => redirectApp(app.AppName?.toLowerCase(), app.AppId)}
|
||||
style={{ cursor: 'pointer' }}
|
||||
>
|
||||
{app.AppName}
|
||||
</p>
|
||||
))
|
||||
{/* Top Bar: Title + Search + Navigation in one line */}
|
||||
<div className="products-top-bar">
|
||||
<div className="products-heading">Products</div>
|
||||
|
||||
{/* Search Box */}
|
||||
<div className="products-search-box">
|
||||
<BiSearch className="products-search-icon" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search products..."
|
||||
value={searchTerm}
|
||||
onChange={handleSearchChange}
|
||||
className="products-search-input"
|
||||
/>
|
||||
{searchTerm && (
|
||||
<button onClick={clearSearch} className="products-search-clear">
|
||||
✕
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Navigation Controls */}
|
||||
{!searchTerm && (
|
||||
<div className="footer-navigation">
|
||||
<button
|
||||
onClick={handlePrevPage}
|
||||
disabled={currentCategoryPage === 0}
|
||||
className="footer-nav-btn"
|
||||
>
|
||||
‹
|
||||
</button>
|
||||
<div className="footer-page-indicator">
|
||||
{currentCategoryPage + 1} / {totalPages}
|
||||
</div>
|
||||
<button
|
||||
onClick={handleNextPage}
|
||||
disabled={currentCategoryPage === totalPages - 1}
|
||||
className="footer-nav-btn"
|
||||
>
|
||||
›
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Search Results Count */}
|
||||
{searchTerm && (
|
||||
<div className="products-search-results-count">
|
||||
{filteredApps.length} {filteredApps.length === 1 ? 'result' : 'results'} found
|
||||
</div>
|
||||
)}
|
||||
|
||||
{searchTerm && filteredApps.length > 0 ? (
|
||||
// Search Results
|
||||
<div className="footer-search-results">
|
||||
{filteredApps.map((app) => (
|
||||
<p
|
||||
key={app.AppId}
|
||||
onClick={() => redirectApp(app.AppName?.toLowerCase(), app.AppId)}
|
||||
className="search-result-item"
|
||||
>
|
||||
{app.AppName}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
) : searchTerm && filteredApps.length === 0 ? (
|
||||
// No Results
|
||||
<div className="footer-no-results">
|
||||
<p>No products found for "{searchTerm}"</p>
|
||||
</div>
|
||||
) : AppCategory.length > 0 ? (
|
||||
<div className="footer-columns-wrapper">
|
||||
{visibleCategories.map((category, index) => (
|
||||
<div className="footer-column" key={index}>
|
||||
<div className="footer-category">{category.title}</div>
|
||||
{category.apps.map((app) => (
|
||||
<p
|
||||
key={app.AppId}
|
||||
onClick={() => redirectApp(app.AppName?.toLowerCase(), app.AppId)}
|
||||
>
|
||||
{app.AppName}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<p>Restaurant</p>
|
||||
<p>Bakery</p>
|
||||
<p>Dairy Delights</p>
|
||||
<p>Electrical, Electronics and Computers</p>
|
||||
<p>Mobile & Accessories</p>
|
||||
<p>Groceries</p>
|
||||
<p>Cement</p>
|
||||
<p>Lifestyle and Fashion</p>
|
||||
<p>Fashion Jewellery</p>
|
||||
<p>Footwear</p>
|
||||
<p>Salon, Spa and Beauty Parlour</p>
|
||||
<p>Beauty and Cosmetics shop</p>
|
||||
<p>Fitness</p>
|
||||
<p>Departmental Stores</p>
|
||||
<p>Wholesale</p>
|
||||
</>
|
||||
<div className="footer-columns-wrapper">
|
||||
{/* Column 1 - Static */}
|
||||
<div className="footer-column">
|
||||
<div className="footer-category">Food & Beverages</div>
|
||||
<p onClick={() => navigate(`${subDirectory}dairy-delights`)}>Dairy Delights</p>
|
||||
<p onClick={() => navigate(`${subDirectory}restaurant`)}>Restaurant</p>
|
||||
<p onClick={() => navigate(`${subDirectory}bakery`)}>Bakery</p>
|
||||
</div>
|
||||
|
||||
{/* Column 2 - Static */}
|
||||
<div className="footer-column">
|
||||
<div className="footer-category">Wellness & Beauty</div>
|
||||
<p onClick={() => navigate(`${subDirectory}beauty-and-cosmetics-shop`)}>Beauty and Cosmetics shop</p>
|
||||
<p onClick={() => navigate(`${subDirectory}fitness`)}>Fitness</p>
|
||||
<p onClick={() => navigate(`${subDirectory}salon-spa-and-beauty-parlour`)}>Salon, Spa and Beauty Parlour</p>
|
||||
</div>
|
||||
|
||||
{/* Column 3 - Static */}
|
||||
<div className="footer-column">
|
||||
<div className="footer-category">Fashion & Lifestyle</div>
|
||||
<p onClick={() => navigate(`${subDirectory}lifestyle-and-fashion`)}>Lifestyle and Fashion</p>
|
||||
<p onClick={() => navigate(`${subDirectory}fashion-jewellery`)}>Fashion Jewellery</p>
|
||||
<p onClick={() => navigate(`${subDirectory}footwear`)}>Footwear</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -92,7 +92,14 @@ const Industries = () => {
|
|||
const redirectApp = (AppName, AppId) => {
|
||||
sessionStore("AppId", AppId);
|
||||
sessionStore("AppName", AppName);
|
||||
navigate(`${subDirectory}${AppName}`);
|
||||
// Clean URL: Remove special chars, convert spaces to hyphens
|
||||
const cleanUrl = AppName
|
||||
.replace(/[,]/g, '') // Remove commas
|
||||
.replace(/\s+/g, '-') // Spaces to hyphens
|
||||
.replace(/&/g, 'and') // & to 'and'
|
||||
.replace(/[^a-z0-9-]/gi, '') // Remove other special chars
|
||||
.toLowerCase();
|
||||
navigate(`${subDirectory}${cleanUrl}`);
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { HiMiniArrowUpRight } from "react-icons/hi2";
|
|||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import { clearSession, getSession, sessionStore } from "../../Services/others";
|
||||
|
||||
import { FaChevronDown } from "react-icons/fa";
|
||||
import { FaChevronDown, FaWhatsapp } from "react-icons/fa";
|
||||
import IndustriesList from "./IndustriesList";
|
||||
import { IoClose } from "react-icons/io5";
|
||||
import { HiMenu } from "react-icons/hi";
|
||||
|
|
@ -81,6 +81,17 @@ const Navbar = ({
|
|||
setIndustryRes(!industryRes);
|
||||
};
|
||||
|
||||
const [solutionsOpen, setSolutionsOpen] = useState(false);
|
||||
const [solutionsOpenRes, setSolutionsOpenRes] = useState(false);
|
||||
|
||||
const handleSolutions = () => {
|
||||
setSolutionsOpen(!solutionsOpen);
|
||||
};
|
||||
|
||||
const handleSolutionsRes = () => {
|
||||
setSolutionsOpenRes(!solutionsOpenRes);
|
||||
};
|
||||
|
||||
const handleNavbarResponsive = () => {
|
||||
// Force scroll to top with immediate execution
|
||||
document.documentElement.scrollTop = 0;
|
||||
|
|
@ -120,7 +131,7 @@ const Navbar = ({
|
|||
};
|
||||
|
||||
const handlePricing = () => {
|
||||
navigate(`${subDirectory}pricing-pozoapp`);
|
||||
navigate(`${subDirectory}pricing`);
|
||||
};
|
||||
const handleNavigatePrivacy = () => {
|
||||
navigate(`${subDirectory}privacy-policy`);
|
||||
|
|
@ -166,7 +177,14 @@ const Navbar = ({
|
|||
const redirectApp = (AppName, AppId) => {
|
||||
sessionStore("AppId", AppId);
|
||||
sessionStore("AppName", AppName);
|
||||
navigate(`${subDirectory}${AppName}`);
|
||||
// Clean URL: Remove special chars, convert spaces to hyphens
|
||||
const cleanUrl = AppName
|
||||
.replace(/[,]/g, '') // Remove commas
|
||||
.replace(/\s+/g, '-') // Spaces to hyphens
|
||||
.replace(/&/g, 'and') // & to 'and'
|
||||
.replace(/[^a-z0-9-]/gi, '') // Remove other special chars
|
||||
.toLowerCase();
|
||||
navigate(`${subDirectory}${cleanUrl}`);
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
|
|
@ -298,6 +316,14 @@ const Navbar = ({
|
|||
PozoApp
|
||||
</div>
|
||||
<div className="navbarOption">
|
||||
<p onClick={navigateAndScrollToTop}>Home</p>
|
||||
<p
|
||||
onClick={handleSolutions}
|
||||
style={{ color: solutionsOpen ? "#1473f8ff" : "" }}
|
||||
>
|
||||
Solutions{" "}
|
||||
{solutionsOpen ? <FaChevronUp size={10} /> : <FaChevronDown size={10} />}
|
||||
</p>
|
||||
<p
|
||||
onClick={handleIndustry}
|
||||
style={{ color: industry ? "#1473f8ff" : "" }}
|
||||
|
|
@ -305,7 +331,6 @@ const Navbar = ({
|
|||
Industries{" "}
|
||||
{industry ? <FaChevronUp size={10} /> : <FaChevronDown size={10} />}
|
||||
</p>
|
||||
<p onClick={scrollToSection}>Offerings </p>
|
||||
<p
|
||||
onClick={handleCompanyList}
|
||||
style={{ color: company ? "#1473f8ff" : "" }}
|
||||
|
|
@ -313,10 +338,36 @@ const Navbar = ({
|
|||
Company{" "}
|
||||
{company ? <FaChevronUp size={10} /> : <FaChevronDown size={10} />}
|
||||
</p>
|
||||
<p onClick={handleBlogPage}>Blog</p>
|
||||
<p onClick={handlePricing}>Pricing</p>
|
||||
<p onClick={handleNavigateContact}>Contact Us </p>
|
||||
<p onClick={handleBlogPage}>Blog</p>
|
||||
<p onClick={() => navigate(`${subDirectory}case-studies`)}>Case Studies</p>
|
||||
<p onClick={handleNavigateContact}>Contact Us</p>
|
||||
</div>
|
||||
{solutionsOpen && (
|
||||
<div className="solutions-dropdown">
|
||||
<div className="solutions-list">
|
||||
<div className="solution-item" onClick={() => navigate(`${subDirectory}solutions/retail-billing`)}>
|
||||
<span>Retail Billing</span>
|
||||
</div>
|
||||
<div className="solution-item" onClick={() => navigate(`${subDirectory}solutions/inventory-purchase`)}>
|
||||
<span>Inventory & Purchase</span>
|
||||
</div>
|
||||
<div className="solution-item" onClick={() => navigate(`${subDirectory}solutions/weighing-scale-pos`)}>
|
||||
<span>Weighing Scale POS</span>
|
||||
</div>
|
||||
<div className="solution-item" onClick={() => navigate(`${subDirectory}solutions/multi-store-erp`)}>
|
||||
<span>Multi-Store ERP</span>
|
||||
</div>
|
||||
<div className="solution-item" onClick={() => navigate(`${subDirectory}solutions/gst-billing-e-invoice`)}>
|
||||
<span>GST Billing & E-Invoice</span>
|
||||
</div>
|
||||
<div className="solution-item" onClick={() => navigate(`${subDirectory}solutions/offline-billing`)}>
|
||||
<span>Offline Billing</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{industry && (
|
||||
<IndustriesList
|
||||
industryRef={industryRef}
|
||||
|
|
@ -327,11 +378,17 @@ const Navbar = ({
|
|||
)}
|
||||
|
||||
<div className="signinBtnNavbar">
|
||||
<div onClick={handleDemoModal}>Book Demo</div>
|
||||
<div onClick={handleNavigateStore}>
|
||||
<sub style={{ fontSize: "14px" }}>Store</sub>
|
||||
<sup>BETA</sup>
|
||||
</div>
|
||||
<div onClick={handleDemoModal}>Get Demo</div>
|
||||
<div
|
||||
onClick={() => window.open("https://wa.me/917324000012", "_blank")}
|
||||
style={{ cursor: "pointer", display: "flex", alignItems: "center", gap: "0.5rem" }}
|
||||
>
|
||||
<FaWhatsapp style={{ fontSize: "20px" }} />
|
||||
</div>
|
||||
{!userId ? (
|
||||
<button onClick={handleSiginOnclick}>
|
||||
Sign in
|
||||
|
|
@ -411,9 +468,42 @@ const Navbar = ({
|
|||
className={`NavbarMenuResponsive ${closingMenu ? "closing" : ""}`}
|
||||
>
|
||||
<div className="ResnavbarOption">
|
||||
<span onClick={navigateAndScrollToTop} className="indusOpen">
|
||||
Home
|
||||
</span>
|
||||
<span onClick={handleSolutionsRes} className="indusOpen">
|
||||
Solutions{" "}
|
||||
{solutionsOpenRes ? (
|
||||
<FaChevronUp size={10} />
|
||||
) : (
|
||||
<FaChevronDown size={10} />
|
||||
)}
|
||||
</span>
|
||||
{solutionsOpenRes && (
|
||||
<div className="solutions-dropdown-mobile">
|
||||
<div className="solution-item-mobile" onClick={() => navigate(`${subDirectory}solutions/retail-billing`)}>
|
||||
Retail Billing
|
||||
</div>
|
||||
<div className="solution-item-mobile" onClick={() => navigate(`${subDirectory}solutions/inventory-purchase`)}>
|
||||
Inventory & Purchase
|
||||
</div>
|
||||
<div className="solution-item-mobile" onClick={() => navigate(`${subDirectory}solutions/weighing-scale-pos`)}>
|
||||
Weighing Scale POS
|
||||
</div>
|
||||
<div className="solution-item-mobile" onClick={() => navigate(`${subDirectory}solutions/multi-store-erp`)}>
|
||||
Multi-Store ERP
|
||||
</div>
|
||||
<div className="solution-item-mobile" onClick={() => navigate(`${subDirectory}solutions/gst-billing-e-invoice`)}>
|
||||
GST Billing & E-Invoice
|
||||
</div>
|
||||
<div className="solution-item-mobile" onClick={() => navigate(`${subDirectory}solutions/offline-billing`)}>
|
||||
Offline Billing
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<span onClick={handleIndustryRes} className="indusOpen">
|
||||
Industries{" "}
|
||||
{industry ? (
|
||||
{industryRes ? (
|
||||
<FaChevronUp size={10} />
|
||||
) : (
|
||||
<FaChevronDown size={10} />
|
||||
|
|
@ -428,9 +518,6 @@ const Navbar = ({
|
|||
/>
|
||||
</>
|
||||
)}
|
||||
{/* <span onClick={scrollToSection} className="indusOpen">
|
||||
Offerings
|
||||
</span> */}
|
||||
<span className="indusOpen" onClick={handleCompanyListRes}>
|
||||
Company <FaChevronDown size={10} />
|
||||
</span>
|
||||
|
|
@ -438,31 +525,36 @@ const Navbar = ({
|
|||
<div className="industryRes">
|
||||
<div className="compnayListsRes">
|
||||
<p onClick={handleAboutUs}>About Us</p>
|
||||
{/* <p>Partnership</p>
|
||||
<p>Events</p> */}
|
||||
{/* <p>Webinars</p> */}
|
||||
<p onClick={handleNavigatePrivacy}>Privacy Policy </p>
|
||||
<p onClick={handleNavigatetestimonials}>Testimonials </p>
|
||||
{/* <p>Terms </p> */}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<span onClick={handleBlogPage} className="indusOpen">
|
||||
Blog{" "}
|
||||
</span>
|
||||
<span onClick={handlePricing} className="indusOpen">
|
||||
Pricing{" "}
|
||||
Pricing
|
||||
</span>
|
||||
<span onClick={handleBlogPage} className="indusOpen">
|
||||
Blog
|
||||
</span>
|
||||
<span onClick={() => navigate(`${subDirectory}case-studies`)} className="indusOpen">
|
||||
Case Studies
|
||||
</span>
|
||||
<span onClick={handleNavigateContact} className="indusOpen">
|
||||
Contact Us{" "}
|
||||
Contact Us
|
||||
</span>
|
||||
</div>
|
||||
<div className="signinBtnNavbarRes">
|
||||
<div onClick={handleDemoModal}>Book Demo</div>
|
||||
<div onClick={handleNavigateStore}>
|
||||
<sub style={{ fontSize: "14px" }}>Store</sub>
|
||||
<sup>BETA</sup>
|
||||
</div>
|
||||
<div onClick={handleDemoModal}>Get Demo</div>
|
||||
<div
|
||||
onClick={() => window.open("https://wa.me/917324000012", "_blank")}
|
||||
style={{ cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", gap: "0.5rem" }}
|
||||
>
|
||||
<FaWhatsapp style={{ fontSize: "20px" }} />
|
||||
</div>
|
||||
<button onClick={handleSiginOnclick}>
|
||||
<div></div>
|
||||
Sign in
|
||||
|
|
@ -476,6 +568,19 @@ const Navbar = ({
|
|||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mobile Sticky Footer for Book Demo & WhatsApp */}
|
||||
<div className="mobile-sticky-footer">
|
||||
<div onClick={handleDemoModal} className="mobile-sticky-btn">
|
||||
Book Demo
|
||||
</div>
|
||||
<div
|
||||
onClick={() => window.open("https://wa.me/917324000012", "_blank")}
|
||||
className="mobile-sticky-btn whatsapp-btn"
|
||||
>
|
||||
<FaWhatsapp style={{ fontSize: "20px" }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import Innovation from "../Images/Innovation.webp";
|
|||
import OverViewVideo from "../Videos/OverView.webm";
|
||||
import AnimatedText from "./AnimatedText/AnimatedText";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { getAdminPanel } from "../../features/AdminPanel/AdminPanel";
|
||||
|
||||
const subDirectory = import.meta.env.BASE_URL;
|
||||
gsap.registerPlugin(ScrollTrigger, SplitText);
|
||||
|
|
@ -22,27 +24,97 @@ const OverView = ({
|
|||
handleModalSignInClose,
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useDispatch();
|
||||
const sloganRef = useRef(null);
|
||||
const featuresRef = useRef([]);
|
||||
const aiCardRef = useRef(null);
|
||||
|
||||
const features = [
|
||||
// 🚀 Dynamic content from CMS
|
||||
const [heroContent, setHeroContent] = useState({
|
||||
mainHeadline: "Retail ERP & POS built for Indian MSMEs — fast billing, smart inventory, GST-ready.",
|
||||
description: "A SaaS platform that empowers Small and Medium Businesses by digitizing operations and reducing Total Cost of Ownership with minimal investment.",
|
||||
ctaButtonText: "Experience Now",
|
||||
ctaButtonLink: "/signin"
|
||||
});
|
||||
|
||||
const [offeringsContent, setOfferingsContent] = useState([
|
||||
{
|
||||
id: 1,
|
||||
icon: Experience,
|
||||
title: "Experience",
|
||||
desc: "Proven expertise delivering real value",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
icon: Innovation,
|
||||
title: "Innovation",
|
||||
desc: "Smarter intelligence for better outcomes",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
icon: CostEfficiency,
|
||||
title: "Cost Efficiency",
|
||||
desc: "Maximum value with minimal cost",
|
||||
},
|
||||
];
|
||||
]);
|
||||
|
||||
// Fetch dynamic content from CMS
|
||||
useEffect(() => {
|
||||
fetchHeroContent();
|
||||
fetchOfferingsContent();
|
||||
}, []);
|
||||
|
||||
const fetchHeroContent = async () => {
|
||||
try {
|
||||
const res = await dispatch(
|
||||
getAdminPanel({ sectionName: "HeroSection" })
|
||||
).unwrap();
|
||||
|
||||
if (res?.data?.statusCode === 1 && res?.data?.data?.length > 0) {
|
||||
const heroData = res.data.data[0];
|
||||
if (heroData.Content) {
|
||||
const content = JSON.parse(heroData.Content);
|
||||
setHeroContent({
|
||||
mainHeadline: content.mainHeadline || heroContent.mainHeadline,
|
||||
description: content.description || heroContent.description,
|
||||
ctaButtonText: content.ctaButtonText || heroContent.ctaButtonText,
|
||||
ctaButtonLink: content.ctaButtonLink || heroContent.ctaButtonLink
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("Using default hero content");
|
||||
}
|
||||
};
|
||||
|
||||
const fetchOfferingsContent = async () => {
|
||||
try {
|
||||
const res = await dispatch(
|
||||
getAdminPanel({ sectionName: "Offerings" })
|
||||
).unwrap();
|
||||
|
||||
if (res?.data?.statusCode === 1 && res?.data?.data?.length > 0) {
|
||||
const offeringsData = res.data.data[0];
|
||||
if (offeringsData.Content) {
|
||||
const content = JSON.parse(offeringsData.Content);
|
||||
if (content.offerings && content.offerings.length > 0) {
|
||||
// Map with icons
|
||||
const mappedOfferings = content.offerings.map(offering => ({
|
||||
...offering,
|
||||
icon: offering.icon === 'experience' ? Experience :
|
||||
offering.icon === 'innovation' ? Innovation :
|
||||
offering.icon === 'cost' ? CostEfficiency : Experience
|
||||
}));
|
||||
setOfferingsContent(mappedOfferings);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("Using default offerings content");
|
||||
}
|
||||
};
|
||||
|
||||
const features = offeringsContent;
|
||||
|
||||
useEffect(() => {
|
||||
// Slogan animation with SplitText
|
||||
|
|
@ -114,18 +186,30 @@ const OverView = ({
|
|||
|
||||
return (
|
||||
<div className="OverView-Master">
|
||||
{/* Background Video */}
|
||||
<video autoPlay muted loop playsInline className="bg-video">
|
||||
<source src={OverViewVideo} type="video/mp4" preload="metadata" />
|
||||
{/* Background Video - Optimized loading */}
|
||||
<video
|
||||
autoPlay
|
||||
muted
|
||||
loop
|
||||
playsInline
|
||||
className="bg-video"
|
||||
preload="none"
|
||||
loading="lazy"
|
||||
>
|
||||
<source src={OverViewVideo} type="video/webm" />
|
||||
{/* <source src="https://csjnrlpkmurliskqkmnp.supabase.co/storage/v1/object/public/Store/PozoAppBg3.mp4" type="video/mp4" /> */}
|
||||
</video>
|
||||
{/* Navbar */}
|
||||
{/* <Navbar /> */}
|
||||
|
||||
{/* Slogan */}
|
||||
{/* Slogan - Dynamic from CMS */}
|
||||
<div className="overviewSlogan" ref={sloganRef}>
|
||||
Streamline... Simplify... <br />
|
||||
Succeed with Pozo Apps
|
||||
{heroContent.mainHeadline.split('\n').map((line, i) => (
|
||||
<React.Fragment key={i}>
|
||||
{line}
|
||||
{i < heroContent.mainHeadline.split('\n').length - 1 && <br />}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Hero Section */}
|
||||
|
|
@ -138,7 +222,7 @@ const OverView = ({
|
|||
className="feature-item"
|
||||
ref={(el) => (featuresRef.current[index] = el)}
|
||||
>
|
||||
<img src={item.icon} alt={item.title} width={40} />
|
||||
<img src={item.icon} alt={item.title} width={40} loading="lazy" />
|
||||
<div className="feature-text">
|
||||
<h3>{item.title}</h3>
|
||||
<p>{item.desc}</p>
|
||||
|
|
@ -151,14 +235,13 @@ const OverView = ({
|
|||
<div className="hero-right">
|
||||
<div className="ai-card">
|
||||
<p>
|
||||
Agentic AI-powered SaaS solutions for businesses of all sizes –
|
||||
from MSME to Enterprises.
|
||||
{heroContent.description}
|
||||
</p>
|
||||
<button
|
||||
className="experience-btn"
|
||||
onClick={() => navigate(`${subDirectory}signin`)}
|
||||
onClick={() => navigate(`${subDirectory}${heroContent.ctaButtonLink.replace(/^\//, '')}`)}
|
||||
>
|
||||
Experience Now
|
||||
{heroContent.ctaButtonText}
|
||||
<div className="icon-container">
|
||||
<HiMiniArrowUpRight className="icon-main" />
|
||||
<HiMiniArrowUpRight className="icon-hover" />
|
||||
|
|
|
|||
|
|
@ -666,6 +666,15 @@ const PricingPozoApp = () => {
|
|||
if (industry) {
|
||||
handleIndustry();
|
||||
}
|
||||
// Clean URL: Remove special chars, convert spaces to hyphens
|
||||
const cleanUrl = AppName
|
||||
.replace(/[,]/g, '') // Remove commas
|
||||
.replace(/\s+/g, '-') // Spaces to hyphens
|
||||
.replace(/&/g, 'and') // & to 'and'
|
||||
.replace(/[^a-z0-9-]/gi, '') // Remove other special chars
|
||||
.toLowerCase();
|
||||
navigate(`${subDirectory}${cleanUrl}`);
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
// Moved loading check after all hooks
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ const ResponsiveApp = () => {
|
|||
};
|
||||
|
||||
const handlePricing = () => {
|
||||
navigate(`${subDirectory}pricing-pozoapp`);
|
||||
navigate(`${subDirectory}pricing`);
|
||||
};
|
||||
|
||||
const handleNavigateStore = () => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import React, { useState, useEffect, useRef } from "react";
|
||||
import "../Styles/SignIn.scss";
|
||||
import pozominilogoWhite from "../Images/pozominilogoWhite.webp";
|
||||
import pozoAppLogo from "../Images/pozoAppLogo.webp";
|
||||
import pozoAppLogo from "../Images/pozoAppLogo.webp";
|
||||
import { RiArrowRightUpLine } from "react-icons/ri";
|
||||
import { FaChevronDown } from "react-icons/fa";
|
||||
import { useNavigate, useLocation } from "react-router-dom";
|
||||
|
|
@ -719,7 +718,7 @@ const SignIn = () => {
|
|||
<div className="inputsTitle">
|
||||
<img
|
||||
className="whitelogoPng"
|
||||
src={pozominilogoWhite}
|
||||
src={pozoAppLogo}
|
||||
alt=""
|
||||
onClick={navigateHomePage}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
import React from "react";
|
||||
import Navbar from "../Components/Navbar";
|
||||
import Footer from "../Components/Footer";
|
||||
import "./CaseStudies.scss";
|
||||
|
||||
const CaseStudies = () => {
|
||||
return (
|
||||
<div className="case-studies-page">
|
||||
<Navbar isScrolled={true} forceTopZero={true} />
|
||||
|
||||
<div className="case-studies-hero">
|
||||
<div className="case-studies-hero-content">
|
||||
<h1>Case Studies</h1>
|
||||
<p>Success stories from businesses powered by PozoApp</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="case-studies-container">
|
||||
<div className="coming-soon-message">
|
||||
<h2>Coming Soon</h2>
|
||||
<p>We're currently working on bringing you inspiring success stories from our clients.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CaseStudies;
|
||||
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
.case-studies-page {
|
||||
min-height: 100vh;
|
||||
background: #000;
|
||||
color: #fff;
|
||||
font-family: "NeueMontreal", sans-serif;
|
||||
}
|
||||
|
||||
.case-studies-hero {
|
||||
padding: 120px 2rem 80px;
|
||||
text-align: center;
|
||||
background: linear-gradient(135deg, #000 0%, #1a1a1a 100%);
|
||||
|
||||
@media (max-width: 768px) {
|
||||
padding: 100px 1.5rem 60px;
|
||||
}
|
||||
|
||||
.case-studies-hero-content {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
|
||||
h1 {
|
||||
font-size: 56px;
|
||||
font-weight: 700;
|
||||
margin: 0 0 1.5rem 0;
|
||||
background: linear-gradient(135deg, #fff 0%, #999 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
font-size: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 22px;
|
||||
color: #999;
|
||||
margin: 0;
|
||||
line-height: 1.5;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.case-studies-container {
|
||||
padding: 120px 2rem;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
padding: 80px 1.5rem;
|
||||
}
|
||||
|
||||
.coming-soon-message {
|
||||
h2 {
|
||||
font-size: 48px;
|
||||
font-weight: 600;
|
||||
margin: 0 0 1.5rem 0;
|
||||
color: #fff;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
font-size: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 20px;
|
||||
color: #999;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,20 +1,9 @@
|
|||
import React, { useEffect, useRef, useState } from "react";
|
||||
import React, { useEffect, useRef, useState, lazy, Suspense } from "react";
|
||||
import Lenis from "@studio-freight/lenis";
|
||||
import { gsap } from "gsap";
|
||||
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||||
import "./HomePage.scss";
|
||||
import { IoClose } from "react-icons/io5";
|
||||
import OverView from "../Components/OverView.jsx";
|
||||
import Offering from "../Components/Offering.jsx";
|
||||
import DigitalSection from "../Components/DigitalSection.jsx";
|
||||
import Footer from "../Components/Footer.jsx";
|
||||
import NoLimt from "../Components/NoLimt.jsx";
|
||||
import TrendingApp from "../Components/TrendingApp.jsx";
|
||||
import FaqSection from "../Components/FaqSection.jsx";
|
||||
import Insiders from "../Components/Insiders.jsx";
|
||||
import Industries from "../Components/Industries.jsx";
|
||||
import PozoVideo from "../Components/PozoVideo.jsx";
|
||||
import Loader from "../Components/Loader/PozoLoader.jsx";
|
||||
import { FaWhatsapp } from "react-icons/fa";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { FaChevronUp } from "react-icons/fa";
|
||||
|
|
@ -27,15 +16,30 @@ import {
|
|||
getAllApplicationData,
|
||||
} from "../../features/publicHome/publicHome";
|
||||
import { getSession, sessionStore } from "../../Services/others";
|
||||
import Navbar from "../Components/Navbar.jsx";
|
||||
import IndustriesList from "../Components/IndustriesList.jsx";
|
||||
import CompanyList from "../Components/companyList.jsx";
|
||||
import BookDemo from "../Components/BookDemo.jsx";
|
||||
import ModalSignIn from "../Components/ModalSignIn.jsx";
|
||||
import SEO from "../../Components/SEO/SEO.jsx";
|
||||
import { getSeo } from "../../features/SEO/seo.js"; // assume this exists
|
||||
import { getSeo } from "../../features/SEO/seo.js";
|
||||
import { getConfigNames } from "../../features/configmasterPage/configmasterPage.js";
|
||||
|
||||
// ✅ Critical imports - Load immediately
|
||||
import Navbar from "../Components/Navbar.jsx";
|
||||
import OverView from "../Components/OverView.jsx";
|
||||
import Loader from "../Components/Loader/PozoLoader.jsx";
|
||||
import SEO from "../../Components/SEO/SEO.jsx";
|
||||
|
||||
// 🚀 Lazy imports - Code split for better performance
|
||||
const Offering = lazy(() => import("../Components/Offering.jsx"));
|
||||
const DigitalSection = lazy(() => import("../Components/DigitalSection.jsx"));
|
||||
const PozoVideo = lazy(() => import("../Components/PozoVideo.jsx"));
|
||||
const TrendingApp = lazy(() => import("../Components/TrendingApp.jsx"));
|
||||
const FaqSection = lazy(() => import("../Components/FaqSection.jsx"));
|
||||
const Insiders = lazy(() => import("../Components/Insiders.jsx"));
|
||||
const Footer = lazy(() => import("../Components/Footer.jsx"));
|
||||
|
||||
// 🎯 Conditional lazy imports - Load only when needed
|
||||
const IndustriesList = lazy(() => import("../Components/IndustriesList.jsx"));
|
||||
const CompanyList = lazy(() => import("../Components/companyList.jsx"));
|
||||
const BookDemo = lazy(() => import("../Components/BookDemo.jsx"));
|
||||
const ModalSignIn = lazy(() => import("../Components/ModalSignIn.jsx"));
|
||||
|
||||
// import og from "../../../public/og/home.jpg"
|
||||
|
||||
const subDirectory = import.meta.env.BASE_URL;
|
||||
|
|
@ -66,68 +70,63 @@ const HomePage = () => {
|
|||
const [seoData, setSeoData] = useState(null);
|
||||
const [allpagesData, setAllpagesData] = useState([]);
|
||||
|
||||
// 🚀 Optimized: All independent API calls run in parallel
|
||||
useEffect(() => {
|
||||
const fetchSEOData = async () => {
|
||||
const initializeData = async () => {
|
||||
try {
|
||||
// Get all pages
|
||||
const Res = await dispatch(
|
||||
getConfigNames({ TypeName: "SEO" })
|
||||
).unwrap();
|
||||
if (Res?.data?.statusCode === 1) {
|
||||
const pages = Res.data.data;
|
||||
// Run all independent API calls in parallel!
|
||||
const [seoConfigRes, appDataRes, tokenRes] = await Promise.all([
|
||||
// SEO Config
|
||||
dispatch(getConfigNames({ TypeName: "SEO" })).unwrap(),
|
||||
// App Data
|
||||
dispatch(getAllApplicationData()).unwrap(),
|
||||
// Token
|
||||
dispatch(PostToken({ username: "1000000001", password: "1234" })).unwrap()
|
||||
]);
|
||||
|
||||
// Process SEO data
|
||||
if (seoConfigRes?.data?.statusCode === 1) {
|
||||
const pages = seoConfigRes.data.data;
|
||||
setAllpagesData(pages);
|
||||
|
||||
// Find Home page ID
|
||||
const SeoId = pages.find((e) => e.ConfigName === "home")?.ConfigId;
|
||||
if (!SeoId) {
|
||||
console.warn("Home page ConfigId not found");
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch SEO for Home page
|
||||
const response = await dispatch(getSeo({ PageId: SeoId })).unwrap();
|
||||
if (response?.data?.statusCode === 1) {
|
||||
const data = response.data.data.find((e) => e.PageId === SeoId);
|
||||
if (data) {
|
||||
setSeoData({
|
||||
metaTitle: data?.MetaTitle,
|
||||
metaDescription: data?.MetaDesc,
|
||||
keywords: data?.Keywords,
|
||||
imageAltText: data?.ImgAltText,
|
||||
});
|
||||
}
|
||||
if (SeoId) {
|
||||
// Fetch SEO details (non-blocking)
|
||||
dispatch(getSeo({ PageId: SeoId })).unwrap().then((response) => {
|
||||
if (response?.data?.statusCode === 1) {
|
||||
const data = response.data.data.find((e) => e.PageId === SeoId);
|
||||
if (data) {
|
||||
setSeoData({
|
||||
metaTitle: data?.MetaTitle,
|
||||
metaDescription: data?.MetaDesc,
|
||||
keywords: data?.Keywords,
|
||||
imageAltText: data?.ImgAltText,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Process App data
|
||||
if (appDataRes?.data?.statusCode === 1) {
|
||||
const activeApps = appDataRes?.data?.data?.filter(
|
||||
(value) => value?.ActiveStatus === "A"
|
||||
);
|
||||
setAppCategory(activeApps);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error fetching SEO data:", error);
|
||||
console.error("Error initializing data:", error);
|
||||
}
|
||||
};
|
||||
|
||||
fetchSEOData();
|
||||
}, [dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
getAppData();
|
||||
initializeData();
|
||||
}, []);
|
||||
|
||||
const getAppData = async () => {
|
||||
try {
|
||||
const response = await dispatch(getAllApplicationData()).unwrap();
|
||||
if (response?.data?.statusCode === 1) {
|
||||
let finalsubCategory = response?.data?.data?.filter(
|
||||
(value) => value?.ActiveStatus === "A"
|
||||
);
|
||||
setAppCategory(finalsubCategory);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching app data:", error);
|
||||
}
|
||||
};
|
||||
console.log(AppCategory, "AppCategory");
|
||||
|
||||
useEffect(() => {
|
||||
// Simulate loading delay
|
||||
const timer = setTimeout(() => setLoading(false), 100);
|
||||
// Show page immediately - don't wait!
|
||||
const timer = setTimeout(() => setLoading(false), 300);
|
||||
|
||||
// Lenis smooth scrolling
|
||||
const lenisInstance = new Lenis({
|
||||
|
|
@ -159,55 +158,44 @@ const HomePage = () => {
|
|||
};
|
||||
}, []);
|
||||
|
||||
// Separate useEffect for API calls
|
||||
// 🚀 Optimized: Fetch categories in parallel with other data (if needed for navbar)
|
||||
useEffect(() => {
|
||||
const fetchConfigName = async () => {
|
||||
setSubCategory([]);
|
||||
setAppCategory([]);
|
||||
const response = await dispatch(getCategoryData()).unwrap();
|
||||
if (response?.data?.statusCode === 1) {
|
||||
let finalCategory = response?.data?.data;
|
||||
setCategory(finalCategory);
|
||||
}
|
||||
};
|
||||
|
||||
const Tokens = async () => {
|
||||
let data = {
|
||||
username: "1000000001",
|
||||
password: "1234",
|
||||
};
|
||||
const fetchCategoryData = async () => {
|
||||
try {
|
||||
await dispatch(PostToken(data)).unwrap();
|
||||
const response = await dispatch(getCategoryData()).unwrap();
|
||||
if (response?.data?.statusCode === 1) {
|
||||
const finalCategory = response?.data?.data;
|
||||
setCategory(finalCategory);
|
||||
|
||||
// Auto-fetch first subcategory (non-blocking)
|
||||
if (finalCategory?.[0]?.CateId) {
|
||||
dispatch(getSubCategoryData(finalCategory[0].CateId)).unwrap()
|
||||
.then((subRes) => {
|
||||
if (subRes?.data?.statusCode === 1) {
|
||||
const activeSubCat = subRes?.data?.data?.filter(
|
||||
(value) => value.ActiveStatus === "A"
|
||||
);
|
||||
setSubCategory(activeSubCat);
|
||||
}
|
||||
})
|
||||
.catch((err) => console.error("Error fetching subcategory:", err));
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching token:", error);
|
||||
console.error("Error fetching categories:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const initializeData = async () => {
|
||||
await fetchConfigName();
|
||||
await Tokens();
|
||||
};
|
||||
initializeData();
|
||||
}, []);
|
||||
// Auto-fetch subcategories when categories load
|
||||
useEffect(() => {
|
||||
const getSubCategory = async (cateId) => {
|
||||
// setAppCategory([]);
|
||||
const response = await dispatch(getSubCategoryData(cateId)).unwrap();
|
||||
if (response?.data?.statusCode === 1) {
|
||||
let finalsubCategory = response?.data?.data?.filter(
|
||||
(value) => value.ActiveStatus === "A"
|
||||
);
|
||||
setSubCategory(finalsubCategory);
|
||||
}
|
||||
};
|
||||
|
||||
if (Category?.[0]?.CateId != undefined) {
|
||||
getSubCategory(Category?.[0]?.CateId);
|
||||
// Only fetch if needed for navbar/menu
|
||||
if (AppCategory.length > 0) {
|
||||
// Already have app data, skip category fetch
|
||||
} else {
|
||||
fetchCategoryData();
|
||||
}
|
||||
}, [Category]);
|
||||
}, [AppCategory]);
|
||||
|
||||
// Auto-fetch apps when subcategories load
|
||||
// Commented out - not needed with getAllApplicationData
|
||||
// useEffect(() => {
|
||||
// const getAppData = async (subcatId) => {
|
||||
// const response = await dispatch(getApplicationData(subcatId)).unwrap();
|
||||
|
|
@ -224,8 +212,6 @@ const HomePage = () => {
|
|||
// }
|
||||
// }, [SubCategory]);
|
||||
|
||||
if (loading) return <Loader />;
|
||||
|
||||
const scrollToTop = () => {
|
||||
if (lenis) {
|
||||
lenis.scrollTo(0, { duration: 1.5 });
|
||||
|
|
@ -235,7 +221,16 @@ const HomePage = () => {
|
|||
};
|
||||
|
||||
const redirectApp = async (AppName, AppId) => {
|
||||
navigate(`${subDirectory}${AppName}`);
|
||||
sessionStore("AppId", AppId);
|
||||
sessionStore("AppName", AppName);
|
||||
// Clean URL: Remove special chars, convert spaces to hyphens
|
||||
const cleanUrl = AppName
|
||||
.replace(/[,]/g, '') // Remove commas
|
||||
.replace(/\s+/g, '-') // Spaces to hyphens
|
||||
.replace(/&/g, 'and') // & to 'and'
|
||||
.replace(/[^a-z0-9-]/gi, '') // Remove other special chars
|
||||
.toLowerCase();
|
||||
navigate(`${subDirectory}${cleanUrl}`);
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
|
|
@ -329,32 +324,30 @@ const HomePage = () => {
|
|||
handleModalSignInClose={handleModalSignInClose}
|
||||
/>
|
||||
</section>
|
||||
<section>
|
||||
<Offering />
|
||||
</section>
|
||||
<section>
|
||||
<DigitalSection />
|
||||
</section>
|
||||
<section>
|
||||
<PozoVideo />
|
||||
</section>
|
||||
|
||||
{/* Application DropDown */}
|
||||
{/* <section>
|
||||
<Industries />
|
||||
</section> */}
|
||||
<section>
|
||||
<TrendingApp />
|
||||
</section>
|
||||
<section>
|
||||
<FaqSection />
|
||||
</section>
|
||||
<section>
|
||||
<Insiders />
|
||||
</section>
|
||||
<section>
|
||||
<Footer />
|
||||
</section>
|
||||
<Suspense fallback={null}>
|
||||
<section>
|
||||
<Offering />
|
||||
</section>
|
||||
<section>
|
||||
<DigitalSection />
|
||||
</section>
|
||||
<section>
|
||||
<PozoVideo />
|
||||
</section>
|
||||
<section>
|
||||
<TrendingApp />
|
||||
</section>
|
||||
<section>
|
||||
<FaqSection />
|
||||
</section>
|
||||
<section>
|
||||
<Insiders />
|
||||
</section>
|
||||
<section>
|
||||
<Footer AppCategory={AppCategory} />
|
||||
</section>
|
||||
</Suspense>
|
||||
|
||||
<div
|
||||
className="folatingWhatsapp"
|
||||
|
|
@ -371,24 +364,36 @@ const HomePage = () => {
|
|||
)}
|
||||
|
||||
{industry && (
|
||||
<IndustriesList
|
||||
industryRef={industryRef}
|
||||
closingIndustry={closingIndustry}
|
||||
AppCategory={AppCategory}
|
||||
redirectApp={redirectApp}
|
||||
/>
|
||||
<Suspense fallback={null}>
|
||||
<IndustriesList
|
||||
industryRef={industryRef}
|
||||
closingIndustry={closingIndustry}
|
||||
AppCategory={AppCategory}
|
||||
redirectApp={redirectApp}
|
||||
/>
|
||||
</Suspense>
|
||||
)}
|
||||
|
||||
{company && (
|
||||
<CompanyList
|
||||
companyRef={companyRef}
|
||||
closingCompany={closingCompany}
|
||||
/>
|
||||
<Suspense fallback={null}>
|
||||
<CompanyList
|
||||
companyRef={companyRef}
|
||||
closingCompany={closingCompany}
|
||||
/>
|
||||
</Suspense>
|
||||
)}
|
||||
|
||||
{demoModal && <BookDemo onClose={handleDemoModalClose} />}
|
||||
{demoModal && (
|
||||
<Suspense fallback={null}>
|
||||
<BookDemo onClose={handleDemoModalClose} />
|
||||
</Suspense>
|
||||
)}
|
||||
|
||||
{modalSignIn && <ModalSignIn onClose={handleModalSignInClose} />}
|
||||
{modalSignIn && (
|
||||
<Suspense fallback={null}>
|
||||
<ModalSignIn onClose={handleModalSignInClose} />
|
||||
</Suspense>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
import React from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import "./Solutions.scss";
|
||||
import Navbar from "../Components/Navbar";
|
||||
import Footer from "../Components/Footer";
|
||||
|
||||
const subDirectory = import.meta.env.BASE_URL;
|
||||
|
||||
const Solutions = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const solutions = [
|
||||
{
|
||||
id: 1,
|
||||
title: "Retail Billing",
|
||||
description: "Fast, intuitive billing system for retail stores with GST compliance",
|
||||
icon: "🛒",
|
||||
path: "retail-billing",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Inventory & Purchase",
|
||||
description: "Smart inventory management with real-time stock tracking",
|
||||
icon: "📦",
|
||||
path: "inventory-purchase",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "Weighing Scale POS",
|
||||
description: "Integrated weighing scale with POS for seamless billing",
|
||||
icon: "⚖️",
|
||||
path: "weighing-scale-pos",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "Multi-Store ERP",
|
||||
description: "Manage multiple stores from one centralized platform",
|
||||
icon: "🏪",
|
||||
path: "multi-store-erp",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: "GST Billing & E-Invoice",
|
||||
description: "GST-ready billing with automated e-invoice generation",
|
||||
icon: "📄",
|
||||
path: "gst-billing-e-invoice",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
title: "Offline Billing",
|
||||
description: "Continue billing even without internet connectivity",
|
||||
icon: "📴",
|
||||
path: "offline-billing",
|
||||
},
|
||||
];
|
||||
|
||||
const handleSolutionClick = (path) => {
|
||||
navigate(`${subDirectory}solutions/${path}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="solutions-page">
|
||||
<Navbar isScrolled={true} forceTopZero={true} />
|
||||
|
||||
<div className="solutions-hero">
|
||||
<div className="solutions-hero-content">
|
||||
<h1>Our Solutions</h1>
|
||||
<p>Comprehensive retail management solutions for Indian MSMEs</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="solutions-grid-container">
|
||||
<div className="solutions-grid">
|
||||
{solutions.map((solution) => (
|
||||
<div
|
||||
key={solution.id}
|
||||
className="solution-card"
|
||||
onClick={() => handleSolutionClick(solution.path)}
|
||||
>
|
||||
<div className="solution-icon">{solution.icon}</div>
|
||||
<h3>{solution.title}</h3>
|
||||
<p>{solution.description}</p>
|
||||
<button className="solution-btn">
|
||||
Learn More →
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Solutions;
|
||||
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
.solutions-page {
|
||||
min-height: 100vh;
|
||||
background: #000;
|
||||
color: #fff;
|
||||
font-family: "NeueMontreal", sans-serif;
|
||||
}
|
||||
|
||||
.solutions-hero {
|
||||
padding: 120px 2rem 80px;
|
||||
text-align: center;
|
||||
background: linear-gradient(135deg, #000 0%, #1a1a1a 100%);
|
||||
|
||||
@media (max-width: 768px) {
|
||||
padding: 100px 1.5rem 60px;
|
||||
}
|
||||
|
||||
.solutions-hero-content {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
|
||||
h1 {
|
||||
font-size: 56px;
|
||||
font-weight: 700;
|
||||
margin: 0 0 1.5rem 0;
|
||||
background: linear-gradient(135deg, #fff 0%, #999 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
font-size: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 22px;
|
||||
color: #999;
|
||||
margin: 0;
|
||||
line-height: 1.5;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.solutions-grid-container {
|
||||
padding: 80px 2rem 120px;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
padding: 60px 1.5rem 80px;
|
||||
}
|
||||
}
|
||||
|
||||
.solutions-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
||||
gap: 2rem;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.solution-card {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 16px;
|
||||
padding: 2.5rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
@media (max-width: 768px) {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.solution-icon {
|
||||
font-size: 48px;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
margin: 0 0 1rem 0;
|
||||
color: #fff;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
font-size: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 16px;
|
||||
color: #999;
|
||||
line-height: 1.6;
|
||||
margin: 0 0 1.5rem 0;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.solution-btn {
|
||||
background: transparent;
|
||||
border: 1px solid #fff;
|
||||
color: #fff;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 6px;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
font-family: inherit;
|
||||
|
||||
&:hover {
|
||||
background: #fff;
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,17 +1,24 @@
|
|||
.Footer-Master {
|
||||
width: 100%;
|
||||
background-color: #010101;
|
||||
padding: 1.5rem 4rem 0 1.5rem;
|
||||
// padding: 3rem 4rem 2rem 4rem;
|
||||
padding: 2rem 1rem 1rem 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 2rem;
|
||||
gap: 4rem;
|
||||
font-family: "NeueMontreal";
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
gap: 3rem;
|
||||
padding: 2.5rem 2rem 2rem 2rem;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
padding: 1rem 1rem 1rem 1rem;
|
||||
padding: 2rem 1.5rem 1.5rem 1.5rem;
|
||||
gap: 2.5rem;
|
||||
}
|
||||
|
||||
.footerLeft {
|
||||
|
|
@ -28,12 +35,13 @@
|
|||
|
||||
div {
|
||||
text-align: left;
|
||||
font-size: 16px;
|
||||
font-size: 23px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.clutter {
|
||||
font-size: 16px;
|
||||
font-size: 16px !important;
|
||||
|
||||
text-align: left;
|
||||
margin-top: 1rem;
|
||||
|
||||
|
|
@ -70,53 +78,307 @@
|
|||
color: #fff;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
@media (max-width: 500px) {
|
||||
gap: 2rem;
|
||||
flex: 1;
|
||||
max-width: 1000px;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
flex-direction: column;
|
||||
margin-bottom: 3rem;
|
||||
gap: 2rem;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.footerProducts {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 8px;
|
||||
column-gap: 2rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
width: 100%;
|
||||
max-width: 1100px;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
// Top Bar - Everything in one line
|
||||
.products-top-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2rem;
|
||||
margin-bottom: 1.5rem;
|
||||
flex-wrap: wrap;
|
||||
|
||||
div {
|
||||
font-size: 18px;
|
||||
font-family: "NeueMontreal";
|
||||
font-weight: 400;
|
||||
grid-column: span 3;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
grid-column: span 2;
|
||||
@media (max-width: 900px) {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 13.5px;
|
||||
// Main "Products" heading
|
||||
.products-heading {
|
||||
font-size: 18px;
|
||||
font-family: "NeueMontreal";
|
||||
font-weight: 400;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
flex-shrink: 0;
|
||||
|
||||
&:hover {
|
||||
color: #418df7;
|
||||
@media (max-width: 900px) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Search Box (in top bar)
|
||||
.products-search-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
max-width: 350px;
|
||||
|
||||
@media (max-width: 900px) {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.products-search-icon {
|
||||
position: absolute;
|
||||
left: 16px;
|
||||
font-size: 18px;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.products-search-input {
|
||||
width: 100%;
|
||||
padding: 10px 40px 10px 45px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 8px;
|
||||
color: #fff;
|
||||
font-family: "NeueMontreal";
|
||||
font-size: 14px;
|
||||
transition: all 0.3s ease;
|
||||
outline: none;
|
||||
|
||||
&::placeholder {
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
border-color: #3588fd;
|
||||
box-shadow: 0 0 0 3px rgba(53, 136, 253, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.products-search-clear {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
background: none;
|
||||
border: none;
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
padding: 4px 8px;
|
||||
transition: all 0.2s ease;
|
||||
opacity: 0.6;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Search Results Count
|
||||
.products-search-results-count {
|
||||
font-size: 12px;
|
||||
color: #888;
|
||||
margin-bottom: 1rem;
|
||||
font-family: "NeueMontreal";
|
||||
}
|
||||
|
||||
// Search Results
|
||||
.footer-search-results {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 0.5rem 2rem;
|
||||
margin-top: 1rem;
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.search-result-item {
|
||||
font-size: 14px;
|
||||
font-family: "NeueMontreal";
|
||||
font-weight: 400;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
transition: all 0.25s ease;
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
background: rgba(53, 136, 253, 0.05);
|
||||
border: 1px solid rgba(53, 136, 253, 0.1);
|
||||
|
||||
&:hover {
|
||||
color: #3588fd;
|
||||
background: rgba(53, 136, 253, 0.15);
|
||||
border-color: rgba(53, 136, 253, 0.3);
|
||||
transform: translateX(3px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No Results
|
||||
.footer-no-results {
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
color: #888;
|
||||
font-family: "NeueMontreal";
|
||||
font-size: 14px;
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
color: #888 !important;
|
||||
cursor: default !important;
|
||||
|
||||
&:hover {
|
||||
color: #888 !important;
|
||||
transform: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Navigation Controls (in top bar)
|
||||
.footer-navigation {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.8rem;
|
||||
margin-left: auto;
|
||||
flex-shrink: 0;
|
||||
|
||||
@media (max-width: 900px) {
|
||||
margin-left: 0;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.footer-nav-btn {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
color: #fff;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 6px;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 300;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
background: rgba(53, 136, 253, 0.2);
|
||||
border-color: #3588fd;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.3;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-page-indicator {
|
||||
font-size: 12px;
|
||||
color: #888;
|
||||
font-family: "NeueMontreal";
|
||||
min-width: 60px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
// Container for columns
|
||||
.footer-columns-wrapper {
|
||||
display: flex;
|
||||
gap: 4rem;
|
||||
// min-height: 300px;
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
gap: 3rem;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
flex-direction: column;
|
||||
gap: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
// Individual columns
|
||||
.footer-column {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.2rem;
|
||||
min-width: 0;
|
||||
|
||||
// Category headers (Food & Beverages, Wellness, etc.)
|
||||
.footer-category {
|
||||
font-size: 11px;
|
||||
font-family: "NeueMontreal";
|
||||
font-weight: 500;
|
||||
color: #888;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.8px;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
// Product links
|
||||
p {
|
||||
font-size: 13px;
|
||||
font-family: "NeueMontreal";
|
||||
font-weight: 400;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
transition: all 0.25s ease;
|
||||
line-height: 1.9;
|
||||
padding: 0px 0;
|
||||
text-wrap: nowrap;
|
||||
|
||||
&:hover {
|
||||
color: #3588fd;
|
||||
transform: translateX(3px);
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
font-size: 13.5px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footerContact {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
min-width: 100px;
|
||||
|
||||
div {
|
||||
font-size: 18px;
|
||||
font-family: "NeueMontreal";
|
||||
font-weight: 400;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
a {
|
||||
|
|
@ -126,10 +388,12 @@
|
|||
cursor: pointer;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
transition: all 0.3s ease;
|
||||
transition: all 0.25s ease;
|
||||
line-height: 1.8;
|
||||
|
||||
&:hover {
|
||||
color: #418df7;
|
||||
color: #3588fd;
|
||||
transform: translateX(3px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -137,25 +401,31 @@
|
|||
.footePhone {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.5rem;
|
||||
min-width: 100px;
|
||||
|
||||
div {
|
||||
font-size: 18px;
|
||||
font-family: "NeueMontreal";
|
||||
font-weight: 400;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
a {
|
||||
font-size: 13px;
|
||||
font-size: 14px;
|
||||
font-family: "NeueMontreal";
|
||||
font-weight: 400;
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
transition: all 0.3s ease;
|
||||
transition: all 0.25s ease;
|
||||
line-height: 1.8;
|
||||
letter-spacing: 0.3px;
|
||||
|
||||
&:hover {
|
||||
color: #418df7;
|
||||
color: #3588fd;
|
||||
transform: translateX(3px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -163,10 +433,9 @@
|
|||
|
||||
.policyDiv {
|
||||
background-color: #010101;
|
||||
padding: 0 1rem 2.5rem 1rem;
|
||||
padding: 0 1rem 0.5rem 1rem;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
|
|
|
|||
|
|
@ -135,6 +135,82 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Solutions Dropdown
|
||||
.solutions-dropdown {
|
||||
position: fixed;
|
||||
top: 4.5rem;
|
||||
left: 12%;
|
||||
background-color: #fff;
|
||||
// padding: 1.5rem 2rem;
|
||||
border-radius: 12px;
|
||||
animation: fadeInIndustry 0.3s ease;
|
||||
box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px;
|
||||
z-index: 100;
|
||||
min-width: 280px;
|
||||
max-width: 320px;
|
||||
|
||||
.solutions-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
|
||||
.solution-item {
|
||||
padding: 0.6rem 1rem;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s ease;
|
||||
color: #000;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.3px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #1473f8;
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.solutions-dropdown-mobile {
|
||||
padding: 0.5rem 0 0.5rem 1.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
margin: 0.5rem 0;
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
border-radius: 6px;
|
||||
|
||||
.solution-item-mobile {
|
||||
padding: 0.75rem 1rem;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s;
|
||||
color: #e5e5e5;
|
||||
font-size: 13px;
|
||||
letter-spacing: 0.3px;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #1473f8;
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: #1473f8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.IndustriesTypes {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
|
@ -679,6 +755,67 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Mobile Sticky Footer for Book Demo & WhatsApp
|
||||
.mobile-sticky-footer {
|
||||
display: none;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
|
||||
backdrop-filter: blur(20px);
|
||||
box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.12);
|
||||
padding: 1rem 1.25rem;
|
||||
gap: 1rem;
|
||||
z-index: 999;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.08);
|
||||
|
||||
@media (max-width: 768px) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.mobile-sticky-btn {
|
||||
flex: 1;
|
||||
padding: 1rem 1.75rem;
|
||||
background: linear-gradient(135deg, #000 0%, #1a1a1a 100%);
|
||||
color: #fff;
|
||||
border-radius: 12px;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: "NeueMontreal", sans-serif;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
letter-spacing: 0.3px;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
&.whatsapp-btn {
|
||||
background: linear-gradient(135deg, #25D366 0%, #1ea952 100%);
|
||||
flex: 0;
|
||||
min-width: 60px;
|
||||
padding: 1rem;
|
||||
box-shadow: 0 4px 12px rgba(37, 211, 102, 0.3);
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 6px 16px rgba(37, 211, 102, 0.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInMenu {
|
||||
from {
|
||||
opacity: 0;
|
||||
|
|
|
|||
|
|
@ -141,11 +141,12 @@
|
|||
@media (max-width: 768px) {
|
||||
.slide {
|
||||
width: 300px;
|
||||
height: 60vh;
|
||||
height: 50vh;
|
||||
}
|
||||
|
||||
.slide-track {
|
||||
width: calc(200% + 1rem);
|
||||
width: calc(1000% + 1rem);
|
||||
animation: scroll 12s linear infinite;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
.OverView-Master {
|
||||
width: 100vw;
|
||||
height: 115vh;
|
||||
min-height: 100vh;
|
||||
height: auto;
|
||||
background: #000;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -42,8 +43,9 @@
|
|||
|
||||
// Slogan - Hero Title
|
||||
.overviewSlogan {
|
||||
font-size: 5vw;
|
||||
font-size: 4.5vw;
|
||||
font-weight: 500;
|
||||
width:80vw;
|
||||
line-height: 1.2;
|
||||
margin: 6.5rem 1.5rem 0 1.5rem;
|
||||
position: relative;
|
||||
|
|
@ -83,9 +85,10 @@
|
|||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
align-items: flex-start;
|
||||
margin: 0 1.5rem;
|
||||
margin-top: 5.5rem;
|
||||
margin-bottom: 3rem;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
gap: 3rem;
|
||||
|
|
@ -125,11 +128,12 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.2rem;
|
||||
justify-content: flex-end;
|
||||
justify-content: flex-start;
|
||||
flex: 1;
|
||||
min-height: fit-content;
|
||||
@media (max-width: 600px) {
|
||||
gap: 1rem;
|
||||
padding:16px 0;
|
||||
padding: 16px 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -267,7 +271,7 @@
|
|||
-webkit-backdrop-filter: blur(30px);
|
||||
border-radius: 20px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||
padding: 2rem;
|
||||
padding: 1.75rem;
|
||||
max-width: 500px;
|
||||
margin-right: 5rem;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
||||
|
|
@ -318,10 +322,10 @@
|
|||
}
|
||||
|
||||
p {
|
||||
font-size: 24px;
|
||||
font-size: 22px;
|
||||
font-family: "NeueMontreal";
|
||||
line-height: 1.4;
|
||||
margin: 0 0 1.5rem 0;
|
||||
line-height: 1.35;
|
||||
margin: 0 0 1.25rem 0;
|
||||
color: #fff;
|
||||
font-weight: 400;
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
1027
src/check.jsx
1027
src/check.jsx
File diff suppressed because it is too large
Load Diff
|
|
@ -15,6 +15,7 @@
|
|||
align-items: center;
|
||||
gap: 16px;
|
||||
position: relative;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -28,6 +29,7 @@
|
|||
gap: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
svg {
|
||||
margin-top: 4px;
|
||||
display: flex;
|
||||
|
|
@ -108,6 +110,7 @@
|
|||
transform: translate(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
sup {
|
||||
font-size: 10px;
|
||||
background-color: #e68200;
|
||||
|
|
@ -124,6 +127,7 @@
|
|||
cursor: pointer;
|
||||
letter-spacing: 0.2px;
|
||||
-webkit-text-stroke: 0.2px;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
z-index: 50;
|
||||
position: relative;
|
||||
|
|
@ -136,7 +140,7 @@
|
|||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
width: 80%;
|
||||
margin-bottom: 4rem;
|
||||
margin-bottom: 0;
|
||||
gap: 1rem;
|
||||
position: fixed;
|
||||
top: 4rem;
|
||||
|
|
@ -146,8 +150,12 @@
|
|||
border-radius: 12px;
|
||||
animation: fadeInIndustry 0.5s ease;
|
||||
height: 85vh;
|
||||
max-height: calc(100vh - 5rem);
|
||||
box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px;
|
||||
z-index: 100;
|
||||
overflow: hidden;
|
||||
isolation: isolate;
|
||||
touch-action: none;
|
||||
|
||||
&.closing {
|
||||
animation: fadeOutIndustry 0.4s ease;
|
||||
|
|
@ -158,17 +166,41 @@
|
|||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.IndustriesOne,
|
||||
.IndustriesTwo,
|
||||
.IndustriesThree {
|
||||
width: 30%;
|
||||
font-family: "NeueMontreal";
|
||||
height: 100%;
|
||||
max-height: calc(85vh - 4rem);
|
||||
border-right: 2px dashed #9e9e9e;
|
||||
height: 80vh;
|
||||
overflow: auto;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
scrollbar-width: thin;
|
||||
padding-bottom: 4rem;
|
||||
padding-bottom: 2rem;
|
||||
padding-right: 1rem;
|
||||
overscroll-behavior: contain;
|
||||
touch-action: pan-y;
|
||||
|
||||
// Custom scrollbar styling
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #888;
|
||||
border-radius: 10px;
|
||||
|
||||
&:hover {
|
||||
background: #555;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
width: 100%;
|
||||
|
|
@ -203,6 +235,7 @@
|
|||
&:hover {
|
||||
color: #3588fd;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #ffffff;
|
||||
background-color: rgba(255, 115, 0, 0.966);
|
||||
|
|
@ -223,6 +256,7 @@
|
|||
z-index: 100;
|
||||
position: relative;
|
||||
display: none;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
display: flex;
|
||||
}
|
||||
|
|
@ -247,10 +281,12 @@
|
|||
&.closing {
|
||||
animation: fadeOutMenu 0.4s ease;
|
||||
}
|
||||
|
||||
@media (max-width: 1300px) {
|
||||
top: 8%;
|
||||
}
|
||||
}
|
||||
|
||||
.ResNavHeader {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
|
@ -258,12 +294,14 @@
|
|||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.ResNavHeaderClose {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: "NeueMontreal";
|
||||
gap: 4px;
|
||||
cursor: pointer;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -271,6 +309,7 @@
|
|||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.ResnavbarOption {
|
||||
width: 100%;
|
||||
font-family: "NeueMontreal";
|
||||
|
|
@ -279,6 +318,7 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
|
||||
.indusOpen {
|
||||
font-size: 16px;
|
||||
display: flex;
|
||||
|
|
@ -289,7 +329,38 @@
|
|||
border-bottom: 2px dashed #868686;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.IndustriesTypes {
|
||||
position: relative;
|
||||
top: unset;
|
||||
left: unset;
|
||||
width: 100%;
|
||||
background-color: #383838;
|
||||
color: #fff;
|
||||
overflow: auto;
|
||||
isolation: unset;
|
||||
touch-action: unset;
|
||||
height: 70vh;
|
||||
box-shadow: unset !important;
|
||||
}
|
||||
|
||||
.IndustriesOne,
|
||||
.IndustriesTwo,
|
||||
.IndustriesThree {
|
||||
border-right: none;
|
||||
height: max-content;
|
||||
max-height: 40vh;
|
||||
margin-bottom: 2rem;
|
||||
|
||||
>div,
|
||||
>p {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.industryRes {
|
||||
background-color: #383838;
|
||||
color: #fff;
|
||||
|
|
@ -312,12 +383,14 @@
|
|||
font-size: 16px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: "NeueMontreal";
|
||||
font-size: 14px;
|
||||
margin-bottom: 4px;
|
||||
color: #cecece;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #3588fd;
|
||||
}
|
||||
|
|
@ -331,6 +404,7 @@
|
|||
margin-bottom: 4px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
color: #3588fd;
|
||||
}
|
||||
|
|
@ -345,6 +419,7 @@
|
|||
font-family: "NeueMontreal";
|
||||
margin-top: 3rem;
|
||||
width: 100%;
|
||||
|
||||
sup {
|
||||
font-size: 10px;
|
||||
background-color: #e68200;
|
||||
|
|
@ -421,12 +496,14 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInMenu {
|
||||
from {
|
||||
opacity: 0;
|
||||
// transform: translateY(-50px);
|
||||
height: 0vh;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
// transform: translateY(0);
|
||||
|
|
@ -440,18 +517,21 @@
|
|||
// transform: translateY(0);
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
// transform: translateY(-50px);
|
||||
height: 0vh;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInIndustry {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
height: 0vh;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
|
|
@ -465,18 +545,21 @@
|
|||
height: 80vh;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
height: 0vh;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInCompany {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
|
|
@ -490,6 +573,7 @@
|
|||
height: 250px;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
height: 0px;
|
||||
|
|
@ -502,6 +586,7 @@
|
|||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
|
|
@ -513,6 +598,7 @@
|
|||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
|
|
@ -524,6 +610,7 @@
|
|||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
|
|
@ -535,6 +622,7 @@
|
|||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
|
|
@ -546,6 +634,7 @@
|
|||
opacity: 0;
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
|
|
@ -557,6 +646,7 @@
|
|||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateX(100%);
|
||||
|
|
@ -588,6 +678,7 @@
|
|||
cursor: pointer;
|
||||
letter-spacing: 0.2px;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
color: #3588fd;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,11 +93,14 @@ import SignIn from "./PozoApp/Components/SignIn.jsx";
|
|||
import LiveSession from "./PozoApp/Components/LiveSession.jsx";
|
||||
import ContactUs from "./PozoApp/Components/ContactUs.jsx";
|
||||
import PricingPozoApp from "./PozoApp/Components/PricingPozoApp.jsx";
|
||||
import Solutions from "./PozoApp/Pages/Solutions.jsx";
|
||||
import CaseStudies from "./PozoApp/Pages/CaseStudies.jsx";
|
||||
import GatewayMasterConfiguration from "./Pages/GatewayMasterConfiguration/GatewayMasterConfiguration.jsx";
|
||||
import GatewayMasterConfigurationList from "./Pages/GatewayMasterConfiguration/GatewayMasterConfigurationList.jsx";
|
||||
import AdminPanelWrapper from "./AdminPanel/AdminPanelWrapper.jsx";
|
||||
import Blog from "./AdminPanel/Blog/Blog.jsx";
|
||||
import BlogDetail from "./AdminPanel/Blog/BlogDetail.jsx";
|
||||
import LandingPageCMS from "./LandingPageCMS/LandingPageCMS.jsx";
|
||||
import PostEditorPage from "./Pages/PostEditorPage.jsx";
|
||||
import PrivacyPolicy from "./PozoApp/Company/PrivacyPolicy.jsx";
|
||||
import CookiePolicy from "./PozoApp/Company/CookiePolicy.jsx";
|
||||
|
|
@ -117,6 +120,12 @@ export const routesConfig = [
|
|||
access: "Marketing",
|
||||
empAccess: "Admin Panel",
|
||||
},
|
||||
{
|
||||
path: `${subDirectory}landing-cms`,
|
||||
component: LandingPageCMS,
|
||||
access: "Marketing",
|
||||
empAccess: "Admin Panel",
|
||||
},
|
||||
{ path: `${subDirectory}:appName`, component: Template, access: "Public" },
|
||||
{ path: `${subDirectory}feature1`, component: Feature1 },
|
||||
{ path: `${subDirectory}pdf`, component: PdfPage, access: "Admin" },
|
||||
|
|
@ -168,7 +177,7 @@ export const routesConfig = [
|
|||
{ path: `${subDirectory}homepage`, component: PublicHome, access: "Public" },
|
||||
// { path: `${subDirectory}signinnew`, component: SignIn, access: "Public" },
|
||||
{
|
||||
path: `${subDirectory}pricing-pozoapp`,
|
||||
path: `${subDirectory}pricing`,
|
||||
component: PricingPozoApp,
|
||||
access: "Public",
|
||||
},
|
||||
|
|
@ -178,6 +187,8 @@ export const routesConfig = [
|
|||
access: "Public",
|
||||
},
|
||||
{ path: `${subDirectory}contact-us`, component: ContactUs, access: "Public" },
|
||||
{ path: `${subDirectory}solutions`, component: Solutions, access: "Public" },
|
||||
{ path: `${subDirectory}case-studies`, component: CaseStudies, access: "Public" },
|
||||
{ path: `${subDirectory}blog`, component: Blog, access: "Public" },
|
||||
// {
|
||||
// path: `${subDirectory}blog/blog-details/:id`,
|
||||
|
|
|
|||
|
|
@ -65,13 +65,14 @@ export default defineConfig(({ command, mode, ssrBuild }) => {
|
|||
// },
|
||||
// }),
|
||||
],
|
||||
base: "/home/",
|
||||
base: "/", // Changed from "/home/" to "/" for clean SEO URLs
|
||||
envDir: "src",
|
||||
envPrefix: "ENV_",
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
plugins: [react()],
|
||||
base: "/", // Changed from default to "/" for consistency
|
||||
envDir: "src",
|
||||
envPrefix: "ENV_",
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue