changed images to public folder

This commit is contained in:
Malini 2025-10-30 10:23:11 +05:30
parent 40c0656d3d
commit 3c0665a909
89 changed files with 1528 additions and 532 deletions

View File

Before

Width:  |  Height:  |  Size: 964 B

After

Width:  |  Height:  |  Size: 964 B

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 957 B

After

Width:  |  Height:  |  Size: 957 B

View File

Before

Width:  |  Height:  |  Size: 967 B

After

Width:  |  Height:  |  Size: 967 B

View File

Before

Width:  |  Height:  |  Size: 775 B

After

Width:  |  Height:  |  Size: 775 B

View File

Before

Width:  |  Height:  |  Size: 970 B

After

Width:  |  Height:  |  Size: 970 B

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 790 B

After

Width:  |  Height:  |  Size: 790 B

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 370 B

After

Width:  |  Height:  |  Size: 370 B

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 1013 B

After

Width:  |  Height:  |  Size: 1013 B

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

Before

Width:  |  Height:  |  Size: 189 B

After

Width:  |  Height:  |  Size: 189 B

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 392 B

After

Width:  |  Height:  |  Size: 392 B

View File

Before

Width:  |  Height:  |  Size: 967 B

After

Width:  |  Height:  |  Size: 967 B

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 272 B

After

Width:  |  Height:  |  Size: 272 B

View File

Before

Width:  |  Height:  |  Size: 731 B

After

Width:  |  Height:  |  Size: 731 B

View File

Before

Width:  |  Height:  |  Size: 936 B

After

Width:  |  Height:  |  Size: 936 B

View File

Before

Width:  |  Height:  |  Size: 766 B

After

Width:  |  Height:  |  Size: 766 B

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 242 B

After

Width:  |  Height:  |  Size: 242 B

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.33317 2C5.6665 2 6.99984 5 6.99984 5.33333C6.99984 6 5.99984 6.66667 5.6665 7.33333C5.33317 8 5.99984 8.66667 6.6665 9.33333C6.9265 9.59333 7.99984 10.6667 8.6665 10.3333C9.33317 10 9.99984 9 10.6665 9C10.9998 9 13.9998 10.3333 13.9998 10.6667C13.9998 12 12.9998 13 11.9998 13.3333C10.9998 13.6667 10.3332 13.6667 8.99984 13.3333C7.6665 13 6.6665 12.6667 4.99984 11C3.33317 9.33333 2.99984 8.33333 2.6665 7C2.33317 5.66667 2.33317 5 2.6665 4C2.99984 3 3.99984 2 5.33317 2Z" stroke="#232528" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 674 B

View File

Before

Width:  |  Height:  |  Size: 852 B

After

Width:  |  Height:  |  Size: 852 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.66683 13.3337C2.30016 13.3337 1.98639 13.2032 1.7255 12.9423C1.46461 12.6814 1.33394 12.3674 1.3335 12.0003V4.00033C1.3335 3.63366 1.46416 3.31988 1.7255 3.05899C1.98683 2.7981 2.30061 2.66744 2.66683 2.66699H13.3335C13.7002 2.66699 14.0142 2.79766 14.2755 3.05899C14.5368 3.32033 14.6673 3.6341 14.6668 4.00033V12.0003C14.6668 12.367 14.5364 12.681 14.2755 12.9423C14.0146 13.2037 13.7006 13.3341 13.3335 13.3337H2.66683ZM8.00016 8.66699L2.66683 5.33366V12.0003H13.3335V5.33366L8.00016 8.66699ZM8.00016 7.33366L13.3335 4.00033H2.66683L8.00016 7.33366ZM2.66683 5.33366V4.00033V12.0003V5.33366Z" fill="#232528"/>
</svg>

After

Width:  |  Height:  |  Size: 727 B

View File

Before

Width:  |  Height:  |  Size: 769 B

After

Width:  |  Height:  |  Size: 769 B

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1013 B

After

