diff --git a/ipi-survey-platform/public/assets/images/FCSCLogo.png b/ipi-survey-platform/public/assets/images/FCSCLogo.png new file mode 100644 index 0000000..0148d29 Binary files /dev/null and b/ipi-survey-platform/public/assets/images/FCSCLogo.png differ diff --git a/ipi-survey-platform/public/assets/images/lock.jpg b/ipi-survey-platform/public/assets/images/lock.jpg new file mode 100644 index 0000000..95aab17 Binary files /dev/null and b/ipi-survey-platform/public/assets/images/lock.jpg differ diff --git a/ipi-survey-platform/public/assets/images/product-image.jpg b/ipi-survey-platform/public/assets/images/product-image.jpg new file mode 100644 index 0000000..3478efa Binary files /dev/null and b/ipi-survey-platform/public/assets/images/product-image.jpg differ diff --git a/ipi-survey-platform/public/assets/images/timeline-image.jpg b/ipi-survey-platform/public/assets/images/timeline-image.jpg new file mode 100644 index 0000000..d341309 Binary files /dev/null and b/ipi-survey-platform/public/assets/images/timeline-image.jpg differ diff --git a/ipi-survey-platform/src/App.jsx b/ipi-survey-platform/src/App.jsx index 473405c..edaec63 100644 --- a/ipi-survey-platform/src/App.jsx +++ b/ipi-survey-platform/src/App.jsx @@ -14,7 +14,7 @@ import ChangePassword from '@/pages/ChangePassword/ChangePassword'; import ForgotPassword from '@/pages/ForgotPassword/ForgotPassword'; import PublicContactForm from '@/pages/PublicContactForm'; import EditCompanyProfile from '@/pages/Admin/configuration/EditCompanyProfile'; - +import Navbar from './pages/LandingPage/component/Navbar'; const RequireRole = ({ allowedRoles = [], children }) => { let role; let token; @@ -37,7 +37,8 @@ const RequireRole = ({ allowedRoles = [], children }) => { return children; } - return ; + // return ; + return }; const SessionWarningModal = ({ show, remainingTime, onExtend, onLogout }) => { @@ -295,6 +296,9 @@ function App() { } /> } /> } /> + {/* landingpage */} + + } /> ); diff --git a/ipi-survey-platform/src/pages/Admin/AdminDashboard.jsx b/ipi-survey-platform/src/pages/Admin/AdminDashboard.jsx index 874d19b..963b694 100644 --- a/ipi-survey-platform/src/pages/Admin/AdminDashboard.jsx +++ b/ipi-survey-platform/src/pages/Admin/AdminDashboard.jsx @@ -51,14 +51,9 @@ const AdminDashboard = () => { setLoading(true); const params = new URLSearchParams(); - // Only add quarter and year to params if they are not 'All' - if (quarter && quarter !== 'All') { - params.append('quarter', quarter); - } - - if (year && year !== 'All') { - params.append('year', year); - } + // Always send both quarter and year, but use 'All' if not specified + params.append('quarter', quarter || 'All'); + params.append('year', year || 'All'); const response = await apiClient.get(`/admin_dashboard?${params.toString()}`); diff --git a/ipi-survey-platform/src/pages/Admin/configuration/AdminUsers/ResetPasswordModal.jsx b/ipi-survey-platform/src/pages/Admin/configuration/AdminUsers/ResetPasswordModal.jsx index d9207ac..f9318bb 100644 --- a/ipi-survey-platform/src/pages/Admin/configuration/AdminUsers/ResetPasswordModal.jsx +++ b/ipi-survey-platform/src/pages/Admin/configuration/AdminUsers/ResetPasswordModal.jsx @@ -118,7 +118,7 @@ const ResetPasswordModal = ({ onClick={() => setShowOldPassword(!showOldPassword)} disabled={loading} > - {showOldPassword ? : } + {showOldPassword ? : } @@ -152,7 +152,7 @@ const ResetPasswordModal = ({ onClick={() => setShowNewPassword(!showNewPassword)} disabled={loading} > - {showNewPassword ? : } + {showNewPassword ? : } @@ -186,7 +186,7 @@ const ResetPasswordModal = ({ onClick={() => setShowConfirmPassword(!showConfirmPassword)} disabled={loading} > - {showConfirmPassword ? : } + {showConfirmPassword ? : } diff --git a/ipi-survey-platform/src/pages/Admin/configuration/IsicHsCodes.jsx b/ipi-survey-platform/src/pages/Admin/configuration/IsicHsCodes.jsx index 6a8c402..71f3a81 100644 --- a/ipi-survey-platform/src/pages/Admin/configuration/IsicHsCodes.jsx +++ b/ipi-survey-platform/src/pages/Admin/configuration/IsicHsCodes.jsx @@ -132,20 +132,23 @@ const ImportModal = ({ isOpen, onClose, onImport }) => { let errorMsg = response.message || 'Import failed'; // Add duplicate HS codes to the error message if they exist - if (response.duplicate_hs_codes_in_system?.length > 0) { - errorMsg += `\nDuplicate HS codes found: ${response.duplicate_hs_codes_in_system.join(', ')}`; - } + // if (response.duplicate_hs_codes_in_system?.length > 0) { + // errorMsg += `\nDuplicate HS codes found: ${response.duplicate_hs_codes_in_system.join(', ')}`; + // } - // Show error summary if available - if (response.summary) { - errorMsg += `\nTotal records: ${response.summary.total_records}`; - errorMsg += `\nImported: ${response.summary.imported}`; - errorMsg += `\nSkipped: ${response.summary.skipped}`; + // // Show error summary if available + // if (response.summary) { + // errorMsg += `\nTotal records: ${response.summary.total_records}`; + // errorMsg += `\nImported: ${response.summary.imported}`; + // errorMsg += `\nSkipped: ${response.summary.skipped}`; if (response.summary.errors?.length > 0) { - errorMsg += `\n\nErrors:\n${response.summary.errors.join('\n')}`; + errorMsg += '\n\nErrors:'; + response.summary.errors.forEach(err => { + errorMsg += `\nRow ${err.row}: ${err.error}`; + }); } - } + setError(errorMsg); return; @@ -159,7 +162,24 @@ const ImportModal = ({ isOpen, onClose, onImport }) => { onClose(); } catch (err) { console.error('Error uploading CSV:', err); - const errorMessage = err.response?.data?.message || 'Failed to import file. Please try again.'; + let errorMessage = 'Failed to import file. Please try again.'; + + // Handle different error response formats + if (err.response?.data) { + if (typeof err.response.data === 'string') { + errorMessage = err.response.data; + } else if (err.response.data.message) { + errorMessage = err.response.data.message; + } else if (err.response.data.error) { + errorMessage = err.response.data.error; + } else { + // Stringify the entire response if it's an object + errorMessage = JSON.stringify(err.response.data, null, 2); + } + } else if (err.message) { + errorMessage = err.message; + } + setError(errorMessage); } finally { setLoading(false); @@ -175,12 +195,9 @@ const ImportModal = ({ isOpen, onClose, onImport }) => { const downloadSampleCSV = () => { const sampleData = [ - ['HS Code', 'Product Name', 'Unit', 'Description', 'Status'], - ['0101', 'Live Horses', 'kg', 'Live pure-bred breeding horses', 'Active'], - ['0102', 'Live Bovine Animals', 'kg', 'Live bovine animals', 'Active'], - ['0103', 'Live Swine', 'kg', 'Live swine', 'Active'], - ['0104', 'Live Sheep And Goats', 'kg', 'Live sheep and goats', 'Active'], - ['0105', 'Live Poultry', 'kg', 'Live poultry', 'Active'] + ['HS Code', 'Product Name', 'Unit'], + ['0101', 'Live Horses', 'kg'], + ['0102', 'Live Bovine Animals', 'kg'], ]; const csvContent = sampleData.map(row => diff --git a/ipi-survey-platform/src/pages/LandingPage/component/Banner.jsx b/ipi-survey-platform/src/pages/LandingPage/component/Banner.jsx new file mode 100644 index 0000000..a7f959e --- /dev/null +++ b/ipi-survey-platform/src/pages/LandingPage/component/Banner.jsx @@ -0,0 +1,39 @@ +import React from "react"; + +const Banner = () => { + return ( +
+ {/* Tagline */} +
+ Official survey by{" "} + + Federal Competitiveness and Statistics Centre (FCSC) + +
+ + {/* Title */} +

+ Industrial Production Index (IPI) Survey – UAE +

+ + {/* Description */} +

+ A secure quarterly survey for manufacturing establishments — with{" "} + monthly breakdowns inside each quarter. + Your data powers official national indicators. +

+ + {/* Buttons */} +
+ + +
+
+ ); +}; + +export default Banner; diff --git a/ipi-survey-platform/src/pages/LandingPage/component/Cards.jsx b/ipi-survey-platform/src/pages/LandingPage/component/Cards.jsx new file mode 100644 index 0000000..8d0722a --- /dev/null +++ b/ipi-survey-platform/src/pages/LandingPage/component/Cards.jsx @@ -0,0 +1,75 @@ +import React from "react"; + +const steps = [ + { + number: 1, + title: "Notification", + description: "You receive an email/SMS when a new quarter opens.", + }, + { + number: 2, + title: "Sign in", + description: + "Use your FCSC-provided account. If needed, use Forgot password.", + }, + { + number: 3, + title: "Enter data", + description: + "Provide monthly quantities and values for each product in the open quarter (e.g., Jan, Feb, Mar for Q1).", + }, + { + number: 4, + title: "Validate", + description: + "Inline checks highlight missing or unusual values across months.", + }, + { + number: 5, + title: "Submit", + description: + "Certify accuracy for the quarter and submit.", + }, + { + number: 6, + title: "Review", + description: + "FCSC may contact you for clarifications or revisions.", + }, +]; + +const Cards = () => { + return ( +
+
+

How the survey works

+

A simple quarterly cycle

+
+ +
+ {steps.map((step) => ( +
+
+
+ {step.number} +
+

+ {step.title} +

+
+

{step.description}

+
+ ))} +
+ +

+ Accounts are issued by FCSC. There is no self-registration. +

+
+ ); +}; + +export default Cards; diff --git a/ipi-survey-platform/src/pages/LandingPage/component/Collect.jsx b/ipi-survey-platform/src/pages/LandingPage/component/Collect.jsx new file mode 100644 index 0000000..c8a4428 --- /dev/null +++ b/ipi-survey-platform/src/pages/LandingPage/component/Collect.jsx @@ -0,0 +1,47 @@ +import React from "react"; + +const Collect = () => { + return ( +
+ {/* Left Section */} +
+

+ Why we collect this data +

+
    +
  • + To produce timely and reliable statistics on manufacturing trends. +
  • +
  • + To support evidence-based decisions by public and private stakeholders. +
  • +
  • + To contribute to national accounts and short-term economic indicators. +
  • +
+
+ + {/* Right Section */} +
+
+ {[ + { q: "Q1", period: "Jan–Mar" }, + { q: "Q2", period: "Apr–Jun" }, + { q: "Q3", period: "Jul–Sep" }, + { q: "Q4", period: "Oct–Dec" }, + ].map((item) => ( +
+

{item.q}

+

{item.period}

+
+ ))} +
+
+
+ ); +}; + +export default Collect; diff --git a/ipi-survey-platform/src/pages/LandingPage/component/Cta.jsx b/ipi-survey-platform/src/pages/LandingPage/component/Cta.jsx new file mode 100644 index 0000000..b18ac66 --- /dev/null +++ b/ipi-survey-platform/src/pages/LandingPage/component/Cta.jsx @@ -0,0 +1,35 @@ +import React from "react"; + +const Cta = () => { + return ( +
+
+ {/* Left content */} +
+

+ We’re here to help +

+

+ Our support team can assist with access, questions, or clarifications. +

+

+ Support hours: Sun–Thu, 8:00–16:00 GST +

+
+ + {/* Buttons */} +
+ + +
+
+
+ ); +}; + +export default Cta; diff --git a/ipi-survey-platform/src/pages/LandingPage/component/Faq.jsx b/ipi-survey-platform/src/pages/LandingPage/component/Faq.jsx new file mode 100644 index 0000000..aad558b --- /dev/null +++ b/ipi-survey-platform/src/pages/LandingPage/component/Faq.jsx @@ -0,0 +1,97 @@ +import React, { useState } from "react"; +import { ChevronDown, ChevronUp } from "lucide-react"; // ✅ Up/Down icons + +const Faq = () => { + const [openIndex, setOpenIndex] = useState(null); + + const faqs = [ + { + question: "Do I need an account to respond?", + answer: + "Yes. FCSC provisions accounts to selected establishments. Use Login to access the survey.", + }, + { + question: "Can I register myself?", + answer: + "No. There is no self-registration. If you were contacted but can’t access your account, use Forgot password or Contact support.", + }, + { + question: "Is my data public?", + answer: "No. Results are published only in aggregate form.", + }, + { + question: "What if production was zero in a month?", + answer: "Enter 0 for the month and provide a reason when prompted.", + }, + { + question: "Can I update after submission?", + answer: + "Yes, if a revision window is open or if FCSC requests a correction.", + }, + { + question: "Which browser is supported?", + answer: "Latest Chrome, Edge, Safari.", + }, + { + question: "How long does it take?", + answer: + "Most respondents complete within minutes each quarter, depending on product lines.", + }, + { + question: "Who can I contact?", + answer: "See Need help below.", + }, + ]; + + const toggleFaq = (index) => { + setOpenIndex(openIndex === index ? null : index); + }; + + return ( +
+

