changed images to public folder
|
Before Width: | Height: | Size: 964 B After Width: | Height: | Size: 964 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 957 B After Width: | Height: | Size: 957 B |
|
Before Width: | Height: | Size: 967 B After Width: | Height: | Size: 967 B |
|
Before Width: | Height: | Size: 775 B After Width: | Height: | Size: 775 B |
|
Before Width: | Height: | Size: 970 B After Width: | Height: | Size: 970 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 790 B After Width: | Height: | Size: 790 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 370 B After Width: | Height: | Size: 370 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 1013 B After Width: | Height: | Size: 1013 B |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 189 B After Width: | Height: | Size: 189 B |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 392 B After Width: | Height: | Size: 392 B |
|
Before Width: | Height: | Size: 967 B After Width: | Height: | Size: 967 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 272 B After Width: | Height: | Size: 272 B |
|
Before Width: | Height: | Size: 731 B After Width: | Height: | Size: 731 B |
|
Before Width: | Height: | Size: 936 B After Width: | Height: | Size: 936 B |
|
Before Width: | Height: | Size: 766 B After Width: | Height: | Size: 766 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 242 B After Width: | Height: | Size: 242 B |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
@ -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 |
|
Before Width: | Height: | Size: 852 B After Width: | Height: | Size: 852 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
@ -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 |
|
Before Width: | Height: | Size: 1013 B After Width: | Height: | Size: 1013 B |
|
Before Width: | Height: | Size: 769 B After Width: | Height: | Size: 769 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1013 B After Width: | Height: | Size: 1013 B |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
@ -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>
|
||||
)}
|
||||
|
||||
@ -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"
|
||||
/>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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"
|
||||
/>
|
||||
|
||||
@ -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 || '—';
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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>
|
||||
);
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
|
||||
@ -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>
|
||||
);
|
||||
|
||||
@ -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]" />
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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"
|
||||
/>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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>
|
||||
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||