Width:  |  Height:  |  Size: 1013 B

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,15 +1,16 @@
import React from 'react';
import { NavLink, useNavigate } from 'react-router-dom';
import Logo from '@/assets/images/fcsclogo.svg';
import DashboardIconActive from '@/assets/images/cuida_dashboard-outline.svg';
import DashboardIconInactive from '@/assets/images/cuida_dashboard-outline-inactive.svg';
import CheckCircleActive from '@/assets/images/checkcircle-active.svg';
import ConfigActive from '@/assets/images/configrationicon-active.svg';
import ConfigInactive from '@/assets/images/configrationicon-inactive.svg';
import UserActive from '@/assets/images/user-active.svg';
import UserInactive from '@/assets/images/user-inactive.svg';
import ManageSubmissionInactive from '@/assets/images/managesubmission - inactive.svg';
import BellIconAsset from '@/assets/images/bell.svg';
const logoSrc = '/assets/images/FCSCLogo.svg';
const dashboardIconActiveSrc = '/assets/images/cuida_dashboard-outline.svg';
const dashboardIconInactiveSrc = '/assets/images/cuida_dashboard-outline-inactive.svg';
const checkCircleActiveSrc = '/assets/images/CheckCircle-active.svg';
const configActiveSrc = '/assets/images/configrationicon-active.svg';
const configInactiveSrc = '/assets/images/configrationicon-inactive.svg';
const userActiveSrc = '/assets/images/User-active.svg';
const userInactiveSrc = '/assets/images/User-inactive.svg';
const manageSubmissionInactiveSrc = '/assets/images/managesubmission - inactive.svg';
const bellIconSrc = '/assets/images/Bell.svg';
const NavItem = ({ label, to, iconActive, iconInactive, end = false }) => (
<NavLink
@ -74,12 +75,12 @@ const AdminHeader = () => {
<header className="bg-white border-b border-[#E5E7EB] shadow-[0_6px_18px_rgba(15,23,42,0.04)]">
<div className="max-w-[1280px] mx-auto px-4">
<div className="flex items-center h-20 gap-6 ">
<img src={Logo} alt="FCSC" className="w-[140px] h-[44px] " />
<img src={logoSrc} alt="FCSC" className="w-[140px] h-[44px] " />
<nav className="flex-1 flex justify-end items-center gap-6 xl:gap-8 text-[14px] leading-5 ml-auto ">
<NavItem to="/admin/dashboard" end label="Dashboard" iconActive={DashboardIconActive} iconInactive={DashboardIconInactive} />
<NavItem to="/admin/validations" label="Manage Submissions" iconActive={CheckCircleActive} iconInactive={ManageSubmissionInactive} />
<NavItem to="/admin/configuration" label="Configuration" iconActive={ConfigActive} iconInactive={ConfigInactive} />
<NavItem to="/admin/users" label="Users" iconActive={UserActive} iconInactive={UserInactive} />
<NavItem to="/admin/dashboard" end label="Dashboard" iconActive={dashboardIconActiveSrc} iconInactive={dashboardIconInactiveSrc} />
<NavItem to="/admin/validations" label="Manage Submissions" iconActive={checkCircleActiveSrc} iconInactive={manageSubmissionInactiveSrc} />
<NavItem to="/admin/configuration" label="Configuration" iconActive={configActiveSrc} iconInactive={configInactiveSrc} />
<NavItem to="/admin/users" label="Users" iconActive={userActiveSrc} iconInactive={userInactiveSrc} />
</nav>
<div className="hidden lg:flex items-center gap-3 ml-auto">
<button
@ -87,7 +88,7 @@ const AdminHeader = () => {
aria-label="Notifications"
className="inline-flex h-9 w-9 items-center justify-center rounded-full border border-transparent hover:border-[#E5E7EB]"
>
<img src={BellIconAsset} alt="Notifications" className="h-[18px] w-[18px]" />
<img src={bellIconSrc} alt="Notifications" className="h-[18px] w-[18px]" />
</button>
<div className="relative">
<button
@ -142,10 +143,10 @@ const AdminHeader = () => {
{open && (
<div className="lg:hidden pb-6 border-t border-[#E5E7EB]">
<nav className="flex flex-col gap-3 pt-4 text-[14px] leading-5">
<NavItem to="/admin/dashboard" end label="Dashboard" iconActive={DashboardIconActive} iconInactive={DashboardIconInactive} />
<NavItem to="/admin/validations" label="Manage Submissions" iconActive={CheckCircleActive} iconInactive={ManageSubmissionInactive} />
<NavItem to="/admin/configuration" label="Configuration" iconActive={ConfigActive} iconInactive={ConfigInactive} />
<NavItem to="/admin/users" label="Users" iconActive={UserActive} iconInactive={UserInactive} />
<NavItem to="/admin/dashboard" end label="Dashboard" iconActive={dashboardIconActiveSrc} iconInactive={dashboardIconInactiveSrc} />
<NavItem to="/admin/validations" label="Manage Submissions" iconActive={checkCircleActiveSrc} iconInactive={manageSubmissionInactiveSrc} />
<NavItem to="/admin/configuration" label="Configuration" iconActive={configActiveSrc} iconInactive={configInactiveSrc} />
<NavItem to="/admin/users" label="Users" iconActive={userActiveSrc} iconInactive={userInactiveSrc} />
</nav>
</div>
)}

View File

@ -1,10 +1,10 @@
import React, { useState, useMemo } from 'react';
import Table from '@/components/common/Table';
// Import SVG files as URLs in Vite
import SearchIcon from '@/assets/images/material-symbols_search-rounded.svg';
import CheckCircle from '@/assets/images/check-circle-fill 1.svg';
import XCircle from '@/assets/images/warning-circle-fill 1.svg';
import EyeIcon from '@/assets/images/User-active.svg';
const searchIconSrc = '/assets/images/material-symbols_search-rounded.svg';
const checkCircleSrc = '/assets/images/check-circle-fill 1.svg';
const xCircleSrc = '/assets/images/warning-circle-fill 1.svg';
const eyeIconSrc = '/assets/images/User-active.svg';
const submissions = [
{
@ -176,9 +176,9 @@ const SubmissionTable = () => {
item.reviewer,
item.reviewedOn,
<div className="flex items-center justify-center gap-3">
<img src={CheckCircle} alt="Approve" className="text-green-600 w-5 h-5 cursor-pointer hover:scale-110 transition-transform" />
<img src={XCircle} alt="Reject" className="text-red-500 w-5 h-5 cursor-pointer hover:scale-110 transition-transform" />
<img src={EyeIcon} alt="View" className="text-gray-500 w-5 h-5 cursor-pointer hover:scale-110 transition-transform" />
<img src={checkCircleSrc} alt="Approve" className="text-green-600 w-5 h-5 cursor-pointer hover:scale-110 transition-transform" />
<img src={xCircleSrc} alt="Reject" className="text-red-500 w-5 h-5 cursor-pointer hover:scale-110 transition-transform" />
<img src={eyeIconSrc} alt="View" className="text-gray-500 w-5 h-5 cursor-pointer hover:scale-110 transition-transform" />
</div>,
]);
@ -205,7 +205,7 @@ const SubmissionTable = () => {
</h2>
<div className="relative w-[280px]">
<img
src={SearchIcon}
src={searchIconSrc}
alt="Search"
className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4"
/>

View File

@ -1,6 +1,7 @@
import React from 'react';
import CaretDownActive from '@/assets/images/caretdown-active.svg';
import CalendarIcon from '@/assets/images/uil_calender.svg';
const caretDownActiveSrc = '/assets/images/caretdown-active.svg';
const calendarIconSrc = '/assets/images/uil_calender.svg';
const baseInputStyles = {
default: {
@ -165,7 +166,7 @@ export const SelectField = ({
style = {},
name,
id,
rightIcon = CaretDownActive,
rightIcon = caretDownActiveSrc,
placeholder,
onFocus,
onBlur,
@ -384,7 +385,7 @@ export const PhoneField = ({
</option>
))}
</select>
<img src={CaretDownActive} alt="" style={arrowStyle} />
<img src={caretDownActiveSrc} alt="" style={arrowStyle} />
</div>
<input
type="text"
@ -410,7 +411,7 @@ export const DateField = ({
style = {},
name,
id,
rightIcon = CalendarIcon,
rightIcon = calendarIconSrc,
onBlur,
onFocus,
...rest

View File

@ -1,8 +1,9 @@
import React from 'react';
import CaretLeftIcon from '@/assets/images/caretleft.svg';
import CaretRightIcon from '@/assets/images/caretright.svg';
import CaretDoubleLeftIcon from '@/assets/images/caretdoubleleft.svg';
import CaretDoubleRightIcon from '@/assets/images/caretdoubleright.svg';
const caretLeftSrc = '/assets/images/CaretLeft.svg';
const caretRightSrc = '/assets/images/CaretRight.svg';
const caretDoubleLeftSrc = '/assets/images/CaretDoubleLeft.svg';
const caretDoubleRightSrc = '/assets/images/CaretDoubleRight.svg';
// Generic, reusable table
// Props:
@ -210,7 +211,7 @@ const Table = ({
disabled={!hasPrevious}
aria-label="Previous page"
>
<img src={CaretLeftIcon} alt="Previous" className="h-4 w-4" />
<img src={caretLeftSrc} alt="Previous" className="h-4 w-4" />
</button>
<div className="flex items-center gap-2 text-[#232528]">
<span className="font-medium">{rangeStart}</span>
@ -226,7 +227,7 @@ const Table = ({
disabled={!hasNext}
aria-label="Next page"
>
<img src={CaretRightIcon} alt="Next" className="h-4 w-4" />
<img src={caretRightSrc} alt="Next" className="h-4 w-4" />
</button>
</div>
@ -254,7 +255,7 @@ const Table = ({
onClick={() => goToPage(1)}
disabled={!hasPrevious}
>
<img src={CaretDoubleLeftIcon} alt="First" className="h-4 w-4" />
<img src={caretDoubleLeftSrc} alt="First" className="h-4 w-4" />
<span>First</span>
</button>
<button
@ -263,7 +264,7 @@ const Table = ({
onClick={() => goToPage(safeCurrentPage - 1)}
disabled={!hasPrevious}
>
<img src={CaretLeftIcon} alt="Previous" className="h-4 w-4" />
<img src={caretLeftSrc} alt="Previous" className="h-4 w-4" />
<span>Previous</span>
</button>
@ -299,7 +300,7 @@ const Table = ({
disabled={!hasNext}
>
<span>Next</span>
<img src={CaretRightIcon} alt="Next" className="h-4 w-4" />
<img src={caretRightSrc} alt="Next" className="h-4 w-4" />
</button>
<button
type="button"
@ -308,7 +309,7 @@ const Table = ({
disabled={!hasNext}
>
<span>Last</span>
<img src={CaretDoubleRightIcon} alt="Last" className="h-4 w-4" />
<img src={caretDoubleRightSrc} alt="Last" className="h-4 w-4" />
</button>
</div>
</div>

View File

@ -1,8 +1,9 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';
import Table from '@/components/common/Table';
import SearchIcon from '@/assets/images/material-symbols_search-rounded.svg';
import CaretDown from '@/assets/images/caretdown.svg';
const searchIconSrc = '/assets/images/material-symbols_search-rounded.svg';
const caretDownSrc = '/assets/images/CaretDown.svg';
const getStatusClass = (status) => {
const normalized = String(status || '').toLowerCase();
@ -115,7 +116,7 @@ export const SubmissionHistory = ({ history = [], loading = false, error = '' })
className="w-full h-10 rounded-md border border-[#E5E7EB] pl-10 pr-3 text-sm focus:outline-none"
/>
<img
src={SearchIcon}
src={searchIconSrc}
alt="Search"
className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5"
/>
@ -133,7 +134,7 @@ export const SubmissionHistory = ({ history = [], loading = false, error = '' })
))}
</select>
<img
src={CaretDown}
src={caretDownSrc}
alt="Open"
className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4"
/>

View File

@ -29,7 +29,12 @@ const formatRelativeDays = (value) => {
export const SurveyStatus = ({ data = null, loading = false, error = '' }) => {
const navigate = useNavigate();
const handleStartSurvey = () => {
navigate('/survey');
navigate('/survey', {
state: {
currentQuarter: data?.current_quarter,
currentYear: data?.current_quarter_year
}
});
};
const submissionStatus = data?.submission_status || '—';

View File

@ -1,12 +1,13 @@
import React from 'react';
import { NavLink, useNavigate } from 'react-router-dom';
import Logo from '@/assets/images/fcsclogo.svg';
import SurveyIconActive from '@/assets/images/vector.svg';
import SurveyIconInactive from '@/assets/images/vectorblack.svg';
import DashboardIconActive from '@/assets/images/cuida_dashboard-outline.svg';
import DashboardIconInactive from '@/assets/images/cuida_dashboard-outline-inactive.svg';
import HistoryIconActive from '@/assets/images/mdi_history.svg';
import HistoryIconInactive from '@/assets/images/history.svg';
const logoSrc = '/assets/images/FCSCLogo.svg';
const surveyIconActiveSrc = '/assets/images/Vector.svg';
const surveyIconInactiveSrc = '/assets/images/Vectorblack.svg';
const dashboardIconActiveSrc = '/assets/images/cuida_dashboard-outline.svg';
const dashboardIconInactiveSrc = '/assets/images/cuida_dashboard-outline-inactive.svg';
const historyIconActiveSrc = '/assets/images/mdi_history.svg';
const historyIconInactiveSrc = '/assets/images/history.svg';
const HeaderBar = () => {
const [open, setOpen] = React.useState(false);
@ -62,7 +63,7 @@ const HeaderBar = () => {
<header className="bg-white border-b border-b-[#E2E8F0]">
<div className="max-w-[1280px] mx-auto px-4">
<div className="flex items-center justify-between h-16">
<img src={Logo} alt="FCSC" className="w-[131px] h-[40px] opacity-100 rotate-0" />
<img src={logoSrc} alt="FCSC" className="w-[131px] h-[40px] opacity-100 rotate-0" />
<nav className="hidden md:flex items-center gap-8 text-[14px] leading-5">
<NavLink
to="/dashboard"
@ -71,7 +72,7 @@ const HeaderBar = () => {
>
{({ isActive }) => (
<>
<img src={isActive ? DashboardIconActive : DashboardIconInactive} alt="Dashboard" className="h-[18px] w-[18px]" />
<img src={isActive ? dashboardIconActiveSrc : dashboardIconInactiveSrc} alt="Dashboard" className="h-[18px] w-[18px]" />
<span>Dashboard</span>
</>
)}
@ -82,7 +83,7 @@ const HeaderBar = () => {
>
{({ isActive }) => (
<>
<img src={isActive ? SurveyIconActive : SurveyIconInactive} alt="Survey" className="h-[18px] w-[18px]" />
<img src={isActive ? surveyIconActiveSrc : surveyIconInactiveSrc} alt="Survey" className="h-[18px] w-[18px]" />
<span>Survey</span>
</>
)}
@ -93,7 +94,7 @@ const HeaderBar = () => {
>
{({ isActive }) => (
<>
<img src={isActive ? HistoryIconActive : HistoryIconInactive} alt="History" className="h-[18px] w-[18px]" />
<img src={isActive ? historyIconActiveSrc : historyIconInactiveSrc} alt="History" className="h-[18px] w-[18px]" />
<span>History</span>
</>
)}
@ -146,15 +147,15 @@ const HeaderBar = () => {
<div className="md:hidden pb-3">
<nav className="flex flex-col gap-2 text-[14px] leading-5">
<NavLink to="/dashboard" onClick={() => setOpen(false)} className={({ isActive }) => `inline-flex items-center gap-2 px-2 py-2 rounded border-b-2 ${isActive ? 'text-[#92722A] bg-[#F2ECCF] border-[#92722A]' : 'text-[#232528] hover:bg-gray-100 border-transparent'}`}>
<img src={DashboardIconInactive} alt="Dashboard" className="h-[18px] w-[18px]" />
<img src={dashboardIconInactiveSrc} alt="Dashboard" className="h-[18px] w-[18px]" />
<span>Dashboard</span>
</NavLink>
<NavLink to="/survey" onClick={() => setOpen(false)} className={({ isActive }) => `inline-flex items-center gap-2 px-2 py-2 rounded border-b-2 ${isActive ? 'text-[#92722A] bg-[#F2ECCF] border-[#92722A]' : 'text-[#232528] hover:bg-gray-100 border-transparent'}`}>
<img src={SurveyIconInactive} alt="Survey" className="h-[18px] w-[18px]" />
<img src={surveyIconInactiveSrc} alt="Survey" className="h-[18px] w-[18px]" />
<span>Survey</span>
</NavLink>
<NavLink to="/history" onClick={() => setOpen(false)} className={({ isActive }) => `inline-flex items-center gap-2 px-2 py-2 rounded border-b-2 ${isActive ? 'text-[#92722A] bg-[#F2ECCF] border-[#92722A]' : 'text-[#232528] hover:bg-gray-100 border-transparent'}`}>
<img src={HistoryIconInactive} alt="History" className="h-[18px] w-[18px]" />
<img src={historyIconInactiveSrc} alt="History" className="h-[18px] w-[18px]" />
<span>History</span>
</NavLink>
<button

View File

@ -1,22 +1,24 @@
import React from 'react';
import CaretDown from '@/assets/images/caretdown.svg';
import BackVendor from '@/assets/images/backvector.svg';
const caretDownSrc = '/assets/images/CaretDown.svg';
const backVectorSrc = '/assets/images/BackVector.svg';
const mailIconSrc = '/assets/images/material-symbols_mail-outline.svg';
const phoneIconSrc = '/assets/images/line-md_phone.svg';
const Field = ({ label, placeholder = '', type = 'text', value = '', onChange = () => {}, disabled = false }) => (
const Field = ({ label, placeholder = '', type = 'text', value = '', onChange = () => {}, disabled = true }) => (
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">{label}</label>
<input
type={type}
placeholder={placeholder}
value={value}
disabled={disabled}
disabled={true}
onChange={onChange}
className={`block w-full h-10 rounded-md border-2 border-[#92722A] focus:border-[#92722A] focus:ring-0 px-4 text-sm bg-white ${disabled ? 'opacity-75 cursor-not-allowed' : ''}`}
className="block w-full h-10 rounded-md border-2 border-[#E6D7A2] focus:border-[#92722A] focus:ring-0 px-4 text-sm bg-gray-50 cursor-not-allowed"
/>
</div>
);
const Select = ({ label, options = [], value = '', placeholder = 'Select option', onChange = () => {}, disabled = false }) => (
const Select = ({ label, options = [], value = '', placeholder = 'Select option', onChange = () => {}, disabled = true }) => (
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">{label}</label>
<div className="relative">
@ -40,7 +42,7 @@ const Select = ({ label, options = [], value = '', placeholder = 'Select option'
);
})}
</select>
<img src={CaretDown} alt="open" className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4" />
<img src={caretDownSrc} alt="open" className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4" />
</div>
</div>
);
@ -106,87 +108,172 @@ const EstablishmentInfo = ({
});
};
return (
<div className="space-y-2">
{/* Reporting Period */}
<Card>
<h3 className="text-sm font-semibold text-gray-900 mb-4">Reporting Period</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Select
label="Quarter"
placeholder="Select quarter"
options={["Q1", "Q2", "Q3", "Q4"]}
value={info.quarter}
onChange={handleFieldChange('quarter')}
disabled={loading}
/>
<Select
label="Year"
placeholder="Select year"
options={["2022", "2023", "2024", "2025"]}
value={info.year}
onChange={handleFieldChange('year')}
disabled={loading}
/>
return (
<div className="space-y-6 relative">
{loading && (
<div className="absolute inset-0 z-40 flex items-center justify-center bg-white/80">
<div className="h-12 w-12 animate-spin rounded-full border-[3px] border-[#92722A] border-t-transparent" />
</div>
</Card>
)}
<h2 className="text-xl font-semibold text-[#232528] mb-2">IPI Quarterly Survey Establishment Information (Step 1 of 3)</h2>
{/* Survey Information */}
<div className="bg-[#F2ECCF] p-5 rounded-md shadow-sm ring-1 ring-gray-200">
<h2 className="text-lg font-semibold text-[#6C4527] mb-2">Industrial Production Index (IPI) survey: {data.quarter} {data.year}</h2>
<p className="text-sm text-[#6C4527] mb-4">
You're completing the <b>IPI Quarterly Survey</b> for <b>{data.quarter} {data.year}</b>. This step shows establishment details already registered with us. <b>Step 1 is read-only.</b> To make corrections, update them in <b>Profile Establishment</b>, then return to this survey.
</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<div className="space-y-4">
<div className="flex items-baseline justify-between flex-wrap md:flex-nowrap gap-6">
<div className="flex items-baseline gap-1">
<span className="text-sm font-medium text-[#6C4527] whitespace-nowrap">Due:</span>
<span className="text-sm text-[#6C4527] whitespace-nowrap">Jan 31, 2025</span>
</div>
<div className="flex items-baseline gap-1">
<span className="text-sm font-medium text-[#6C4527] whitespace-nowrap">Estimated time:</span>
<span className="text-sm text-[#6C4527] whitespace-nowrap">15-20 minutes (step 1: 1-2 mins)</span>
</div>
<div className="flex items-baseline gap-1">
<span className="text-sm font-medium text-[#6C4527] whitespace-nowrap">Next:</span>
<span className="text-sm text-[#6C4527] whitespace-nowrap">Product Data, then Review & Submit</span>
</div>
</div>
<div className="space-y-2">
<ul className="text-sm text-[#6C4527] list-disc pl-5 space-y-1">
<li>After submission, responses are locked.A receipt appears in History after submission</li>
<li className="whitespace-nowrap">
After submission, responses are Data is used for statistical reporting and handled per our privacy policy locked. A receipt appears in History.
</li>
</ul>
</div>
<div className="flex items-center gap-6 mt-2 text-sm text-[#6C4527]">
{/* Email */}
<div className="flex items-center gap-2">
<img src={mailIconSrc} alt="email" className="w-4 h-4" />
<span>support@ipi.gov.example</span>
</div>
{/* Establishment Information */}
<Card>
{/* Phone */}
<div className="flex items-center gap-2">
<img src={phoneIconSrc} alt="phone" className="w-4 h-4" />
<span>+971-2-000-0000</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="flex justify-end gap-1 mt-1 text-sm">
<a href="#" className="text-[#92722A] hover:underline">You can return to Step 1 after updating details in Profile.</a>
</div>
<div className="space-y-1" aria-busy={loading ? "true" : "false"}>
{/* Reporting Period */}
<Card>
<h3 className="text-sm font-semibold text-gray-900 mb-4">Reporting Period</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Quarter</label>
<div className="relative">
<select
value={info.quarter}
onChange={handleFieldChange('quarter')}
disabled={true}
className="block w-full h-10 rounded-md border-2 border-[#E6D7A2] focus:border-[#92722A] focus:ring-0 px-4 pr-10 text-sm bg-gray-50 appearance-none cursor-not-allowed"
>
<option value="" disabled>Select quarter</option>
{["Q1", "Q2", "Q3", "Q4"].map(quarter => (
<option key={quarter} value={quarter}>{quarter}</option>
))}
</select>
<img
src={caretDownSrc}
alt="open"
className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Year</label>
<div className="relative">
<select
value={info.year}
onChange={handleFieldChange('year')}
disabled={true}
className="block w-full h-10 rounded-md border-2 border-[#E6D7A2] focus:border-[#92722A] focus:ring-0 px-4 pr-10 text-sm bg-gray-50 appearance-none cursor-not-allowed"
>
<option value="" disabled>Select year</option>
{["2022", "2023", "2024", "2025"].map(year => (
<option key={year} value={year}>{year}</option>
))}
</select>
<img
src={caretDownSrc}
alt="open"
className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4"
/>
</div>
</div>
</div>
</Card>
{/* Establishment Information Form */}
<Card>
<h3 className="text-sm font-semibold text-gray-900 mb-4">Establishment Information</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Field
label="Establishment Name"
placeholder="Al Masaood Industries LLC"
placeholder="Enter Establishment Name"
value={info.establishmentName}
onChange={handleFieldChange('establishmentName')}
disabled={loading}
/>
<Field
label="Permanent Factory Code"
placeholder="PFC-2024-001"
placeholder="Enter Permanent Factory Code"
value={info.permanentFactoryCode}
onChange={handleFieldChange('permanentFactoryCode')}
disabled={loading}
/>
<Field
label="Industry Code (Business Register)"
placeholder="IND-2834"
placeholder="Enter Industry Code"
value={info.industryCode}
onChange={handleFieldChange('industryCode')}
disabled={loading}
/>
<Field
label="License Number"
placeholder="CN-1234567"
placeholder="Enter License Number"
value={info.licenseNumber}
onChange={handleFieldChange('licenseNumber')}
disabled={loading}
/>
<Field
label="ISIC Code"
placeholder="2410"
placeholder="Enter ISIC Code"
value={info.isicCode}
onChange={handleFieldChange('isicCode')}
disabled={loading}
/>
<Field
label="Emirate"
placeholder="Abu Dhabi"
placeholder="Enter Emirate"
value={info.emirate}
onChange={handleFieldChange('emirate')}
disabled={loading}
/>
</div>
</Card>
</Card>
{/* Employee Information */}
<Card>
{/* Employee Information */}
<Card>
<h3 className="text-sm font-semibold text-gray-900 mb-4">Employee Information</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Field
label="Emirati Male"
placeholder="500"
placeholder="Enter Emirati Male"
type="number"
value={info.employeeInfo.emiratiMale}
onChange={handleEmployeeChange('emiratiMale')}
@ -194,7 +281,7 @@ const EstablishmentInfo = ({
/>
<Field
label="Non-Emirati Male"
placeholder="500"
placeholder="Enter Non-Emirati Male"
type="number"
value={info.employeeInfo.nonEmiratiMale}
onChange={handleEmployeeChange('nonEmiratiMale')}
@ -202,7 +289,7 @@ const EstablishmentInfo = ({
/>
<Field
label="Emirati Female"
placeholder="500"
placeholder="Enter Emirati Female"
type="number"
value={info.employeeInfo.emiratiFemale}
onChange={handleEmployeeChange('emiratiFemale')}
@ -210,7 +297,7 @@ const EstablishmentInfo = ({
/>
<Field
label="Non-Emirati Female"
placeholder="500"
placeholder="Enter Non-Emirati Female"
type="number"
value={info.employeeInfo.nonEmiratiFemale}
onChange={handleEmployeeChange('nonEmiratiFemale')}
@ -218,7 +305,7 @@ const EstablishmentInfo = ({
/>
<Field
label="Total Employees"
placeholder="2000"
placeholder="Enter Total Employees"
type="number"
value={info.employeeInfo.totalEmployees}
onChange={handleEmployeeChange('totalEmployees')}
@ -226,22 +313,22 @@ const EstablishmentInfo = ({
/>
<Field
label="Total Emirati"
placeholder="1000"
placeholder="Enter Total Emirati"
type="number"
value={info.employeeInfo.totalEmirati}
onChange={handleEmployeeChange('totalEmirati')}
disabled={loading}
/>
</div>
</Card>
</Card>
{/* Footer actions */}
<div className="flex flex-col sm:flex-row justify-between gap-3">
{/* Footer actions */}
<div className="flex flex-col sm:flex-row justify-between gap-3">
<button
onClick={onBack}
className="inline-flex items-center gap-2 h-9 px-4 rounded-md border border-[#92722A] text-[#92722A] bg-transparent hover:bg-[#92722A]/10"
>
<img src={BackVendor} alt="" className="h-4 w-4" />
<img src={backVectorSrc} alt="" className="h-4 w-4" />
<span>Back</span>
</button>
<button
@ -254,13 +341,15 @@ const EstablishmentInfo = ({
<path strokeLinecap="round" strokeLinejoin="round" d="M9 5l7 7-7 7" />
</svg>
</button>
</div>
{(loading || error) && (
<div className="mt-3">
{loading && <p className="text-sm text-[#5F646D]">Loading establishment information</p>}
{!loading && error && <p className="text-sm text-red-600">{error}</p>}
</div>
)}
{(loading || error) && (
<div className="mt-3">
{loading && <p className="text-sm text-[#5F646D]">Loading establishment information</p>}
{!loading && error && <p className="text-sm text-red-600">{error}</p>}
</div>
)}
</div>
</div>
);
};

View File

@ -5,25 +5,41 @@ import {
fetchProducts,
fetchUnits,
} from '@/services/masters/masterService.js';
import CaretDown from '@/assets/images/caretdown-black.svg';
const Input = ({ placeholder = '', type = 'text', value = '', onChange = () => {} }) => (
<input
type={type}
placeholder={placeholder}
value={value}
onChange={onChange}
className="block w-full h-10 rounded-md border-2 border-[#92722A] focus:border-[#92722A] focus:ring-0 px-4 text-sm bg-white"
/>
);
const caretDownSrc = '/assets/images/CaretDown-black.svg';
const Select = ({ placeholder = '', options = [], value = '', onChange }) => (
<div className="relative">
<select
className="block w-full h-10 rounded-md border-2 border-[#92722A] focus:border-[#92722A] focus:ring-0 px-4 pr-10 text-sm bg-white appearance-none"
value={value}
onChange={onChange}
>
const Input = ({ placeholder = '', type = 'text', value = '', onChange = () => {}, required = false }) => {
const [isFocused, setIsFocused] = React.useState(false);
const borderColor = value || isFocused ? 'border-[#92722A]' : 'border-[#CBA344]';
return (
<div className="relative">
<input
type={type}
placeholder={placeholder}
value={value}
onChange={onChange}
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
required={required}
className={`block w-full h-10 rounded-md border-2 ${borderColor} focus:ring-0 px-4 text-sm bg-white transition-colors`}
/>
</div>
);
};
const Select = ({ placeholder = '', options = [], value = '', onChange }) => {
const [isFocused, setIsFocused] = React.useState(false);
return (
<div className="relative">
<select
className={`block w-full h-10 rounded-md border-2 ${value ? 'border-[#92722A]' : 'border-[#CBA344]'} ${isFocused ? 'border-[#92722A]' : ''} focus:ring-0 px-4 pr-10 text-sm bg-white appearance-none`}
value={value}
onChange={onChange}
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
>
<option value="" disabled>{placeholder}</option>
{options.map((opt) => {
if (opt && typeof opt === 'object') {
@ -41,18 +57,26 @@ const Select = ({ placeholder = '', options = [], value = '', onChange }) => (
);
})}
</select>
<img src={CaretDown} alt="open" className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4" />
<img src={caretDownSrc} alt="open" className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4" />
</div>
);
);
};
const Textarea = ({ placeholder = '', value = '', onChange = () => {} }) => (
<textarea
placeholder={placeholder}
value={value}
onChange={onChange}
className="block w-full rounded-md border-2 border-[#92722A] focus:border-[#92722A] focus:ring-0 px-4 py-2 text-sm bg-white min-h-[96px]"
/>
);
const Textarea = ({ placeholder = '', value = '', onChange = () => {} }) => {
const [isFocused, setIsFocused] = React.useState(false);
const borderColor = value || isFocused ? 'border-[#92722A]' : 'border-[#CBA344]';
return (
<textarea
placeholder={placeholder}
value={value}
onChange={onChange}
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
className={`block w-full rounded-md border-2 ${borderColor} focus:ring-0 px-4 py-2 text-sm bg-white min-h-[96px] transition-colors`}
/>
);
};
const Card = ({ children }) => (
<div className="bg-white rounded-md ring-1 ring-gray-200">
@ -145,6 +169,7 @@ const ProductData = ({
setProductsError('');
try {
const productsList = await fetchProducts({ signal: productsController.signal });
console.log('Products fetched:', productsList);
setProductOptions(productsList);
setProductsError('');
} catch (error) {
@ -231,17 +256,91 @@ const ProductData = ({
const canAddMoreProducts = products.length < MAX_PRODUCTS;
return (
<div className="space-y-5 ">
<div className="space-y-5">
{/* Informational Section */}
<div className="bg-[#F2ECCF] rounded-md p-4 mb-6">
<h3 className="text-base font-semibold mb-2 text-[#6C4527]">
Why we collect monthly product data
</h3>
<p className="text-sm text-[#6C4527] mb-4">
This step collects <strong className="text-[#6C4527]">monthly output quantity and </strong><strong className="text-[#6C4527]">production cost</strong> for each product you manufacture or process. The data inform the
<strong className="text-[#6C4527]"> Industrial Production Index (IPI)</strong> and capacity-utilization statistics.
Results are published <strong className="text-[#6C4527]">only in aggregated form</strong> and your information is protected
by national statistics confidentiality provisions.
</p>
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4 text-sm text-[#6C4527] mt-4">
<div className="flex items-baseline justify-between flex-wrap md:flex-nowrap gap-6">
<div className="flex items-baseline gap-1">
<span className="text-sm font-normal text-[#6C4527] whitespace-nowrap">Due:</span>
<span className="text-sm font-normal text-[#6C4527] whitespace-nowrap">Jan 31, 2025</span>
</div>
<div className="flex items-baseline gap-1">
<span className="text-sm font-normal text-[#6C4527] whitespace-nowrap">Estimated time:</span>
<span className="text-sm font-normal text-[#6C4527] whitespace-nowrap">Depends on number of products</span>
</div>
<div className="flex items-baseline gap-1">
<span className="text-sm font-normal text-[#6C4527] whitespace-nowrap">What you'll do:</span>
<span className="text-sm font-normal text-[#6C4527] whitespace-nowrap">Add products select HS code & unit enter monthly Qty & Cost set next-quarter targets</span>
</div>
</div>
</div>
<div className="mt-4 space-y-2">
<div className="flex items-start gap-2">
<div className="w-1.5 h-1.5 rounded-full bg-[#6C4527] mt-2 flex-shrink-0"></div>
<span className="text-sm font-normal text-[#6C4527]">
<strong>Confidentiality:</strong> Used only for statistics; not shared for taxation or enforcement.
</span>
</div>
<div className="flex items-start gap-2">
<div className="w-1.5 h-1.5 rounded-full bg-[#6C4527] mt-2 flex-shrink-0"></div>
<span className="text-sm font-normal text-[#6C4527]">
<strong>Completeness:</strong> Report all products with notable output in the quarter.
</span>
</div>
</div>
</div>
{/* Info line section (Already exists) */}
{/* Data Definitions & Entry Rules Section */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* Left card - Data definitions */}
<div className="bg-[#F2ECCF] rounded-md p-4 text-[#6C4527]">
<h3 className="font-semibold mb-2">Data definitions</h3>
<p className="font-normal"><strong>Product (HS Code Name):</strong> Standard trade classification. Start typing to search by code or name.</p>
<p className="font-normal"><strong>Quantity (Qty):</strong> Physical output produced in the month, measured in the selected unit.</p>
<p className="font-normal"><strong>Cost (AED):</strong> Total <em>production cost</em> for that month, excluding VAT (e.g., materials, energy, direct labour, and manufacturing expenses). Do not include sales margins.</p>
<p className="font-normal"><strong>Annual Installed Capacity:</strong> Maximum achievable annual output under normal operating conditions with existing equipment; do not include extraordinary overtime.</p>
</div>
{/* Right card - Entry rules */}
<div className="bg-[#F2ECCF] rounded-md p-4 text-[#6C4527]">
<h3 className="font-semibold mb-2">Entry rules & validation</h3>
<p><strong>Mandatory:</strong> All fields in this step are required except "Reason for variation/0 Target" and free-text Notes.</p>
<p><strong>Monthly entries:</strong> Enter Qty and Cost for each month in the Current and Forecast quarters. Use 0 where there is no output or cost.</p>
<p><strong>Number only:</strong> Use a decimal point where needed. No negative values.</p>
<p><strong>Units:</strong> Use one measurement unit per product across all months.</p>
<p><strong>Delete:</strong> Removing a product here affects this survey only; it does not change your profile.</p>
</div>
</div>
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<h2 className="text-lg font-semibold text-gray-900">Product Data</h2>
<span className="inline-flex items-center rounded text-xs font-medium px-2 py-0.5" style={{ backgroundColor: '#F3FAF4', color: '#2F663C' }}>Current Quarter: Q1 2025</span>
</div>
<div className="flex items-center gap-3">
<button
onClick={addProduct}
disabled={!canAddMoreProducts}
className={`inline-flex items-center gap-2 text-sm font-medium px-3 py-2 rounded ${canAddMoreProducts ? 'bg-[#B68A35] text-white cursor-pointer hover:bg-[#9e782f]' : 'bg-gray-200 text-gray-500 cursor-not-allowed'}`}
className={`inline-flex items-center gap-2 text-sm font-medium px-3 py-2 rounded ${canAddMoreProducts ? 'bg-[#92722A] text-white cursor-pointer hover:bg-[#9e782f]' : 'bg-gray-200 text-gray-500 cursor-not-allowed'}`}
>
<span>+ Add Product</span>
</button>
@ -304,47 +403,140 @@ const ProductData = ({
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<SectionBox title="Q4 2024 Previous" badgeBg="#E7F5FF" badgeText="#003CFF">
<div className="grid grid-cols-1 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Quantity (liter)</label>
<Input
placeholder="Enter quantity"
type="number"
value={p.previousQuantity || ''}
onChange={(e) => updateProductField(p.id, 'previousQuantity', e.target.value)}
/>
<div className="space-y-4">
<div className="flex items-end space-x-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Oct Qty</label>
<Input
className="w-24"
type="number"
value={p.previousQuantity || ''}
onChange={(e) => updateProductField(p.id, 'previousQuantity', e.target.value)}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Nov Qty</label>
<Input
className="w-24"
type="number"
value={p.novQuantity || ''}
onChange={(e) => updateProductField(p.id, 'novQuantity', e.target.value)}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Dec Qty</label>
<Input
className="w-24"
type="number"
value={p.decQuantity || ''}
onChange={(e) => updateProductField(p.id, 'decQuantity', e.target.value)}
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Cost (AED)</label>
<Input
placeholder="Enter cost"
type="number"
value={p.previousCost || ''}
onChange={(e) => updateProductField(p.id, 'previousCost', e.target.value)}
/>
<div className="border-t border-gray-200 my-2"></div>
<div className="flex items-end space-x-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Oct Cost (AED)</label>
<Input
className="w-24"
type="number"
value={p.octCost || ''}
onChange={(e) => updateProductField(p.id, 'octCost', e.target.value)}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Nov Cost (AED)</label>
<Input
className="w-24"
type="number"
value={p.novCost || ''}
onChange={(e) => updateProductField(p.id, 'novCost', e.target.value)}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Dec Cost (AED)</label>
<Input
className="w-24"
type="number"
value={p.decCost || ''}
onChange={(e) => updateProductField(p.id, 'decCost', e.target.value)}
/>
</div>
</div>
</div>
</SectionBox>
<SectionBox title="Q1 2025 Current" badgeBg="#F3FAF4" badgeText="#2F663C">
<div className="grid grid-cols-1 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Quantity (liter)</label>
<Input
placeholder="Enter quantity"
type="number"
value={p.currentQuantity || ''}
onChange={(e) => updateProductField(p.id, 'currentQuantity', e.target.value)}
/>
<div className="space-y-4">
<div className="flex items-end space-x-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Jan Qty<span className="text-red-600">*</span></label>
<Input
className="w-24"
type="number"
value={p.janQuantity || ''}
required
placeholder="Enter"
onChange={(e) => updateProductField(p.id, 'janQuantity', e.target.value)}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Feb Qty<span className="text-red-600">*</span></label>
<Input
className="w-24"
type="number"
value={p.febQuantity || ''}
required
placeholder="Enter"
onChange={(e) => updateProductField(p.id, 'febQuantity', e.target.value)}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Mar Qty<span className="text-red-600"></span></label>
<Input
className="w-24"
type="number"
value={p.marQuantity || ''}
required
placeholder="Enter"
onChange={(e) => updateProductField(p.id, 'marQuantity', e.target.value)}
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Cost (AED)</label>
<Input
placeholder="Enter cost"
type="number"
value={p.currentCost || ''}
onChange={(e) => updateProductField(p.id, 'currentCost', e.target.value)}
/>
<div className="flex items-end space-x-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Jan Cost (AED)<span className="text-red-600"></span></label>
<Input
className="w-24"
type="number"
value={p.janCost || ''}
required
placeholder="Enter"
onChange={(e) => updateProductField(p.id, 'janCost', e.target.value)}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Feb Cost (AED)<span className="text-red-600"></span></label>
<Input
className="w-24"
type="number"
value={p.febCost || ''}
required
placeholder="Enter"
onChange={(e) => updateProductField(p.id, 'febCost', e.target.value)}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Mar Cost (AED)<span className="text-red-600"></span></label>
<Input
className="w-24"
type="number"
value={p.marCost || ''}
required
placeholder="Enter"
onChange={(e) => updateProductField(p.id, 'marCost', e.target.value)}
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Reason for Variation</label>
@ -358,49 +550,83 @@ const ProductData = ({
<p className="mt-1 text-xs text-red-600">{reasonsError}</p>
)}
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Other reason for variation</label>
<Input
placeholder="Specify other reason"
value={p.otherVariationReason || ''}
onChange={(e) => updateProductField(p.id, 'otherVariationReason', e.target.value)}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Remarks (optional)</label>
<Textarea
placeholder="Add short note.."
value={p.remarks || ''}
onChange={(e) => updateProductField(p.id, 'remarks', e.target.value)}
/>
</div>
</div>
</SectionBox>
<SectionBox title="Q2 2025 Forecast" badgeBg="#F9F7ED" badgeText="#7C5E24">
<div className="grid grid-cols-1 gap-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-4">
<div className="flex items-end space-x-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Expected quantity (liter)</label>
<label className="block text-sm font-medium text-gray-700 mb-1">Apr Qty</label>
<Input
placeholder="Enter quantity"
className="w-24"
type="number"
value={p.forecastQuantity || ''}
onChange={(e) => updateProductField(p.id, 'forecastQuantity', e.target.value)}
required
placeholder="Enter"
value={p.aprQuantity || ''}
onChange={(e) => updateProductField(p.id, 'aprQuantity', e.target.value)}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Expected cost (AED)</label>
<label className="block text-sm font-medium text-gray-700 mb-1">May Qty</label>
<Input
placeholder="Enter cost"
className="w-24"
type="number"
value={p.forecastCost || ''}
onChange={(e) => updateProductField(p.id, 'forecastCost', e.target.value)}
required
placeholder="Enter"
value={p.mayQuantity || ''}
onChange={(e) => updateProductField(p.id, 'mayQuantity', e.target.value)}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Jun Qty</label>
<Input
className="w-24"
type="number"
required
placeholder="Enter"
value={p.junQuantity || ''}
onChange={(e) => updateProductField(p.id, 'junQuantity', e.target.value)}
/>
</div>
</div>
<div className="flex items-end space-x-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Apr Cost (AED)</label>
<Input
className="w-24"
type="number"
required
placeholder="Enter"
value={p.aprCost || ''}
onChange={(e) => updateProductField(p.id, 'aprCost', e.target.value)}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">May Cost (AED)</label>
<Input
className="w-24"
type="number"
required
placeholder="Enter"
value={p.mayCost || ''}
onChange={(e) => updateProductField(p.id, 'mayCost', e.target.value)}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Jun Cost (AED)</label>
<Input
className="w-24"
type="number"
required
placeholder="Enter"
value={p.junCost || ''}
onChange={(e) => updateProductField(p.id, 'junCost', e.target.value)}
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Reason for 0 Target</label>
<label className="block text-sm font-medium text-gray-700 mb-1">Reason for 0 Target<span className="text-red-600">*</span></label>
<Select
placeholder={isLoadingZeroReasons ? 'Loading reasons...' : 'Select reason'}
options={zeroTargetReasons}
@ -411,14 +637,6 @@ const ProductData = ({
<p className="mt-1 text-xs text-red-600">{zeroReasonsError}</p>
)}
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Other reason for 0 target</label>
<Input
placeholder="Specify other reason"
value={p.otherZeroTargetReason || ''}
onChange={(e) => updateProductField(p.id, 'otherZeroTargetReason', e.target.value)}
/>
</div>
</div>
</SectionBox>
</div>
@ -451,4 +669,3 @@ const ProductData = ({
};
export default ProductData;

View File

@ -1,38 +1,47 @@
import React from 'react';
import Table from '@/components/common/Table';
import BackVendor from '@/assets/images/caretdown-black.svg';
const caretUpSrc = '/assets/images/caret-up.svg';
const caretDownSrc = '/assets/images/CaretDown-black.svg';
const establishmentIconSrc = '/assets/images/Establishment.svg';
const establishmentIdIconSrc = '/assets/images/Establishmentid.svg';
const emailIconSrc = '/assets/images/emailid.svg';
const emiratesIconSrc = '/assets/images/emirates.svg';
const totalEmployeesIconSrc = '/assets/images/totalemployess.svg';
const maleEmployeesIconSrc = '/assets/images/maleemployes.svg';
const femaleEmployeesIconSrc = '/assets/images/femaleemployess.svg';
const uaeIconSrc = '/assets/images/uae.svg';
const nonUaeIconSrc = '/assets/images/nonuae.svg';
const Card = ({ title, children }) => (
<div className="bg-white w-full rounded-lg shadow-sm ring-1 ring-gray-200">
const Card = ({ title, children, className = '' }) => (
<div className={`bg-white rounded-lg border border-gray-200 overflow-hidden ${className}`}>
{title && (
<div className="px-5 pt-5">
<h3 className="text-sm font-semibold text-gray-900">{title}</h3>
<div className="px-6 py-4 border-b border-gray-200">
<h3 className="text-base font-semibold text-gray-900">{title}</h3>
</div>
)}
<div className="p-5">
<div className="p-6">
{children}
</div>
</div>
);
const KeyValueTable = ({ rows = [] }) => (
<div className="overflow-hidden rounded-md ring-1 ring-[#C3C6CB]">
<div className="overflow-x-auto">
<table className="min-w-[720px] w-full table-fixed divide-y divide-[#C3C6CB]">
<tbody className="bg-white divide-y divide-[#C3C6CB]">
{rows.map(([label, value], idx) => (
<tr key={idx}>
<td
className="w-[628px] px-4 h-12 align-middle text-sm text-gray-900 bg-[#F2ECCF] font-medium"
style={{ borderTopLeftRadius: idx === 0 ? 4 : 0, borderBottomLeftRadius: idx === rows.length - 1 ? 4 : 0 }}
>
{label}
</td>
<td className="px-4 h-12 align-middle text-sm text-gray-900">{value}</td>
</tr>
))}
</tbody>
</table>
const InfoCard = ({ icon: Icon, label, value }) => (
<div className="flex items-start gap-3 p-3 bg-gray-50 rounded-lg">
<div className="flex-shrink-0 p-2 bg-white rounded-lg border border-gray-200">
<img src={Icon} alt="" className="w-5 h-5" />
</div>
<div>
<p className="text-xs font-medium text-gray-500">{label}</p>
<p className="text-sm font-medium text-gray-900 mt-0.5">{value || '—'}</p>
</div>
</div>
);
const DetailSection = ({ title, children, className = '' }) => (
<div className={`space-y-4 ${className}`}>
<h4 className="text-sm font-medium text-gray-700">{title}</h4>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5 gap-4">
{children}
</div>
</div>
);
@ -46,42 +55,193 @@ const formatNumber = (value) => {
return new Intl.NumberFormat('en-US').format(number);
};
const buildEstablishmentRows = (establishment) => {
const buildEstablishmentDetails = (establishment) => {
if (!establishment) return [];
return [
['Establishment Name', establishment.establishmentName || '—'],
['Establishment ID', establishment.permanentFactoryCode || '—'],
['Industry Code', establishment.industryCode || '—'],
['License Number', establishment.licenseNumber || '—'],
['ISIC Code', establishment.isicCode || '—'],
['Emirate', establishment.emirate || '—'],
['Quarter', establishment.quarter || '—'],
['Year', establishment.year || '—'],
{ icon: establishmentIconSrc, label: 'Establishment Name', value: establishment.establishmentName },
{ icon: establishmentIdIconSrc, label: 'Establishment ID', value: establishment.licenseNumber },
{ icon: emailIconSrc, label: 'Email', value: establishment.email },
{ icon: emiratesIconSrc, label: 'Emirate', value: establishment.emirate },
];
};
const buildEmploymentRows = (establishment) => {
const info = establishment?.employeeInfo || {};
return [
['Total Employees', formatNumber(info.totalEmployees) || '—'],
['Emirati Male', formatNumber(info.emiratiMale) || '—'],
['Emirati Female', formatNumber(info.emiratiFemale) || '—'],
['Non-Emirati Male', formatNumber(info.nonEmiratiMale) || '—'],
['Non-Emirati Female', formatNumber(info.nonEmiratiFemale) || '—'],
['Total Emirati', formatNumber(info.totalEmirati) || '—'],
];
const employmentIcons = {
'Total Employees': totalEmployeesIconSrc,
'Male Employees': maleEmployeesIconSrc,
'Female Employees': femaleEmployeesIconSrc,
'UAE Nationals': uaeIconSrc,
'Non-UAE Nationals': nonUaeIconSrc,
};
const buildEmploymentDetails = (establishment) => {
if (!establishment?.employeeInfo) return [];
const employeeInfo = establishment.employeeInfo;
const result = [];
// Only add fields that exist in the employeeInfo object
if (employeeInfo.emiratiMale !== undefined || employeeInfo.nonEmiratiMale !== undefined) {
const totalMale = employeeInfo.emiratiMale;
result.push({
icon: maleEmployeesIconSrc,
label: 'Male Employees',
value: formatNumber(totalMale)
});
}
if (employeeInfo.emiratiFemale !== undefined || employeeInfo.nonEmiratiFemale !== undefined) {
const totalFemale = employeeInfo.emiratiFemale;
result.push({
icon: femaleEmployeesIconSrc,
label: 'Female Employees',
value: formatNumber(totalFemale)
});
}
if (employeeInfo.emiratiMale !== undefined || employeeInfo.emiratiFemale !== undefined) {
const totalUAE = (Number(employeeInfo.emiratiMale) || 0) + (Number(employeeInfo.emiratiFemale) || 0);
result.push({
icon: uaeIconSrc,
label: 'UAE Nationals',
value: formatNumber(totalUAE)
});
}
if (employeeInfo.nonEmiratiMale !== undefined || employeeInfo.nonEmiratiFemale !== undefined) {
const totalNonUAE = (Number(employeeInfo.nonEmiratiMale) || 0) + (Number(employeeInfo.nonEmiratiFemale) || 0);
result.push({
icon: nonUaeIconSrc,
label: 'Non-UAE Nationals',
value: formatNumber(totalNonUAE)
});
}
// Add total employees if any of the fields exist
if (result.length > 0) {
const total = result.reduce((sum, item) => {
if (item.label === 'Male Employees' || item.label === 'Female Employees') {
return sum + parseInt(item.value.replace(/,/g, '') || 0);
}
return sum;
}, 0);
result.unshift({
icon: totalEmployeesIconSrc,
label: 'Total Employees',
value: formatNumber(employeeInfo.totalEmployees || total)
});
}
return result;
};
const buildProductRows = (products = []) => {
if (!Array.isArray(products)) return [];
return products.map((product) => [
product.product || '—',
product.unit || '—',
formatNumber(product.currentQuantity) || '—',
formatNumber(product.currentCost) || '—',
formatNumber(product.forecastQuantity) || '—',
formatNumber(product.forecastCost) || '—',
]);
// Helper function to find display name by ID in an array of options
const findDisplayName = (options, value) => {
if (!options || !Array.isArray(options)) return value || '—';
const option = options.find(opt => opt.value === value || opt.id === value);
return option ? option.label || option.name || value : value || '—';
};
const buildProductRows = (products = [], options = {}) => {
console.log('Raw products data:', products); // Debug log
console.log('Available options:', options); // Debug log
if (!Array.isArray(products)) {
console.warn('buildProductRows: Expected an array but got', typeof products);
return [];
}
if (products.length === 0) {
console.warn('buildProductRows: Empty products array received');
return [];
}
const {
variationReasons = [],
zeroTargetReasons = [],
unitOptions = [],
productOptions = []
} = options;
const rows = products.map((product, index) => {
if (!product) {
console.warn(`buildProductRows: Product at index ${index} is null or undefined`);
return null;
}
try {
// Find the full product details from productOptions if available
const fullProduct = productOptions.find(p => p.id === product.productId || p.value === product.productId);
console.log("fullProduct",fullProduct)
// Extract product details with better fallbacks
const productId = product.id || `product-${Math.random().toString(36).substr(2, 9)}`;
const productName = fullProduct?.label || fullProduct?.name || product.productName || product.product?.name || product.product;
console.log("productName",productName)
const productCode = fullProduct?.code || product.productCode || product.code || product.product?.code || product.id || `CODE-${index + 1}`;
console.log("productCode",productCode)
// Find unit display name
const unitnames = findDisplayName(unitOptions)
console.log("unitnames",unitnames)
const unitName = findDisplayName(unitOptions, product.unit);
console.log("unitName",unitName)
// Find reason display names
const variationReasonName = findDisplayName(variationReasons, product.variationReason);
const zeroTargetReasonName = findDisplayName(zeroTargetReasons, product.zeroTargetReason);
const capacity = product.capacity !== undefined && product.capacity !== null ? formatNumber(product.capacity) : '—';
// Map the quantity and cost data from the product form
const row = {
id: productId,
product: productName,
productCode: productCode,
unit: unitName, // Use display name instead of ID
capacity: capacity,
// Current Quarter (Q1) - January to March
q1_jan_quantity: formatNumber(product.janQuantity) || '—',
q1_feb_quantity: formatNumber(product.febQuantity) || '—',
q1_mar_quantity: formatNumber(product.marQuantity) || '—',
q1_jan_cost: formatNumber(product.janCost) || '—',
q1_feb_cost: formatNumber(product.febCost) || '—',
q1_mar_cost: formatNumber(product.marCost) || '—',
// Next Quarter (Q2) - April to June
q2_apr_quantity: formatNumber(product.aprQuantity) || '—',
q2_may_quantity: formatNumber(product.mayQuantity) || '—',
q2_jun_quantity: formatNumber(product.junQuantity) || '—',
q2_apr_cost: formatNumber(product.aprCost) || '—',
q2_may_cost: formatNumber(product.mayCost) || '—',
q2_jun_cost: formatNumber(product.junCost) || '—',
// Previous Quarter (Q4) - October to December (if available)
q4_oct_quantity: formatNumber(product.previousQuantity) || '—',
q4_nov_quantity: formatNumber(product.novQuantity) || '—',
q4_dec_quantity: formatNumber(product.decQuantity) || '—',
q4_oct_cost: formatNumber(product.octCost) || '—',
q4_nov_cost: formatNumber(product.novCost) || '—',
q4_dec_cost: formatNumber(product.decCost) || '—',
// Reasons and remarks - use display names
variationReason: variationReasonName,
zeroTargetReason: zeroTargetReasonName,
remarks: product.remarks || '—',
// Keep the raw product data for debugging
_raw: { ...product }
};
console.log(`Processed product ${index + 1}:`, row); // Debug log
return row;
} catch (error) {
console.error(`Error processing product at index ${index}:`, error, product);
return null;
}
});
// Filter out any null/undefined rows that might have been created due to errors
return rows.filter(Boolean);
};
const ReviewSubmit = ({
@ -95,9 +255,11 @@ const ReviewSubmit = ({
hasSubmitted = false,
}) => {
const [confirm, setConfirm] = React.useState(false);
const establishmentRows = React.useMemo(() => buildEstablishmentRows(establishment), [establishment]);
const employmentRows = React.useMemo(() => buildEmploymentRows(establishment), [establishment]);
const establishmentDetails = React.useMemo(() => buildEstablishmentDetails(establishment), [establishment]);
const employmentDetails = React.useMemo(() => buildEmploymentDetails(establishment), [establishment]);
const productRows = React.useMemo(() => buildProductRows(products), [products]);
const infoBadgeClass = 'inline-flex items-center rounded-[10px] border border-[#E5D7AA] bg-[#FDF9EB] px-3 py-1 text-sm font-medium text-[#92722A]';
const submitLabel = React.useMemo(() => {
if (hasSubmitted) return 'Submitted';
@ -152,36 +314,119 @@ const ReviewSubmit = ({
</div>
)}
<h2 className="text-lg font-semibold text-gray-900">Review & Submit</h2>
{/* <div className="space-y-6">
<Card title="Establishment Information" className="mb-6">
<div className="space-y-6">
<DetailSection>
{establishmentDetails.map((detail, idx) => (
<InfoCard
key={idx}
icon={detail.icon}
label={detail.label}
value={detail.value}
/>
))}
</DetailSection>
</div>
</Card>
<Card title="Establishment Information">
<KeyValueTable
rows={establishmentRows}
/>
</Card>
<Card title="Employment Information" className="mb-6">
<div className="space-y-6">
<DetailSection>
{employmentDetails.map((detail, idx) => (
<InfoCard
key={idx}
icon={detail.icon}
label={detail.label}
value={detail.value}
/>
))}
</DetailSection>
</div>
</Card>
<Card title="Product Summary">
<Table
headers={["Product", "Unit", "Current Quarter Quantity", "Current Quarter Cost (AED)", "Next Quarter Quantity", "Next Quarter Cost (AED)"]}
rows={productRows}
/>
</Card>
{productRows.length > 0 && (
<Card title="Product Information" className="mb-6">
<div className="space-y-6">
{productRows.map((product, index) => (
<div key={product.id || index} className="border border-gray-200 rounded-md p-4">
<div className="flex justify-between items-start mb-4">
<h3 className="text-sm font-semibold text-gray-900">
Product: <span className="font-normal">{product.product}</span>
</h3>
<div className="flex gap-3">
<div className="flex items-center gap-1 border border-gray-200 rounded px-2 py-1 text-xs">
<span className="font-semibold text-gray-700">Unit:</span>
<span className="text-gray-600">{product.unit}</span>
</div>
<div className="flex items-center gap-1 border border-gray-200 rounded px-2 py-1 text-xs">
<span className="font-semibold text-gray-700">Capacity:</span>
<span className="text-gray-600">{product.capacity}</span>
</div>
</div>
</div>
<div className="overflow-x-auto">
<table className="min-w-full border border-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">Period</th>
<th className="px-4 py-2 text-right text-xs font-medium text-gray-500 uppercase">Quantity</th>
<th className="px-4 py-2 text-right text-xs font-medium text-gray-500 uppercase">Cost (AED)</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200">
<tr>
<td className="px-4 py-3 text-sm font-medium text-gray-900">Current</td>
<td className="px-4 py-3 text-sm text-gray-500 text-right">{product.currentQuantity}</td>
<td className="px-4 py-3 text-sm text-gray-500 text-right">{product.currentCost}</td>
</tr>
<tr>
<td className="px-4 py-3 text-sm font-medium text-gray-900">Forecast</td>
<td className="px-4 py-3 text-sm text-gray-500 text-right">{product.forecastQuantity}</td>
<td className="px-4 py-3 text-sm text-gray-500 text-right">{product.forecastCost}</td>
</tr>
</tbody>
</table>
</div>
{(product.variationReason || product.zeroTargetReason) && (
<div className="mt-4 pt-4 border-t border-gray-200">
{product.variationReason && product.variationReason !== '—' && (
<p className="text-xs text-gray-600 mb-2">
<span className="font-medium">Variation Reason:</span> {product.variationReason}
</p>
)}
{product.zeroTargetReason && product.zeroTargetReason !== '—' && (
<p className="text-xs text-gray-600">
<span className="font-medium">Zero Target Reason:</span> {product.zeroTargetReason}
</p>
)}
</div>
)}
{product.remarks && product.remarks !== '—' && (
<div className="mt-3 pt-3 border-t border-gray-100">
<p className="text-xs text-gray-500">
<span className="font-medium">Remarks:</span> {product.remarks}
</p>
</div>
)}
</div>
))}
</div>
</Card>
)}
</div> */}
<Card title="Employment Details">
<KeyValueTable
rows={employmentRows}
/>
</Card>
{/* Info note */}
{!hasSubmitted && (
{/* {!hasSubmitted && (
<div className="rounded-md bg-[#E7F0FF] border border-[#C6DBFF] px-4 py-3 text-[13px] text-[#2563EB]">
Review your data carefully before submission. You can go back to previous steps to edit any details. Once submitted, changes will require admin approval.
</div>
)}
{/* Confirmation */}
<div className="bg-white rounded-md ring-1 ring-gray-200 px-4 py-3">
{/* <div className="bg-white rounded-md ring-1 ring-gray-200 px-4 py-3">
<label className="flex items-start gap-3 text-sm text-gray-700">
<input
type="checkbox"
@ -192,28 +437,315 @@ const ReviewSubmit = ({
/>
<span>I hereby confirm that all data entered is accurate and complete to the best of my knowledge.</span>
</label>
</div>
</div> */}
{/* Footer actions */}
<div className="flex flex-col sm:flex-row justify-between gap-3">
<button
onClick={onBack}
className="inline-flex items-center gap-2 h-9 px-4 rounded-md border border-[#92722A] text-[#92722A] bg-transparent hover:bg-[#92722A]/10"
>
<img src={BackVendor} alt="" className="h-4 w-4" />
<span>Back</span>
</button>
<button
disabled={!confirm || isSubmitting || hasSubmitted}
onClick={onSubmit}
className={`inline-flex items-center h-9 px-5 rounded-md cursor-pointer ${
!confirm || isSubmitting || hasSubmitted
? 'bg-gray-200 text-gray-400 cursor-not-allowed'
: 'bg-[#92722A] text-white hover:bg-[#7b5c1f]'
}`}
>
<span>{submitLabel}</span>
</button>
<div className="space-y-6">
{/* Establishment and Employment Information */}
<section className="min-h-[219px] rounded-[16px] border border-[#E6EAF5] bg-white px-0 py-6 shadow-[0_16px_32px_rgba(15,23,42,0.08)]">
<div className="grid gap-1 lg:grid-cols-2">
<div className="space-y-6 lg:pr-6 lg:pl-15">
<div className="flex items-center gap-3">
<h2 className="text-lg font-semibold text-[#232528]">Establishment Information</h2>
</div>
<div className="grid gap-4 sm:grid-cols-2">
{establishmentDetails.map((item) => (
<div key={item.label} className="flex items-start gap-3">
{item.label === 'Establishment Name' && (
<img src={establishmentIconSrc} alt="Establishment" className="h-5 w-5" />
)}
{item.label === 'Establishment ID' && (
<img src={establishmentIdIconSrc} alt="Establishment ID" className="h-5 w-5" />
)}
{item.label === 'Email' && (
<img src={emailIconSrc} alt="Email" className="h-5 w-5" />
)}
{item.label === 'Emirate' && (
<img src={emiratesIconSrc} alt="Emirate" className="h-5 w-5" />
)}
{item.label === 'License Number' && (
<img src={establishmentIdIconSrc} alt="License Number" className="h-5 w-5" />
)}
{!['Establishment Name', 'Establishment ID', 'Email', 'Emirate', 'License Number'].includes(item.label) && (
<span className="mt-1 h-2.5 w-2.5 rounded-full bg-[#92722A]" />
)}
<div className="space-y-1">
<span className="text-sm font-semibold text-[#232528]">{item.label}</span>
<br />
<span className="text-sm text-[#4B5563]">{item.value || '--'}</span>
</div>
</div>
))}
</div>
</div>
<div className="space-y-6 border-t border-[#E6EAF5] pt-6 lg:border-0 lg:border-l lg:border-[#E6EAF5] lg:pl-6 lg:pt-1">
<div className="flex items-center gap-3">
<h2 className="text-lg font-semibold text-[#232528]">Employment Details</h2>
</div>
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{employmentDetails.map((item) => (
<div key={item.label} className="flex items-start gap-3">
{employmentIcons[item.label] ? (
<img src={employmentIcons[item.label]} alt={item.label} className="h-5 w-5" />
) : (
<span className="mt-1 h-2.5 w-2.5 rounded-full bg-[#92722A]" />
)}
<div className="space-y-1">
<span className="text-sm font-semibold text-[#232528]">{item.label}</span>
<br/>
<span className="text-sm text-[#4B5563]">{item.value || '--'}</span>
</div>
</div>
))}
</div>
</div>
</div>
</section>
{/* Product Information Section */}
{/* <section className="rounded-[16px] border border-[#E6EAF5] bg-white px-0 py-6 shadow-[0_16px_32px_rgba(15,23,42,0.08)]">
<div className="px-6">
<div className="flex items-center justify-between">
<h2 className="text-lg font-semibold text-[#232528]">Product Information</h2>
<div className="flex gap-2">
<div className="flex items-center gap-1 rounded-[10px] border border-[#E5D7AA] bg-[#FDF9EB] px-3 py-1 text-sm font-medium text-[#92722A]">
<img src={CaretUp} alt="" className="h-3 w-3" />
<span>Q1 2025</span>
</div>
<div className="flex items-center gap-1 rounded-[10px] border border-[#E5D7AA] bg-[#FDF9EB] px-3 py-1 text-sm font-medium text-[#92722A]">
<img src={CaretUp} alt="" className="h-3 w-3" />
<span>Q2 2025</span>
</div>
</div>
</div>
<div className="mt-6 overflow-x-auto">
<table className="min-w-full divide-y divide-[#E5E7EB]">
<thead className="bg-[#F9FAFB]">
<tr>
<th scope="col" className="px-4 py-3 text-left text-xs font-medium text-[#6B7280] uppercase tracking-wider">
Product
</th>
<th scope="col" className="px-4 py-3 text-left text-xs font-medium text-[#6B7280] uppercase tracking-wider">
Unit
</th>
<th scope="col" className="px-4 py-3 text-left text-xs font-medium text-[#6B7280] uppercase tracking-wider">
Q1 2025
</th>
<th scope="col" className="px-4 py-3 text-left text-xs font-medium text-[#6B7280] uppercase tracking-wider">
Q2 2025
</th>
<th scope="col" className="px-4 py-3 text-left text-xs font-medium text-[#6B7280] uppercase tracking-wider">
Reason
</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-[#E5E7EB]">
{products.map((product, index) => (
<tr key={index}>
<td className="px-4 py-4 whitespace-nowrap text-sm font-medium text-[#111827]">
{product.product || '—'}
</td>
<td className="px-4 py-4 whitespace-nowrap text-sm text-[#6B7280]">
{product.unit || '—'}
</td>
<td className="px-4 py-4 whitespace-nowrap text-sm text-[#6B7280]">
<div className="flex flex-col">
<span>Qty: {formatNumber(product.q1Quantity) || '—'}</span>
<span>Cost: {formatNumber(product.q1Cost) || '—'}</span>
</div>
</td>
<td className="px-4 py-4 whitespace-nowrap text-sm text-[#6B7280]">
<div className="flex flex-col">
<span>Qty: {formatNumber(product.q2Quantity) || '—'}</span>
<span>Cost: {formatNumber(product.q2Cost) || '—'}</span>
</div>
</td>
<td className="px-4 py-4 text-sm text-[#6B7280]">
{product.reason || '—'}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
{/* Product Information Section */}
{productRows.length > 0 && productRows.map((product, index) => (
<section key={product.id || index} className="border border-gray-200 rounded-md bg-white p-4 mb-6 shadow-sm">
{/* Header */}
<div className="flex justify-between items-start mb-4">
<h3 className="text-sm font-semibold text-[#2E2E2E]">
<span className="text-gray-500">Product:</span>{' '}
<span className="font-normal">{product.product}</span>
{product.productCode && product.productCode !== product.product && (
<span className="text-gray-400 text-xs ml-2">(ID: {product.productCode})</span>
)}
</h3>
<div className="flex gap-3">
<div className="flex items-center gap-1 border border-gray-200 rounded px-2 py-1 text-xs">
<span className="font-semibold text-gray-700">Unit:</span>
<span className="text-gray-600">{product.unit}</span>
</div>
<div className="flex items-center gap-1 border border-gray-200 rounded px-2 py-1 text-xs">
<span className="font-semibold text-gray-700">Capacity:</span>
<span className="text-gray-600">{product.capacity}</span>
</div>
</div>
</div>
{/* Table */}
<div className="overflow-x-auto">
<table className="min-w-full border border-gray-300 text-sm text-center">
<thead>
<tr className="font-semibold text-[#232528] text-center">
<th rowSpan="2" className="border border-gray-300 py-2 px-3 text-left bg-[#F2ECCF] w-[140px]">
Metric
</th>
<th colSpan="3" className="border border-gray-300 py-2 px-3 bg-[#F2ECCF]">
Q4-2024 (Previous Quarter)
</th>
<th colSpan="3" className="border border-gray-300 py-2 px-3 bg-[#F2ECCF]">
Q1-2025 (Current Quarter)
</th>
<th colSpan="3" className="border border-gray-300 py-2 px-3 bg-[#F2ECCF]">
Q2-2025 (Next Quarter)
</th>
</tr>
{/* Second header row */}
<tr className="bg-white text-[13px] font-medium">
<th className="border border-gray-300 py-2 px-3 bg-[#E9F6FF] text-[#286CFF]">Oct</th>
<th className="border border-gray-300 py-2 px-3 bg-[#E9F6FF] text-[#286CFF]">Nov</th>
<th className="border border-gray-300 py-2 px-3 bg-[#E9F6FF] text-[#286CFF]">Dec</th>
<th className="border border-gray-300 py-2 px-3 bg-[#F3FAF4] text-[#2F663C]">Jan</th>
<th className="border border-gray-300 py-2 px-3 bg-[#F3FAF4] text-[#2F663C]">Feb</th>
<th className="border border-gray-300 py-2 px-3 bg-[#F3FAF4] text-[#2F663C]">Mar</th>
<th className="border border-gray-300 py-2 px-3 bg-[#FFF7E9] text-[#F29F0E]">Apr</th>
<th className="border border-gray-300 py-2 px-3 bg-[#FFF7E9] text-[#F29F0E]">May</th>
<th className="border border-gray-300 py-2 px-3 bg-[#FFF7E9] text-[#F29F0E]">Jun</th>
</tr>
</thead>
<tbody>
{/* Quantity Row */}
<tr>
<td className="border border-gray-300 py-2 px-3 text-left font-medium">
Quantity ({product.unit || 'units'})
</td>
<td className="border border-gray-300 py-2">{product.q4_oct_quantity || '—'}</td>
<td className="border border-gray-300 py-2">{product.q4_nov_quantity || '—'}</td>
<td className="border border-gray-300 py-2">{product.q4_dec_quantity || '—'}</td>
<td className="border border-gray-300 py-2">{product.q1_jan_quantity || '—'}</td>
<td className="border border-gray-300 py-2">{product.q1_feb_quantity || '—'}</td>
<td className="border border-gray-300 py-2">{product.q1_mar_quantity || '—'}</td>
<td className="border border-gray-300 py-2">{product.q2_apr_quantity || '—'}</td>
<td className="border border-gray-300 py-2">{product.q2_may_quantity || '—'}</td>
<td className="border border-gray-300 py-2">{product.q2_jun_quantity || '—'}</td>
</tr>
{/* Cost Row */}
<tr>
<td className="border border-gray-300 py-2 px-3 text-left font-medium">
Cost (AED)
</td>
<td className="border border-gray-300 py-2">{product.q4_oct_cost || '—'}</td>
<td className="border border-gray-300 py-2">{product.q4_nov_cost || '—'}</td>
<td className="border border-gray-300 py-2">{product.q4_dec_cost || '—'}</td>
<td className="border border-gray-300 py-2">{product.q1_jan_cost || '—'}</td>
<td className="border border-gray-300 py-2">{product.q1_feb_cost || '—'}</td>
<td className="border border-gray-300 py-2">{product.q1_mar_cost || '—'}</td>
<td className="border border-gray-300 py-2">{product.q2_apr_cost || '—'}</td>
<td className="border border-gray-300 py-2">{product.q2_may_cost || '—'}</td>
<td className="border border-gray-300 py-2">{product.q2_jun_cost || '—'}</td>
</tr>
{/* Reason Current */}
<tr>
<td className="border border-gray-300 py-2 px-3 text-left font-medium">
Reason (Current)
</td>
<td colSpan="3" className="border border-gray-300 py-2 text-center">
-- --
</td>
<td colSpan="3" className="border border-gray-300 py-2 text-center bg-[#F3FAF4] text-[#2F663C]">
{product.variationReason || '—'}
</td>
<td colSpan="3" className="border border-gray-300 py-2 text-center">
-- --
</td>
</tr>
{/* Reason Forecast */}
<tr>
<td className="border border-gray-300 py-2 px-3 text-left font-medium">
Reason (Forecast)
</td>
<td colSpan="6" className="border border-gray-300 py-2 text-center">
-- --
</td>
<td colSpan="3" className="border border-gray-300 py-2 text-center bg-[#FFF7E9] text-[#F29F0E]">
{product.zeroTargetReason || '—'}
</td>
</tr>
</tbody>
</table>
</div>
{/* Remarks */}
<div className="mt-4 text-xs text-gray-600">
<p className="font-semibold mb-1">Remarks:</p>
<div className="border border-[#F3B340] rounded-md p-2 text-sm bg-white">
{product.remarks || 'No remarks provided'}
</div>
</div>
</section>
))}
{/* Confirmation and Buttons */}
<div className="rounded-[16px] border border-[#E6EAF5] bg-white p-6 shadow-[0_16px_32px_rgba(15,23,42,0.08)]">
{!hasSubmitted && (
<div className="mb-6 rounded-md bg-[#E7F0FF] border border-[#C6DBFF] px-4 py-3 text-sm text-[#2563EB]">
Review your data carefully before submission. You can go back to previous steps to edit any details. Once submitted, changes will require admin approval.
</div>
)}
<div className="bg-white rounded-md">
<label className="flex items-start gap-3 text-sm text-[#4B5563]">
<input
type="checkbox"
className="mt-1 h-4 w-4 text-[#92722A] border-gray-300 rounded"
checked={confirm}
disabled={hasSubmitted}
onChange={(e) => setConfirm(e.target.checked)}
/>
<span>I hereby confirm that all data entered is accurate and complete to the best of my knowledge.</span>
</label>
</div>
<div className="mt-6 flex flex-col sm:flex-row justify-between gap-3">
<button
onClick={onBack}
className="inline-flex items-center justify-center gap-2 h-9 px-4 rounded-md border border-[#92722A] text-[#92722A] bg-transparent hover:bg-[#92722A]/10 transition-colors"
>
<img src={caretDownSrc} alt="" className="h-4 w-4 rotate-90" />
<span>Back</span>
</button>
<button
disabled={!confirm || isSubmitting || hasSubmitted}
onClick={onSubmit}
className={`inline-flex items-center justify-center h-9 px-5 rounded-md transition-colors ${
!confirm || isSubmitting || hasSubmitted
? 'bg-gray-200 text-gray-400 cursor-not-allowed'
: 'bg-[#92722A] text-white hover:bg-[#7b5c1f]'
}`}
>
<span>{submitLabel}</span>
</button>
</div>
</div>
</div>
</div>
);

View File

@ -2,14 +2,15 @@ import React, { useState, useEffect } from 'react';
import AdminHeader from '@/components/admin/AdminHeader';
import StatCard from '@/components/admin/StatCard';
import SubmissionTable from '@/components/admin/SubmissionTable';
import WpfSurveyIcon from '@/assets/images/wpf_survey.svg';
import SubmittedIcon from '@/assets/images/check-circle-fill 1.svg';
import ApprovedIcon from '@/assets/images/check-circle-fill 1-approved.svg';
import RejectedIcon from '@/assets/images/warning-circle-fill 1.svg';
import OverdueIcon from '@/assets/images/warning-fill 1.svg';
import PendingIcon from '@/assets/images/info-fill 1.svg';
import apiClient from '@/services/api/apiClient';
const surveyIconSrc = '/assets/images/wpf_survey.svg';
const submittedIconSrc = '/assets/images/check-circle-fill 1.svg';
const approvedIconSrc = '/assets/images/check-circle-fill 1-approved.svg';
const rejectedIconSrc = '/assets/images/warning-circle-fill 1.svg';
const overdueIconSrc = '/assets/images/warning-fill 1.svg';
const pendingIconSrc = '/assets/images/info-fill 1.svg';
const AdminDashboard = () => {
const [summary, setSummary] = useState({
total_establishments: 0,
@ -96,37 +97,37 @@ const AdminDashboard = () => {
label="Total Establishments"
value={loading ? '--' : summary.total_establishments}
width={290}
icon={<img src={WpfSurveyIcon} alt="Total Establishments" className="h-5 w-5" />}
icon={<img src={surveyIconSrc} alt="Total Establishments" className="h-5 w-5" />}
/>
<StatCard
label="Submitted"
value={loading ? '--' : summary.submitted}
width={190}
icon={<img src={SubmittedIcon} alt="Submitted" className="h-5 w-5" />}
icon={<img src={submittedIconSrc} alt="Submitted" className="h-5 w-5" />}
/>
<StatCard
label="Approved"
value={loading ? '--' : summary.approved}
width={190}
icon={<img src={ApprovedIcon} alt="Approved" className="h-5 w-5" />}
icon={<img src={approvedIconSrc} alt="Approved" className="h-5 w-5" />}
/>
<StatCard
label="Rejected"
value={loading ? '--' : summary.rejected}
width={190}
icon={<img src={RejectedIcon} alt="Rejected" className="h-5 w-5" />}
icon={<img src={rejectedIconSrc} alt="Rejected" className="h-5 w-5" />}
/>
<StatCard
label="Not Started"
value={loading ? '--' : summary.not_started}
width={190}
icon={<img src={OverdueIcon} alt="Not Started" className="h-5 w-5" />}
icon={<img src={overdueIconSrc} alt="Not Started" className="h-5 w-5" />}
/>
<StatCard
label="Pending"
value={loading ? '--' : summary.pending}
width={190}
icon={<img src={PendingIcon} alt="Pending" className="h-5 w-5" />}
icon={<img src={pendingIconSrc} alt="Pending" className="h-5 w-5" />}
/>
</div>
</div>

View File

@ -2,7 +2,8 @@ import React from 'react';
import { Link } from 'react-router-dom';
import AdminHeader from '@/components/admin/AdminHeader';
import AdminUsersContent from './configuration/AdminUsers';
import CaretUp from '@/assets/images/caret-up.svg';
const caretUpSrc = '/assets/images/caret-up.svg';
const AdminUsersPage = () => {
return (
@ -12,11 +13,11 @@ const AdminUsersPage = () => {
<nav className="mb-6 flex items-center gap-3 text-sm text-[#8F9299]">
<Link to="/admin/dashboard" className="flex items-center gap-1 text-[#232528] hover:underline">
Dashboard
<img src={CaretUp} alt="Dashboard" className="h-3 w-3" />
<img src={caretUpSrc} alt="Dashboard" className="h-3 w-3" />
</Link>
<span className="flex items-center gap-1 text-[#92722A] font-medium">
Users
<img src={CaretUp} alt="Users" className="h-3 w-3 rotate-180" />
<img src={caretUpSrc} alt="Users" className="h-3 w-3 rotate-180" />
</span>
</nav>

View File

@ -6,7 +6,8 @@ import IsicHsCodes from '@/pages/Admin/configuration/IsicHsCodes';
import UnitMaster from '@/pages/Admin/configuration/UnitMaster';
import AdminUsers from '@/pages/Admin/configuration/AdminUsers';
import CompanyProfile from '@/pages/Admin/configuration/CompanyProfile';
import CaretUp from '@/assets/images/caret-up.svg';
const caretUpSrc = '/assets/images/caret-up.svg';
const Configuration = () => {
const tabs = ['Quarterly Windows', 'HS Codes', 'Unit Master', 'Admin Users', 'Company Profile'];
@ -16,11 +17,11 @@ const Configuration = () => {
<nav className="mb-6 text-sm text-[#8F9299] flex items-center gap-3">
<Link to="/admin/dashboard" className="flex items-center gap-1 text-[#232528] hover:underline">
Dashboard
<img src={CaretUp} alt="Dashboard" className="h-3 w-3" />
<img src={caretUpSrc} alt="Dashboard" className="h-3 w-3" />
</Link>
<span className="flex items-center gap-1 text-[#92722A] font-medium">
Configuration
<img src={CaretUp} alt="Configuration" className="h-3 w-3" />
<img src={caretUpSrc} alt="Configuration" className="h-3 w-3" />
</span>
</nav>
);

View File

@ -1,16 +1,17 @@
import React from 'react';
import { Link, useNavigate, useParams } from 'react-router-dom';
import AdminHeader from '@/components/admin/AdminHeader';
import CaretUp from '@/assets/images/caret-up.svg';
import EstablishmentIcon from '@/assets/images/establishment.svg';
import EstablishmentIdIcon from '@/assets/images/establishmentid.svg';
import EmailIcon from '@/assets/images/emailid.svg';
import EmiratesIcon from '@/assets/images/emirates.svg';
import TotalEmployeesIcon from '@/assets/images/totalemployess.svg';
import MaleEmployeesIcon from '@/assets/images/maleemployes.svg';
import FemaleEmployeesIcon from '@/assets/images/femaleemployess.svg';
import UaeIcon from '@/assets/images/uae.svg';
import NonUaeIcon from '@/assets/images/nonuae.svg';
const caretUpSrc = '/assets/images/caret-up.svg';
const establishmentIconSrc = '/assets/images/Establishment.svg';
const establishmentIdIconSrc = '/assets/images/Establishmentid.svg';
const emailIconSrc = '/assets/images/emailid.svg';
const emiratesIconSrc = '/assets/images/emirates.svg';
const totalEmployeesIconSrc = '/assets/images/totalemployess.svg';
const maleEmployeesIconSrc = '/assets/images/maleemployes.svg';
const femaleEmployeesIconSrc = '/assets/images/femaleemployess.svg';
const uaeIconSrc = '/assets/images/uae.svg';
const nonUaeIconSrc = '/assets/images/nonuae.svg';
const establishmentDetails = [
{ label: 'Establishment Name', value: 'ABC Manufacturing LLC' },
@ -28,11 +29,11 @@ const employmentDetails = [
];
const employmentIcons = {
'Total Employees': TotalEmployeesIcon,
'Male Employees': MaleEmployeesIcon,
'Female Employees': FemaleEmployeesIcon,
'UAE Nationals': UaeIcon,
'Non-UAE Nationals': NonUaeIcon,
'Total Employees': totalEmployeesIconSrc,
'Male Employees': maleEmployeesIconSrc,
'Female Employees': femaleEmployeesIconSrc,
'UAE Nationals': uaeIconSrc,
'Non-UAE Nationals': nonUaeIconSrc,
};
const quarterLegend = [
@ -127,11 +128,11 @@ const ValidationReview = () => {
<nav className="flex items-center gap-2 text-sm text-[#8F9299]">
<Link to="/admin/dashboard" className="flex items-center gap-2 text-[#232528] hover:underline">
Dashboard
<img src={CaretUp} alt="Dashboard" className="h-3 w-3" />
<img src={caretUpSrc} alt="Dashboard" className="h-3 w-3" />
</Link>
<Link to="/admin/validations" className="flex items-center gap-2 text-[#232528] hover:underline">
Manage Submissions
<img src={CaretUp} alt="Manage Submissions" className="h-3 w-3" />
<img src={caretUpSrc} alt="Manage Submissions" className="h-3 w-3" />
</Link>
<span className="flex items-center gap-2 text-[#92722A] font-medium">
Submission Details
@ -162,16 +163,16 @@ const ValidationReview = () => {
{establishmentDetails.map((item) => (
<div key={item.label} className="flex items-start gap-3">
{item.label === 'Establishment Name' && (
<img src={EstablishmentIcon} alt="Establishment" className="h-5 w-5" />
<img src={establishmentIconSrc} alt="Establishment" className="h-5 w-5" />
)}
{item.label === 'Establishment ID' && (
<img src={EstablishmentIdIcon} alt="Establishment ID" className="h-5 w-5" />
<img src={establishmentIdIconSrc} alt="Establishment ID" className="h-5 w-5" />
)}
{item.label === 'Email' && (
<img src={EmailIcon} alt="Email" className="h-5 w-5" />
<img src={emailIconSrc} alt="Email" className="h-5 w-5" />
)}
{item.label === 'Emirate' && (
<img src={EmiratesIcon} alt="Emirate" className="h-5 w-5" />
<img src={emiratesIconSrc} alt="Emirate" className="h-5 w-5" />
)}
{!['Establishment Name', 'Establishment ID', 'Email', 'Emirate'].includes(item.label) && (
<span className="mt-1 h-2.5 w-2.5 rounded-full bg-[#92722A]" />

View File

@ -4,9 +4,10 @@ import AdminHeader from '@/components/admin/AdminHeader';
import Table from '@/components/common/Table';
import { SelectField } from '@/components/common/FormControls';
import { getSubmissions } from '@/services/admin/submission';
import SearchIcon from '@/assets/images/material-symbols_search-rounded.svg';
import DownloadIcon from '@/assets/images/downloadsimple.svg';
import CaretUp from '@/assets/images/caret-up.svg';
const searchIconSrc = '/assets/images/material-symbols_search-rounded.svg';
const downloadIconSrc = '/assets/images/downloadsimple.svg';
const caretUpSrc = '/assets/images/caret-up.svg';
const STATUS_VARIANTS = {
Approved: { background: '#F3FAF4', text: '#2F663C', border: '#F3FAF4' },
@ -166,7 +167,7 @@ const ManageSubmissions = () => {
</h2>
<div className="flex flex-wrap gap-3">
<div className="relative w-[320px]">
<img src={SearchIcon} alt="Search" className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4" />
<img src={searchIconSrc} alt="Search" className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4" />
<input
value={search}
onChange={(e) => setSearch(e.target.value)}
@ -189,7 +190,7 @@ const ManageSubmissions = () => {
<div className="max-w-[1280px] mx-auto px-4 py-6 flex flex-col gap-6">
<nav className="flex items-center gap-2 text-sm text-[#8F9299]">
<Link to="/admin/dashboard" className="flex items-center gap-2 text-[#232528] hover:underline">
Dashboard <img src={CaretUp} alt="Dashboard" className="h-3 w-3" />
Dashboard <img src={caretUpSrc} alt="Dashboard" className="h-3 w-3" />
</Link>
<span className="flex items-center gap-2 text-[#92722A] font-medium">Manage Submissions</span>
</nav>
@ -213,7 +214,7 @@ const ManageSubmissions = () => {
type="button"
className="ml-auto inline-flex h-10 items-center justify-center gap-3 rounded-[6px] border border-[#C3C6CB] bg-white px-5 text-sm font-medium text-[#5F646D] hover:bg-[#F7F7F7]"
>
<img src={DownloadIcon} alt="Export" className="h-4 w-4" />
<img src={downloadIconSrc} alt="Export" className="h-4 w-4" />
Export CSV
</button>
</div>

View File

@ -1,17 +1,18 @@
import React from 'react';
import Table from '@/components/common/Table';
import SearchIcon from '@/assets/images/material-symbols_search-rounded.svg';
import ExportIcon from '@/assets/images/downloadsimple.svg';
import AddIcon from '@/assets/images/ic_baseline-plus.svg';
import PencilActive from '@/assets/images/pencilsimple.svg';
import PencilInactive from '@/assets/images/pencilsimple-inactive.svg';
import TrashActive from '@/assets/images/trash - active.svg';
import TrashInactive from '@/assets/images/trash - inactive.svg';
import AdminUserIcon from '@/assets/images/usergear.svg';
import ActiveUserIcon from '@/assets/images/active-user.svg';
import InactiveUserIcon from '@/assets/images/inactive-user.svg';
import ResetPasswordIcon from '@/assets/images/hugeicons_reset-password.svg';
import ResetPasswordInactiveIcon from '@/assets/images/hugeicons_reset-password-inactive.svg';
const searchIconSrc = '/assets/images/material-symbols_search-rounded.svg';
const exportIconSrc = '/assets/images/downloadsimple.svg';
const addIconSrc = '/assets/images/ic_baseline-plus.svg';
const pencilActiveSrc = '/assets/images/pencilsimple.svg';
const pencilInactiveSrc = '/assets/images/pencilsimple-inactive.svg';
const trashActiveSrc = '/assets/images/trash - active.svg';
const trashInactiveSrc = '/assets/images/trash - inactive.svg';
const adminUserIconSrc = '/assets/images/usergear.svg';
const activeUserIconSrc = '/assets/images/active-user.svg';
const inactiveUserIconSrc = '/assets/images/inactive-user.svg';
const resetPasswordIconSrc = '/assets/images/hugeicons_reset-password.svg';
const resetPasswordInactiveIconSrc = '/assets/images/hugeicons_reset-password-inactive.svg';
const SummaryCard = ({ label, count, icon, iconBg = '#FDF7EB' }) => (
<div className="flex min-h-[96px] min-w-[220px] flex-1 items-center justify-between rounded-[16px] border border-[#E6EAF5] bg-white px-6 py-5 shadow-[0_12px_24px_rgba(15,23,42,0.06)]">
@ -78,19 +79,19 @@ const AdminUsers = () => {
{
label: 'Total Users',
count: totalUsers,
icon: AdminUserIcon,
icon: adminUserIconSrc,
iconBg: '#FDF7EB',
},
{
label: 'Active User',
count: activeUsers,
icon: ActiveUserIcon,
icon: activeUserIconSrc,
iconBg: '#E7F2FF',
},
{
label: 'Inactive User',
count: inactiveUsers,
icon: InactiveUserIcon,
icon: inactiveUserIconSrc,
iconBg: '#F5F5F7',
},
];
@ -125,18 +126,18 @@ const AdminUsers = () => {
className="w-full h-10 rounded-md border border-[#E5E7EB] pl-10 pr-4 text-sm focus:outline-none"
/>
<img
src={SearchIcon}
src={searchIconSrc}
alt="Search"
className="absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5"
/>
</div>
<div className="flex items-center gap-2 sm:justify-end">
<button className="h-9 px-3 rounded-md bg-[#F7F7F7] border border-[#C3C6CB] text-sm inline-flex items-center gap-2 cursor-pointer">
<img src={ExportIcon} alt="Export" className="h-4 w-4" />
<img src={exportIconSrc} alt="Export" className="h-4 w-4" />
<span>Export CSV</span>
</button>
<button className="h-9 px-3 rounded-md bg-[#B68A35] text-white text-sm inline-flex items-center gap-2 cursor-pointer">
<img src={AddIcon} alt="Add" className="h-4 w-4" />
<img src={addIconSrc} alt="Add" className="h-4 w-4" />
<span>Add User</span>
</button>
</div>
@ -170,7 +171,7 @@ const AdminUsers = () => {
onClick={() => handleEdit(rowIndex)}
>
<img
src={editingRow === rowIndex ? PencilActive : PencilInactive}
src={editingRow === rowIndex ? pencilActiveSrc : pencilInactiveSrc}
alt="Edit"
className="h-4 w-4"
/>
@ -183,7 +184,7 @@ const AdminUsers = () => {
onClick={() => handleDelete(rowIndex)}
>
<img
src={deletingRow === rowIndex ? TrashActive : TrashInactive}
src={deletingRow === rowIndex ? trashActiveSrc : trashInactiveSrc}
alt="Delete"
className="h-4 w-4"
/>
@ -198,7 +199,7 @@ const AdminUsers = () => {
disabled={!isActive}
>
<img
src={isActive ? ResetPasswordIcon : ResetPasswordInactiveIcon}
src={isActive ? resetPasswordIconSrc : resetPasswordInactiveIconSrc}
alt="Reset password"
className="h-4 w-4"
/>

View File

@ -10,16 +10,16 @@ import {
updateEstablishment,
deleteEstablishment,
} from '@/services/establishments/establishmentService';
import SearchIcon from '@/assets/images/material-symbols_search-rounded.svg';
import DownloadIcon from '@/assets/images/downloadsimple.svg';
import AddIcon from '@/assets/images/ic_baseline-plus.svg';
import PencilActive from '@/assets/images/pencilsimple.svg';
import PencilInactive from '@/assets/images/pencilsimple-inactive.svg';
import TrashActive from '@/assets/images/trash - active.svg';
import TrashInactive from '@/assets/images/trash - inactive.svg';
import ResetPasswordActive from '@/assets/images/hugeicons_reset-password.svg';
import ResetPasswordInactive from '@/assets/images/hugeicons_reset-password-inactive.svg';
import DeleteIcon from '@/assets/images/delete.svg';
const searchIconSrc = '/assets/images/material-symbols_search-rounded.svg';
const downloadIconSrc = '/assets/images/DownloadSimple.svg';
const addIconSrc = '/assets/images/ic_baseline-plus.svg';
const pencilActiveSrc = '/assets/images/PencilSimple.svg';
const pencilInactiveSrc = '/assets/images/PencilSimple-inactive.svg';
const trashActiveSrc = '/assets/images/Trash - active.svg';
const trashInactiveSrc = '/assets/images/Trash - Inactive.svg';
const resetPasswordActiveSrc = '/assets/images/hugeicons_reset-password.svg';
const resetPasswordInactiveSrc = '/assets/images/hugeicons_reset-password-inactive.svg';
const deleteIconSrc = '/assets/images/delete.svg';
const PASSWORD_POLICY = {
minLength: 12,
@ -1196,7 +1196,7 @@ const CompanyProfile = () => {
onClick={() => handleEdit(item.apiId ?? item.establishmentId)}
>
<img
src={isEditing ? PencilActive : PencilInactive}
src={isEditing ? pencilActiveSrc : pencilInactiveSrc}
alt="Edit"
className="h-4 w-4"
/>
@ -1205,25 +1205,26 @@ const CompanyProfile = () => {
type="button"
className="h-8 w-8 grid place-items-center rounded hover:bg-gray-50 cursor-pointer"
title="Delete"
aria-label="Delete profile"
aria-label="Delete establishment"
onClick={() => handleDelete(item.apiId ?? item.establishmentId)}
>
<img
src={isDeleting ? TrashActive : TrashInactive}
src={isDeleting ? trashActiveSrc : trashInactiveSrc}
alt="Delete"
className="h-4 w-4"
/>
</button>
<button
type="button"
className="h-8 w-8 grid place-items-center rounded hover:bg-gray-50 cursor-pointer"
title="Reset Password"
className={`h-8 w-8 grid place-items-center rounded hover:bg-gray-50 cursor-pointer ${item.userProfileEmail ? '' : 'opacity-50 cursor-not-allowed'}`}
title={item.userProfileEmail ? 'Reset establishment password' : 'No email on file'}
aria-label="Reset password"
onClick={() => handleResetPassword(item)}
disabled={!item.userProfileEmail}
>
<img
src={isEditing ? ResetPasswordActive : ResetPasswordInactive}
alt="Reset Password"
src={item.userProfileEmail ? resetPasswordActiveSrc : resetPasswordInactiveSrc}
alt="Reset password"
className="h-4 w-4"
/>
</button>
@ -2134,7 +2135,7 @@ const CompanyProfile = () => {
onChange={(event) => setSearchTerm(event.target.value)}
className="w-full h-10 rounded-md border border-[#E5E7EB] pl-10 pr-4 text-sm focus:outline-none"
/>
<img src={SearchIcon} alt="Search" className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4" />
<img src={searchIconSrc} alt="Search" className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4" />
</div>
<SelectField
label=""
@ -2168,15 +2169,15 @@ const CompanyProfile = () => {
onClick={handleExport}
disabled={isLoading}
>
<img src={DownloadIcon} alt="Export" className="h-5 w-5" />
<img src={downloadIconSrc} alt="Export" className="h-5 w-5" />
<span className="font-medium text-[#232528]">Export CSV</span>
</button>
<button
type="button"
className="h-10 px-4 rounded-[6px] bg-[#92722A] text-white text-sm inline-flex items-center gap-2 cursor-pointer"
className="h-10 px-4 rounded-[6px] bg-[#B68A35] text-white text-sm inline-flex items-center gap-2 cursor-pointer"
onClick={openAddModal}
>
<img src={AddIcon} alt="Add" className="h-5 w-5" />
<img src={addIconSrc} alt="Add" className="h-5 w-5" />
<span className="font-medium">Add Profile</span>
</button>
</div>
@ -2359,7 +2360,7 @@ const CompanyProfile = () => {
className="flex items-center justify-center"
style={{ width: '32px', height: '36px' }}
>
<img src={DeleteIcon} alt="Delete" className="h-6 w-6" />
<img src={deleteIconSrc} alt="Delete" className="h-6 w-6" />
</span>
<div className="flex-1">
<h3 className="text-[18px] font-semibold text-[#232528]">Delete Profile</h3>

View File

@ -1,16 +1,17 @@
import React from 'react';
import Table from '@/components/common/Table';
import DownloadIcon from '@/assets/images/downloadsimple.svg';
import UploadImportIcon from '@/assets/images/upload-import.svg';
import AddIcon from '@/assets/images/ic_baseline-plus.svg';
import PencilActive from '@/assets/images/pencilsimple.svg';
import PencilInactive from '@/assets/images/pencilsimple-inactive.svg';
import TrashActive from '@/assets/images/trash - active.svg';
import TrashInactive from '@/assets/images/trash - inactive.svg';
import DeleteIcon from '@/assets/images/delete.svg';
import StatusBadge from '@/components/common/StatusBadge';
import { TextField, SelectField } from '@/components/common/FormControls';
const downloadIconSrc = '/assets/images/DownloadSimple.svg';
const uploadImportIconSrc = '/assets/images/Upload-import.svg';
const addIconSrc = '/assets/images/ic_baseline-plus.svg';
const pencilActiveSrc = '/assets/images/PencilSimple.svg';
const pencilInactiveSrc = '/assets/images/PencilSimple-inactive.svg';
const trashActiveSrc = '/assets/images/Trash - active.svg';
const trashInactiveSrc = '/assets/images/Trash - Inactive.svg';
const deleteIconSrc = '/assets/images/delete.svg';
const createEmptyCodeForm = () => ({
code: '',
product: '',
@ -180,11 +181,11 @@ const IsicHsCodes = () => {
<h3 className="text-[16px] font-medium text-[#232528]">HS Codes</h3>
<div className="flex items-center gap-2">
<button className="h-10 px-4 rounded-[6px] bg-[#F7F7F7] border border-[#C3C6CB] text-sm inline-flex items-center gap-2 cursor-pointer">
<img src={UploadImportIcon} alt="Import" className="h-5 w-5" />
<img src={uploadImportIconSrc} alt="Import" className="h-5 w-5" />
<span className="font-medium text-[#232528]">Import CSV</span>
</button>
<button className="h-10 px-4 rounded-[6px] bg-[#F7F7F7] border border-[#C3C6CB] text-sm inline-flex items-center gap-2 cursor-pointer">
<img src={DownloadIcon} alt="Export" className="h-5 w-5" />
<img src={downloadIconSrc} alt="Export" className="h-5 w-5" />
<span className="font-medium text-[#232528]">Export CSV</span>
</button>
<button
@ -192,7 +193,7 @@ const IsicHsCodes = () => {
className="h-10 px-4 rounded-[6px] bg-[#92722A] text-white text-sm inline-flex items-center gap-2 cursor-pointer"
onClick={openAddModal}
>
<img src={AddIcon} alt="Add" className="h-5 w-5" />
<img src={addIconSrc} alt="Add" className="h-5 w-5" />
<span className="font-medium">Add Code</span>
</button>
</div>
@ -213,7 +214,7 @@ const IsicHsCodes = () => {
onClick={() => handleEdit(rowIndex)}
>
<img
src={editingRow === rowIndex ? PencilActive : PencilInactive}
src={editingRow === rowIndex ? pencilActiveSrc : pencilInactiveSrc}
alt="Edit"
className="h-4 w-4"
/>
@ -226,7 +227,7 @@ const IsicHsCodes = () => {
onClick={() => handleDelete(rowIndex)}
>
<img
src={deletingRow === rowIndex ? TrashActive : TrashInactive}
src={deletingRow === rowIndex ? trashActiveSrc : trashInactiveSrc}
alt="Delete"
className="h-4 w-4"
/>
@ -346,7 +347,7 @@ const IsicHsCodes = () => {
className="flex items-center justify-center"
style={{ width: '32px', height: '36px' }}
>
<img src={DeleteIcon} alt="Delete" className="h-6 w-6" />
<img src={deleteIconSrc} alt="Delete" className="h-6 w-6" />
</span>
<div className="flex-1">
<h3 className="text-[18px] font-semibold text-[#232528]">Delete HS Codes</h3>

View File

@ -2,16 +2,17 @@ import React from 'react';
import Table from '@/components/common/Table';
import { TextField, SelectField, DateField } from '@/components/common/FormControls';
import StatusBadge from '@/components/common/StatusBadge';
import DownloadIcon from '@/assets/images/downloadsimple.svg';
import AddIcon from '@/assets/images/ic_baseline-plus.svg';
import PencilActive from '@/assets/images/pencilsimple.svg';
import PencilInactive from '@/assets/images/pencilsimple-inactive.svg';
import TrashActive from '@/assets/images/trash - active.svg';
import TrashInactive from '@/assets/images/trash - inactive.svg';
import DeleteIcon from '@/assets/images/delete.svg';
import CaretDownActive from '@/assets/images/caretdown-active.svg';
import SearchIcon from '@/assets/images/material-symbols_search-rounded.svg';
import CaretDown from '@/assets/images/caretdown-black.svg';
const downloadIconSrc = '/assets/images/DownloadSimple.svg';
const addIconSrc = '/assets/images/ic_baseline-plus.svg';
const pencilActiveSrc = '/assets/images/PencilSimple.svg';
const pencilInactiveSrc = '/assets/images/PencilSimple-inactive.svg';
const trashActiveSrc = '/assets/images/Trash - active.svg';
const trashInactiveSrc = '/assets/images/Trash - Inactive.svg';
const deleteIconSrc = '/assets/images/delete.svg';
const caretDownActiveSrc = '/assets/images/caretdown-active.svg';
const searchIconSrc = '/assets/images/material-symbols_search-rounded.svg';
const caretDownSrc = '/assets/images/CaretDown-black.svg';
const createEmptyQuarterForm = () => ({
establishment: '',
@ -338,7 +339,7 @@ const QuarterlyWindows = () => {
placeholder="Search Establishment"
className="h-10 w-full rounded-[4px] border border-[#C3C6CB] pl-10 pr-3 text-sm text-[#232528] focus:outline-none"
/>
<img src={SearchIcon} alt="Search" className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5" />
<img src={searchIconSrc} alt="Search" className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5" />
</div>
<div className="relative w-full md:w-[134px]">
<select
@ -352,7 +353,7 @@ const QuarterlyWindows = () => {
</option>
))}
</select>
<img src={CaretDown} alt="Status" className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 h-5 w-5" />
<img src={caretDownSrc} alt="Status" className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 h-5 w-5" />
</div>
<button
type="button"
@ -384,7 +385,7 @@ const QuarterlyWindows = () => {
disabled={!filteredRows.length}
style={{ minWidth: '143px' }}
>
<img src={DownloadIcon} alt="Export" className="h-5 w-5" />
<img src={downloadIconSrc} alt="Export" className="h-5 w-5" />
<span className="font-medium">Export CSV</span>
</button>
<button
@ -392,7 +393,7 @@ const QuarterlyWindows = () => {
className="h-10 px-5 rounded-[6px] bg-[#92722A] text-white text-sm inline-flex items-center gap-3 cursor-pointer"
style={{ minWidth: '148px' }}
>
<img src={AddIcon} alt="Add" className="h-5 w-5" />
<img src={addIconSrc} alt="Add" className="h-5 w-5" />
<span className="font-medium">Add Quarter</span>
</button>
</div>
@ -416,7 +417,7 @@ const QuarterlyWindows = () => {
onMouseLeave={() => setHoveredEdit(null)}
>
<img
src={hoveredEdit === rowIndex || editingRow === rowIndex ? PencilActive : PencilInactive}
src={hoveredEdit === rowIndex || editingRow === rowIndex ? pencilActiveSrc : pencilInactiveSrc}
alt="Edit"
className="h-5 w-5"
/>
@ -431,7 +432,7 @@ const QuarterlyWindows = () => {
onMouseLeave={() => setHoveredDelete(null)}
>
<img
src={hoveredDelete === rowIndex || deletingRow === rowIndex ? TrashActive : TrashInactive}
src={hoveredDelete === rowIndex || deletingRow === rowIndex ? trashActiveSrc : trashInactiveSrc}
alt="Delete"
className="h-5 w-5"
/>
@ -586,7 +587,7 @@ const QuarterlyWindows = () => {
className="flex items-center justify-center"
style={{ width: '32px', height: '36px' }}
>
<img src={DeleteIcon} alt="Delete" className="h-6 w-6" />
<img src={deleteIconSrc} alt="Delete" className="h-6 w-6" />
</span>
<div className="flex-1">
<h3 className="text-[18px] font-semibold text-[#232528]">Delete Quarter</h3>

View File

@ -1,17 +1,18 @@
import React from 'react';
import Table from '@/components/common/Table';
import DownloadIcon from '@/assets/images/downloadsimple.svg';
import AddIcon from '@/assets/images/ic_baseline-plus.svg';
import PencilActive from '@/assets/images/pencilsimple.svg';
import PencilInactive from '@/assets/images/pencilsimple-inactive.svg';
import TrashActive from '@/assets/images/trash - active.svg';
import TrashInactive from '@/assets/images/trash - inactive.svg';
import DeleteIcon from '@/assets/images/delete.svg';
import StatusBadge from '@/components/common/StatusBadge';
import { TextField, SelectField } from '@/components/common/FormControls';
import CaretDownIcon from '@/assets/images/caretdown-active.svg';
import RectangleIcon from '@/assets/images/rectangle.svg';
import CheckboxIcon from '@/assets/images/checkbox.svg';
const downloadIconSrc = '/assets/images/DownloadSimple.svg';
const addIconSrc = '/assets/images/ic_baseline-plus.svg';
const pencilActiveSrc = '/assets/images/PencilSimple.svg';
const pencilInactiveSrc = '/assets/images/PencilSimple-inactive.svg';
const trashActiveSrc = '/assets/images/Trash - active.svg';
const trashInactiveSrc = '/assets/images/Trash - Inactive.svg';
const deleteIconSrc = '/assets/images/delete.svg';
const caretDownIconSrc = '/assets/images/caretdown-active.svg';
const rectangleIconSrc = '/assets/images/rectangle.svg';
const checkboxIconSrc = '/assets/images/checkbox.svg';
const createEmptyUnitForm = () => ({
unitName: '',
@ -303,7 +304,7 @@ const UnitMaster = () => {
<h3 className="text-[16px] font-medium text-[#232528]">Unit Master</h3>
<div className="flex items-center gap-2">
<button className="h-10 px-4 rounded-[6px] bg-[#F7F7F7] border border-[#C3C6CB] text-sm inline-flex items-center gap-2 cursor-pointer">
<img src={DownloadIcon} alt="Export" className="h-5 w-5" />
<img src={downloadIconSrc} alt="Export" className="h-5 w-5" />
<span className="font-medium text-[#232528]">Export CSV</span>
</button>
<button
@ -311,7 +312,7 @@ const UnitMaster = () => {
className="h-10 px-4 rounded-[6px] bg-[#92722A] text-white text-sm inline-flex items-center gap-2 cursor-pointer"
onClick={openAddModal}
>
<img src={AddIcon} alt="Add" className="h-5 w-5" />
<img src={addIconSrc} alt="Add" className="h-5 w-5" />
<span className="font-medium">Add Unit</span>
</button>
</div>
@ -332,7 +333,7 @@ const UnitMaster = () => {
onClick={() => handleEdit(rowIndex)}
>
<img
src={editingRow === rowIndex ? PencilActive : PencilInactive}
src={editingRow === rowIndex ? pencilActiveSrc : pencilInactiveSrc}
alt="Edit"
className="h-4 w-4"
/>
@ -345,7 +346,7 @@ const UnitMaster = () => {
onClick={() => handleDelete(rowIndex)}
>
<img
src={deletingRow === rowIndex ? TrashActive : TrashInactive}
src={deletingRow === rowIndex ? trashActiveSrc : trashInactiveSrc}
alt="Delete"
className="h-4 w-4"
/>
@ -423,7 +424,7 @@ const UnitMaster = () => {
: 'Select Products'}
</span>
<img
src={CaretDownIcon}
src={caretDownIconSrc}
alt="Toggle"
className={`h-4 w-4 transition-transform ${isProductDropdownOpen ? 'rotate-180' : ''}`}
/>
@ -443,7 +444,7 @@ const UnitMaster = () => {
onClick={() => handleProductToggle(option.value)}
>
<span className="relative flex h-5 w-5 items-center justify-center">
<img src={checked ? CheckboxIcon : RectangleIcon} alt="" className="h-5 w-5" />
<img src={checked ? checkboxIconSrc : rectangleIconSrc} alt="" className="h-5 w-5" />
</span>
<span className="text-[#232528]">{option.label}</span>
</button>
@ -503,7 +504,7 @@ const UnitMaster = () => {
className="flex items-center justify-center"
style={{ width: '32px', height: '36px' }}
>
<img src={DeleteIcon} alt="Delete" className="h-6 w-6" />
<img src={deleteIconSrc} alt="Delete" className="h-6 w-6" />
</span>
<div className="flex-1">
<h3 className="text-[18px] font-semibold text-[#232528]">Delete Unit</h3>

View File

@ -1,8 +1,9 @@
import React from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import Logo from '@/assets/images/fcsclogo.svg';
import apiClient from '@/services/api/apiClient';
const logoSrc = '/assets/images/FCSCLogo.svg';
const ChangePassword = () => {
const navigate = useNavigate();
const location = useLocation();
@ -118,7 +119,7 @@ const ChangePassword = () => {
<div className="w-full max-w-md">
<div className="bg-white rounded-lg shadow-sm ring-1 ring-gray-200 overflow-hidden">
<div className="px-7 py-8 border-b border-gray-200 bg-[#F2ECCF] text-center">
<img src={Logo} alt="FCSC" className="w-[188px] h-[58px] mx-auto mb-2" />
<img src={logoSrc} alt="FCSC" className="w-[188px] h-[58px] mx-auto mb-2" />
<h1 className="text-base font-semibold text-[#92722A]">Reset Password</h1>
<p className="mt-1 text-sm text-gray-600">
Enter the verification code sent to your registered email and set a new password.

View File

@ -1,8 +1,9 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';
import Logo from '@/assets/images/fcsclogo.svg';
import { requestPasswordReset } from '@/services/auth/authService.js';
const logoSrc = '/assets/images/FCSCLogo.svg';
const ForgotPassword = () => {
const navigate = useNavigate();
const [email, setEmail] = React.useState('');
@ -41,7 +42,7 @@ const ForgotPassword = () => {
<div className="w-full max-w-md">
<div className="bg-white rounded-lg shadow-sm ring-1 ring-gray-200 overflow-hidden">
<div className="px-7 py-8 border-b border-gray-200 bg-[#F2ECCF] text-center">
<img src={Logo} alt="FCSC" className="w-[188px] h-[58px] mx-auto mb-3" />
<img src={logoSrc} alt="FCSC" className="w-[188px] h-[58px] mx-auto mb-3" />
<h1 className="text-base font-semibold text-[#92722A]">Reset Password</h1>
<p className="mt-1 text-sm text-gray-600">Enter your email and we will send you instructions to reset your password.</p>
</div>

View File

@ -3,8 +3,9 @@ import { useNavigate } from 'react-router-dom';
import Table from '@/components/common/Table';
import HeaderBar from '@/components/layout/HeaderBar';
import { fetchSubmissionHistory } from '@/services/submissions/submissionService.js';
import SearchIcon from '@/assets/images/material-symbols_search-rounded.svg';
import CaretDown from '@/assets/images/caretdown.svg';
const searchIconSrc = '/assets/images/material-symbols_search-rounded.svg';
const caretDownSrc = '/assets/images/CaretDown.svg';
const Badge = ({ variant = 'default', children }) => {
const styles = {
@ -154,7 +155,7 @@ const History = () => {
placeholder="Search submissions"
className="w-full h-10 rounded-md border border-[#E5E7EB] pl-10 pr-3 text-sm focus:outline-none"
/>
<img src={SearchIcon} alt="Search" className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5" />
<img src={searchIconSrc} alt="Search" className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5" />
</div>
<div className="relative w-full md:w-40">
<select
@ -168,7 +169,7 @@ const History = () => {
</option>
))}
</select>
<img src={CaretDown} alt="Toggle" className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4" />
<img src={caretDownSrc} alt="Toggle" className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4" />
</div>
<button
type="button"

View File

@ -1,8 +1,9 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';
import Logo from '@/assets/images/fcsclogo.svg';
import { login } from '@/services/auth/authService.js';
const logoSrc = '/assets/images/FCSCLogo.svg';
const Login = () => {
const navigate = useNavigate();
const [email, setEmail] = React.useState('');
@ -199,7 +200,7 @@ const Login = () => {
<div className="w-full max-w-md">
<div className="bg-white rounded-lg shadow-sm ring-1 ring-gray-200 overflow-hidden">
<div className="px-7 py-8 border-b border-gray-200 bg-[#F2ECCF] text-center">
<img src={Logo} alt="FCSC" className="w-[188px] h-[58px] mx-auto mb-2" />
<img src={logoSrc} alt="FCSC Logo" className="mx-auto h-16 w-auto" />
<h1 className="text-base font-semibold text-[#92722A]">IPI Survey Platform</h1>
</div>

View File

@ -1,8 +1,9 @@
import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import Logo from '@/assets/images/fcsclogo.svg';
import apiClient from '@/services/api/apiClient';
const logoSrc = '/assets/images/FCSCLogo.svg';
const PublicContactForm = () => {
const navigate = useNavigate();
@ -176,7 +177,7 @@ const PublicContactForm = () => {
<div className="w-full max-w-md">
<div className="bg-white rounded-lg shadow-sm ring-1 ring-gray-200 overflow-hidden">
<div className="px-7 py-8 border-b border-gray-200 bg-[#F2ECCF] text-center">
<img src={Logo} alt="FCSC" className="w-[188px] h-[58px] mx-auto mb-2" />
<img src={logoSrc} alt="FCSC" className="w-[188px] h-[58px] mx-auto mb-2" />
<h1 className="text-base font-semibold text-[#92722A]">
{!otpStep ? "Contact Establishment Info" : "Verify Your Email"}
</h1>

View File

@ -1,12 +1,13 @@
import React from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import { submitSurvey, fetchSubmissionDetail } from '@/services/submissions/submissionService';
import { fetchEstablishmentDetail } from '@/services/establishments/establishmentService';
import { fetchEstablishmentDetail, fetchEstablishmentDashboard } from '@/services/establishments/establishmentService';
import EstablishmentInfo from '@/components/survey/EstablishmentInfo/EstablishmentInfo';
import HeaderBar from '@/components/layout/HeaderBar';
import ProductData from '@/components/survey/ProductData/ProductData';
import ReviewSubmit from '@/components/survey/ReviewSubmit/ReviewSubmit';
import CheckCircleActive from '@/assets/images/circleframe.svg';
const checkCircleActiveSrc = '/assets/images/circleframe.svg';
const createEmptyProduct = (id) => ({
id,
@ -72,6 +73,59 @@ const Survey = () => {
setStep(initialStepFromState);
}, [initialStepFromState]);
// Function to fetch current quarter and year from dashboard
const fetchCurrentQuarterAndYear = async () => {
try {
const response = await fetchEstablishmentDashboard();
const data = response?.data ?? response ?? {};
return {
quarter: data?.current_quarter || '',
year: data?.current_quarter_year?.toString() || ''
};
} catch (error) {
console.error('Error fetching current quarter and year:', error);
return { quarter: '', year: '' };
}
};
// Initialize survey with quarter and year from location state or fetch from API
React.useEffect(() => {
let cancelled = false;
const initializeSurveyData = async () => {
try {
// If quarter and year are not provided in location state, fetch them
if (!locationState?.currentQuarter || !locationState?.currentYear) {
const { quarter, year } = await fetchCurrentQuarterAndYear();
if (!cancelled) {
setEstablishmentData(prev => ({
...prev,
quarter: quarter || '',
year: year || ''
}));
}
} else if (!cancelled) {
setEstablishmentData(prev => ({
...prev,
quarter: locationState.currentQuarter || '',
year: locationState.currentYear?.toString() || ''
}));
}
} catch (error) {
console.error('Error initializing survey data:', error);
}
};
// Only initialize if we don't have the data yet
if (!establishmentData.quarter || !establishmentData.year) {
initializeSurveyData();
}
return () => {
cancelled = true;
};
}, [locationState?.currentQuarter, locationState?.currentYear]); // Only depend on these values
React.useEffect(() => {
let cancelled = false;
if (isViewMode) return () => {
@ -98,7 +152,7 @@ const Survey = () => {
industryCode: ensureString(detail?.industry_code) || prev.industryCode,
licenseNumber: ensureString(detail?.license_number) || prev.licenseNumber,
isicCode: ensureString(detail?.isic_code) || prev.isicCode,
emirate: ensureString(detail?.emirate) || prev.emirate,
emirate: ensureString(detail?.establishment_emirate?.name) || ensureString(detail?.emirate) || prev.emirate,
employeeInfo: {
...prev.employeeInfo,
emiratiMale: ensureString(detail?.emirati_male) || prev.employeeInfo.emiratiMale,
@ -312,7 +366,7 @@ const Survey = () => {
if (state === 'completed') {
return (
<span className="inline-flex items-center justify-center w-5 h-5">
<img src={CheckCircleActive} alt="Done" className="h-5 w-5" />
<img src={checkCircleActiveSrc} alt="Done" className="h-5 w-5" />
</span>
);
}
@ -324,73 +378,146 @@ const Survey = () => {
};
return (
<>
<HeaderBar />
{/* Step header bar (56px height, white bg) */}
<div className="bg-white border-b border-gray-200">
<div className="mx-auto max-w-7xl px-4 sm:px-6 md:px-8">
<div className="h-14 flex items-center">
<div className="flex flex-wrap items-center gap-3 sm:gap-6 md:gap-8">
<div className="flex items-center gap-2 text-[#1B1D21] min-w-0">
<StepBadge state={step === 1 ? 'active' : step > 1 ? 'completed' : 'idle'} number={1} />
<span className="text-sm sm:text-base font-medium">Establishment Information</span>
</div>
<div className="flex items-center gap-2 text-[#1B1D21] min-w-0">
<StepBadge state={step === 2 ? 'active' : step > 2 ? 'completed' : 'idle'} number={2} />
<span className="text-sm sm:text-base font-medium">Product Data</span>
</div>
<div className="flex items-center gap-2 text-[#1B1D21] min-w-0">
<StepBadge state={step === 3 ? 'active' : 'idle'} number={3} />
<span className="text-sm sm:text-base font-medium">Review & Submit</span>
</div>
</div>
// <div className="min-h-screen flex flex-col">
// <HeaderBar />
// {/* Step header bar */}
// <div className="bg-white border-b border-gray-200 sticky top-0 z-10">
// <div className="mx-auto max-w-7xl px-3 sm:px-6 lg:px-8">
// <div className="h-10 sm:h-12 flex items-center">
// <div className="w-full">
// <div className="grid grid-cols-3 sm:flex sm:items-center sm:justify-between">
// <div className={`flex flex-col sm:flex-row items-center gap-0.5 sm:gap-1.5 px-1 ${step >= 1 ? 'text-[#1B1D21]' : 'text-gray-400'}`}>
// <StepBadge state={step === 1 ? 'active' : step > 1 ? 'completed' : 'idle'} number={1} />
// <span className="text-[10px] sm:text-xs text-center sm:text-left leading-tight">
// {window.innerWidth < 640 ? 'Establishment' : 'Establishment Info'}
// </span>
// </div>
// <div className={`flex flex-col sm:flex-row items-center gap-0.5 sm:gap-1.5 px-1 ${step >= 2 ? 'text-[#1B1D21]' : 'text-gray-400'}`}>
// <StepBadge state={step === 2 ? 'active' : step > 2 ? 'completed' : 'idle'} number={2} />
// <span className="text-[10px] sm:text-xs leading-tight">
// {window.innerWidth < 640 ? 'Products' : 'Product Data'}
// </span>
// </div>
// <div className={`flex flex-col sm:flex-row items-center gap-0.5 sm:gap-1.5 px-1 ${step >= 3 ? 'text-[#1B1D21]' : 'text-gray-400'}`}>
// <StepBadge state={step === 3 ? 'active' : 'idle'} number={3} />
// <span className="text-[10px] sm:text-xs leading-tight">
// {window.innerWidth < 20 ? 'Review' : 'Review & Submit'}
// </span>
// </div>
// </div>
// </div>
// </div>
// </div>
// </div>
<div className="min-h-screen flex flex-col">
<HeaderBar />
{/* Step Header Bar */}
<div className="bg-white border-b border-gray-200 sticky top-0 z-10">
<div className="mx-auto max-w-7xl px-3 sm:px-6 lg:px-8">
<div className="h-12 flex items-center justify-start">
{/* Stepper container */}
<div className="flex items-center gap-6 sm:gap-10">
{/* Step 1 */}
<div
className={`flex items-center gap-1.5 ${
step >= 1 ? 'text-[#1B1D21]' : 'text-gray-400'
}`}
>
<StepBadge
state={
step === 1 ? 'active' : step > 1 ? 'completed' : 'idle'
}
number={1}
/>
<span className="text-xs sm:text-sm font-medium">
Establishment Information
</span>
</div>
{/* Step 2 */}
<div
className={`flex items-center gap-1.5 ${
step >= 2 ? 'text-[#1B1D21]' : 'text-gray-400'
}`}
>
<StepBadge
state={
step === 2 ? 'active' : step > 2 ? 'completed' : 'idle'
}
number={2}
/>
<span className="text-xs sm:text-sm font-medium">
Product Data
</span>
</div>
{/* Step 3 */}
<div
className={`flex items-center gap-1.5 ${
step >= 3 ? 'text-[#1B1D21]' : 'text-gray-400'
}`}
>
<StepBadge
state={step === 3 ? 'active' : 'idle'}
number={3}
/>
<span className="text-xs sm:text-sm font-medium">
Review & Submit
</span>
</div>
</div>
</div>
</div>
</div>
{/* </div> */}
{/* Page content */}
<div className="bg-[#F7F7F7]">
<div className="mx-auto max-w-7xl px-6 py-6">
{/* Step content */}
{step === 1 && (
<EstablishmentInfo
data={establishmentData}
loading={establishmentLoading || viewLoading}
error={establishmentError || viewError}
onChange={setEstablishmentData}
onNext={() => setStep(2)}
onBack={() => navigate('/')}
/>
)}
{step === 2 && (
<ProductData
products={productsData}
onProductsChange={setProductsData}
onBack={() => setStep(1)}
onNext={() => setStep(3)}
/>
)}
{step === 3 && (
<ReviewSubmit
establishment={establishmentData}
products={productsData}
onBack={() => setStep(2)}
onSubmit={handleSubmit}
toast={toast}
onToastClose={() => {
if (toastTimeoutRef.current) {
window.clearTimeout(toastTimeoutRef.current);
toastTimeoutRef.current = null;
}
setToast(null);
}}
isSubmitting={isSubmitting}
hasSubmitted={hasSubmitted}
/>
)}
</div>
</div>
</>
{/* Main content area */}
<main className="flex-grow bg-[#F7F7F7]">
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-4 sm:py-6">
{step === 1 && (
<EstablishmentInfo
data={establishmentData}
loading={establishmentLoading || viewLoading}
error={establishmentError || viewError}
onChange={setEstablishmentData}
onNext={() => setStep(2)}
onBack={() => navigate('/')}
/>
)}
{step === 2 && (
<ProductData
products={productsData}
onProductsChange={setProductsData}
onBack={() => setStep(1)}
onNext={() => setStep(3)}
/>
)}
{step === 3 && (
<ReviewSubmit
establishment={establishmentData}
products={productsData}
onBack={() => setStep(2)}
onSubmit={handleSubmit}
toast={toast}
onToastClose={() => {
if (toastTimeoutRef.current) {
window.clearTimeout(toastTimeoutRef.current);
toastTimeoutRef.current = null;
}
setToast(null);
}}
isSubmitting={isSubmitting}
hasSubmitted={hasSubmitted}
/>
)}
</div>
</main>
</div>
);
};