+ Frequently asked questions +

+ +
+ {faqs.map((faq, index) => { + const isOpen = openIndex === index; + return ( +
+ + + {isOpen && ( +

+ {faq.answer} +

+ )} +
+ ); + })} +
+
+ ); +}; + +export default Faq; diff --git a/ipi-survey-platform/src/pages/LandingPage/component/Footer.jsx b/ipi-survey-platform/src/pages/LandingPage/component/Footer.jsx new file mode 100644 index 0000000..f73754d --- /dev/null +++ b/ipi-survey-platform/src/pages/LandingPage/component/Footer.jsx @@ -0,0 +1,99 @@ +import React from "react"; +import logo from "/assets/images/FCSCLogo.png"; + +import { + Phone, + PhoneCall, + Facebook, + Instagram, + Linkedin, + Youtube, + Mail, +} from "lucide-react"; + +const Footer = () => { + return ( +
+
+ {/* Column 1 */} +
+

+ The Ministry +

+
    +

    The Federal Competitiveness and Statistics Centre (FCSC) provides reliable data and insights to enhance the UAE’s competitiveness and support sustainable national development.

    +
+
+ + {/* Column 2 */} +
+

+ Using the website +

+ +
+ + {/* Column 3 */} +
+

+ Information and support +

+ +
+ + {/* Column 4 – Logo & Contact */} +
+ Tawasol Logo +
+
+ + +971 4 608 0000 +
+
+ + +971 4 327 3535 +
+

+

+ + +info@fcsc.gov.ae +
+

+
+
+
+ +
+
+

+ Copyright © 2025 Federal Competitiveness and Statistics Centre, All Rights Reserved{" "} + {/* All rights reserved. Last updated on 24/04/2023 at 15:45 */} +

+ + {/* Social Icons */} +
+ {/* + + + */} +
+
+
+
+ ); +}; + +export default Footer; diff --git a/ipi-survey-platform/src/pages/LandingPage/component/Industrial.jsx b/ipi-survey-platform/src/pages/LandingPage/component/Industrial.jsx new file mode 100644 index 0000000..1c2d3e9 --- /dev/null +++ b/ipi-survey-platform/src/pages/LandingPage/component/Industrial.jsx @@ -0,0 +1,49 @@ +import React from "react"; + +const Industrial = () => { + return ( +
+ {/* Left Side: Content */} +
+

+ What is the Industrial Production Index (IPI)? +

+

+ The Industrial Production Index (IPI) measures changes in the volume + of industrial output over time. It tracks production across + manufacturing activities classified by ISIC and is a key official + indicator used to monitor economic activity and inform policy. +

+
+ + {/* Right Side: Quick Facts Box */} +
+

+ Quick facts +

+
    +
  • + Frequency: Quarterly (enter monthly figures for the + quarter) +
  • +
  • + Reference area: United Arab Emirates +
  • +
  • + Respondents: Registered manufacturing establishments +
  • +
  • + Classification: ISIC Rev.4 +
  • +
+ +
+ Tip: Keep monthly records ready (e.g., invoices, ERP + extracts). +
+
+
+ ); +}; + +export default Industrial; diff --git a/ipi-survey-platform/src/pages/LandingPage/component/Navbar.jsx b/ipi-survey-platform/src/pages/LandingPage/component/Navbar.jsx new file mode 100644 index 0000000..a43f6cc --- /dev/null +++ b/ipi-survey-platform/src/pages/LandingPage/component/Navbar.jsx @@ -0,0 +1,146 @@ +import React, { useState, useEffect } from "react"; +import { Menu, X } from "lucide-react"; +import logo from "/assets/images/FCSCLogo.png"; +import Banner from "./Banner"; +import Industrial from "./Industrial"; +import Collect from "./Collect"; +import Survey from "./Survey"; +import Cards from "./Cards"; +import Protected from "./Protected"; +import Participation from "./Participation"; +import Timeline from "./Timeline"; +import Faq from "./Faq"; +import Footer from "./Footer"; +import Resources from "./Resources"; +import Cta from "./Cta"; +import { Link } from "react-router-dom"; + +const Navbar = () => { + const [menuOpen, setMenuOpen] = useState(false); + const [activeSection, setActiveSection] = useState("about-ipi"); + + const closeMenu = () => setMenuOpen(false); + + // Scroll detection for active section + useEffect(() => { + const sections = document.querySelectorAll("section[id]"); + const options = { + root: null, + threshold: 0.5, + }; + + const observer = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + setActiveSection(entry.target.id); + } + }); + }, options); + + sections.forEach((section) => observer.observe(section)); + return () => sections.forEach((section) => observer.unobserve(section)); + }, []); + + // Active & hover styling + const linkClass = (id) => + `relative pb-1 transition-all duration-300 ${ + activeSection === id + ? "text-[#b9933b] after:content-[''] after:absolute after:left-0 after:bottom-0 after:w-full after:h-[2px] after:bg-[#b9933b]" + : "text-gray-800 hover:text-[#b9933b]" + }`; + + // Scroll and highlight on click + const handleClick = (id) => { + setActiveSection(id); + closeMenu(); + const section = document.getElementById(id); + if (section) { + section.scrollIntoView({ behavior: "smooth", block: "start" }); + } + }; + + return ( + <> + {/* Navbar */} +
+
+ FCSC Logo + + {/* Desktop Menu */} + + + {/* Mobile Menu Toggle */} + +
+ + {/* Mobile Menu */} + {menuOpen && ( +
+ {["about-ipi", "how-it-works", "eligibility", "faqs", "resources"].map((id) => ( + + ))} + + Login + +
+ )} +
+ + {/* Sections */} +
+ +
+
+
+ + + + +
+
+ +
+
+ + ); +}; + +export default Navbar; diff --git a/ipi-survey-platform/src/pages/LandingPage/component/Participation.jsx b/ipi-survey-platform/src/pages/LandingPage/component/Participation.jsx new file mode 100644 index 0000000..7c16302 --- /dev/null +++ b/ipi-survey-platform/src/pages/LandingPage/component/Participation.jsx @@ -0,0 +1,40 @@ +import React from "react"; +import sampleForm from "/assets/images/product-image.jpg"; + +const Participation = () => { + return ( + +
+
+ {/* Left Side - Image / Form Box */} +
+
+ Participation form example +
+
+ + {/* Right Side - Text Content */} +
+

+ Why your participation matters +

+ +
    +
  • Accurate indicators help calibrate policies that affect industry.
  • +
  • Timely inputs reduce follow-up calls and queries.
  • +
  • Access to historical submissions and receipts for your records.
  • +
  • + Contributes to a complete national picture of manufacturing performance. +
  • +
+
+
+
+ ); +}; + +export default Participation; diff --git a/ipi-survey-platform/src/pages/LandingPage/component/Protected.jsx b/ipi-survey-platform/src/pages/LandingPage/component/Protected.jsx new file mode 100644 index 0000000..f18cba2 --- /dev/null +++ b/ipi-survey-platform/src/pages/LandingPage/component/Protected.jsx @@ -0,0 +1,88 @@ +import React from "react"; +import Lock from "/assets/images/lock.jpg" + + +const Protected = () => { + return ( +
+
+ + {/* Left Side - Text Content */} +
+

+ How your data is protected and used +

+ +
+
+

Confidentiality

+

+ Your establishment’s data is confidential and used only for official + statistics. Published results are aggregated; no individual + establishment’s data is disclosed. +

+
+ +
+

Legal basis

+

+ + Collected under the national statistics mandate to compile official + indicators. Participation is compulsory for selected establishments + under applicable statistical regulations. +

+
+ +
+

Data security

+

+ + Role-based access, encryption in transit and at rest, and monitored + environments. Regular audits and adherence to government security + guidelines. +

+
+ +
+

Retention

+

+ + Data is retained only as long as necessary for statistical purposes per + policy. +

+
+
+ +

+ See{" "} + + Privacy Policy + + ,{" "} + + Terms of Use + {" "} + and{" "} + + Data Protection + + . +

+
+ + {/* Right Side - Image / Icon Box */} +
+
+ Data Protection Illustration +
+
+
+
+ ); +}; + +export default Protected; diff --git a/ipi-survey-platform/src/pages/LandingPage/component/Resources.jsx b/ipi-survey-platform/src/pages/LandingPage/component/Resources.jsx new file mode 100644 index 0000000..d854db1 --- /dev/null +++ b/ipi-survey-platform/src/pages/LandingPage/component/Resources.jsx @@ -0,0 +1,37 @@ +import React from "react"; + +const Resources = () => { + const resources = [ + { title: "FCSC – Official website", link: "#" }, + { title: "Sample questionnaire (PDF)", link: "#" }, + { title: "Item classification guide (ISIC) (PDF)", link: "#" }, + { title: "Data definitions & unit guidelines (PDF)", link: "#" }, + { title: "Browser and system requirements", link: "#" }, + ]; + + return ( +
+
+

+ Resources & downloads +

+ +
+
+ ); +}; + +export default Resources; diff --git a/ipi-survey-platform/src/pages/LandingPage/component/Survey.jsx b/ipi-survey-platform/src/pages/LandingPage/component/Survey.jsx new file mode 100644 index 0000000..159f717 --- /dev/null +++ b/ipi-survey-platform/src/pages/LandingPage/component/Survey.jsx @@ -0,0 +1,35 @@ +import React from "react"; + +const Survey = () => { + return ( +
+ {/* Heading */} +

+ Who should complete the IPI survey? +

+ + {/* Content */} +
+

+ Manufacturing establishments operating in the UAE that are selected/notified by FCSC. +

+

+ The survey is address-based: if your establishment is contacted, you are required + to respond for the reference quarter. +

+

+ If your activities paused or changed, you must still complete the survey and indicate + reasons where relevant. +

+

+ If you believe you were contacted in error, please see{" "} + + Contact + . +

+
+
+ ); +}; + +export default Survey; diff --git a/ipi-survey-platform/src/pages/LandingPage/component/Timeline.jsx b/ipi-survey-platform/src/pages/LandingPage/component/Timeline.jsx new file mode 100644 index 0000000..d0c87e5 --- /dev/null +++ b/ipi-survey-platform/src/pages/LandingPage/component/Timeline.jsx @@ -0,0 +1,54 @@ +import React from "react"; +import timelineImage from "/assets/images/timeline-image.jpg"; + +const Timeline = () => { + return ( +
+
+ + {/* Left Side - Text Content */} +
+

+ Key dates & timeline +

+ +
+

+ Survey frequency: Quarterly — each survey collects{" "} + monthly figures for the months in that quarter. +

+

+ Quarter mapping: Q1 (Jan–Mar), Q2 (Apr–Jun), Q3 (Jul–Sep), + Q4 (Oct–Dec). +

+

+ Windows: Open and deadline dates are communicated in + notifications; a short grace period may apply. +

+

+ Revisions: If requested, please update promptly; indices are + re-computed when revisions arrive. +

+

+ Tip: Keep your monthly records ready; you can save drafts + before final submission. +

+
+
+ + {/* Right Side - Image / Timeline Box */} +
+
+ Participation form example +
+
+
+
+ ); +}; + +export default Timeline;