From e4b4bb5e71e1bd2eb114100f911c1c2941387dec Mon Sep 17 00:00:00 2001 From: Malini Date: Wed, 29 Oct 2025 13:59:11 +0530 Subject: [PATCH] updated code --- .../src/assets/images/CaretDown.svg | 2 +- .../src/components/common/FormControls.jsx | 2 +- .../src/components/common/Loader.jsx | 21 + .../EstablishmentInfo/EstablishmentInfo.jsx | 2 +- .../Admin/configuration/CompanyProfile.jsx | 832 ++++++++++++------ .../establishments/establishmentService.js | 34 +- .../src/services/masters/masterService.js | 62 ++ 7 files changed, 699 insertions(+), 256 deletions(-) diff --git a/ipi-survey-platform/src/assets/images/CaretDown.svg b/ipi-survey-platform/src/assets/images/CaretDown.svg index 7163c83..58ed51c 100644 --- a/ipi-survey-platform/src/assets/images/CaretDown.svg +++ b/ipi-survey-platform/src/assets/images/CaretDown.svg @@ -1,3 +1,3 @@ - + diff --git a/ipi-survey-platform/src/components/common/FormControls.jsx b/ipi-survey-platform/src/components/common/FormControls.jsx index 20f8b22..c6786f0 100644 --- a/ipi-survey-platform/src/components/common/FormControls.jsx +++ b/ipi-survey-platform/src/components/common/FormControls.jsx @@ -436,7 +436,7 @@ export const DateField = ({ wrapperStyle.width = typeof width === 'number' ? `${width}px` : width; } const inputStyle = { - ...baseInputStyle, + ...(baseInputStyles?.default || {}), ...style, color: value ? '#232528' : '#232528', borderColor: focused ? '#92722A' : '#CBA344', diff --git a/ipi-survey-platform/src/components/common/Loader.jsx b/ipi-survey-platform/src/components/common/Loader.jsx index 8d1c8b6..61b7ac5 100644 --- a/ipi-survey-platform/src/components/common/Loader.jsx +++ b/ipi-survey-platform/src/components/common/Loader.jsx @@ -1 +1,22 @@ +import React from 'react'; + +const sizeClassMap = { + sm: 'h-4 w-4 border-2', + md: 'h-6 w-6 border-2', + lg: 'h-10 w-10 border-4', +}; + +const Loader = ({ size = 'md', label = '', className = '' }) => { + const sizeClass = sizeClassMap[size] || sizeClassMap.md; + return ( +
+ + {label ? {label} : null} +
+ ); +}; + +export default Loader; diff --git a/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx b/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx index 9362384..e731de5 100644 --- a/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx +++ b/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import CaretDown from '../../../assets/images/caretdown.svg'; +import CaretDown from '../../../assets/images/CaretDown.svg'; import PrimaryButton from '../../../assets/images/primarybutton.svg'; import BackVendor from '../../../assets/images/backvector.svg'; diff --git a/ipi-survey-platform/src/pages/Admin/configuration/CompanyProfile.jsx b/ipi-survey-platform/src/pages/Admin/configuration/CompanyProfile.jsx index b5a8429..bab2a32 100644 --- a/ipi-survey-platform/src/pages/Admin/configuration/CompanyProfile.jsx +++ b/ipi-survey-platform/src/pages/Admin/configuration/CompanyProfile.jsx @@ -1,6 +1,8 @@ - import React from 'react'; +import React from 'react'; import Table from '../../../components/common/Table'; +import Loader from '../../../components/common/Loader'; import { TextField, SelectField, PhoneField } from '../../../components/common/FormControls'; +import { fetchEmirates, fetchCityTowns } from '../../../services/masters/masterService'; import { createEstablishment, fetchEstablishments, @@ -37,27 +39,6 @@ const validatePasswordComplexity = (password) => { return ''; }; -const emirateOptions = [ - { label: 'Abu Dhabi', value: 'Abu Dhabi' }, - { label: 'Dubai', value: 'Dubai' }, - { label: 'Sharjah', value: 'Sharjah' }, - { label: 'Ajman', value: 'Ajman' }, - { label: 'Umm Al Quwain', value: 'Umm Al Quwain' }, - { label: 'Ras Al Khaimah', value: 'Ras Al Khaimah' }, - { label: 'Fujairah', value: 'Fujairah' }, -]; - -const cityOptions = [ - { label: 'Abu Dhabi', value: 'Abu Dhabi' }, - { label: 'Al Ain', value: 'Al Ain' }, - { label: 'Dubai', value: 'Dubai' }, - { label: 'Sharjah', value: 'Sharjah' }, - { label: 'Ajman', value: 'Ajman' }, - { label: 'Umm Al Quwain', value: 'Umm Al Quwain' }, - { label: 'Ras Al Khaimah', value: 'Ras Al Khaimah' }, - { label: 'Fujairah', value: 'Fujairah' }, -]; - const countryCodeOptions = [{ label: '+971', value: '+971' }]; const WEBSITE_URL_PATTERN = /^(https?:\/\/)?([\w-]+\.)+[\w-]{2,}(\/[^\s]*)?$/i; @@ -108,7 +89,9 @@ const createEmptyProfile = () => ({ contactName: '', contactAddress: '', contactCityTown: '', + contactCityTownId: '', contactEmirate: '', + contactEmirateId: '', contactPostalCode: '', contactPoBox: '', contactMakaniNumber: '', @@ -123,7 +106,9 @@ const createEmptyProfile = () => ({ corporateName: '', corporateAddress: '', corporateCityTown: '', + corporateCityTownId: '', corporateEmirate: '', + corporateEmirateId: '', corporatePostalCode: '', corporatePoBox: '', corporateMakaniNumber: '', @@ -140,163 +125,164 @@ const createEmptyProfile = () => ({ employmentNonEmiratiFemale: '', employmentTotalEmployees: '', employmentTotalEmirati: '', + createdById: '', }); -const companyProfilesSeed = [ - { - ...createEmptyProfile(), - establishmentName: 'CASCADE MARINE FOODS LLC', - emirate: 'Sharjah', - isicCode: '2098', - establishmentId: 'MSCensus-23-04-001276', - products: '10', - totalEmployees: '300', - createdBy: 'Amend (Owner)', - createdOn: '18/10/2025', - lastUpdated: 'Omar', - contactName: 'CASCADE MARINE FOODS LLC', - contactEmirate: 'Sharjah', - corporateName: 'CASCADE MARINE FOODS LLC', - }, - { - ...createEmptyProfile(), - establishmentName: 'Khazan Meat Factory', - emirate: 'Sharjah', - isicCode: '1098', - establishmentId: 'MSCensus-23-05-002829', - products: '6', - totalEmployees: '100', - createdBy: 'Sara (Admin)', - createdOn: '18/10/2025', - lastUpdated: 'Abdul', - contactName: 'Khazan Meat Factory', - contactEmirate: 'Sharjah', - corporateName: 'Khazan Meat Factory', - }, - { - ...createEmptyProfile(), - establishmentName: 'Spinneys Fresh Food Industries L.L.C', - emirate: 'Dubai', - isicCode: '3198', - establishmentId: 'MSCensus-Dubai-1407', - products: '8', - totalEmployees: '40', - createdBy: 'Shaik (Admin)', - createdOn: '18/10/2025', - lastUpdated: 'Abdul', - contactName: 'Spinneys Fresh Food Industries L.L.C', - contactEmirate: 'Dubai', - corporateName: 'Spinneys Fresh Food Industries L.L.C', - }, - { - ...createEmptyProfile(), - establishmentName: 'Freshly Frozen Foods Factory L.L.C', - emirate: 'Dubai', - isicCode: '2098', - establishmentId: 'MSCensus-Dubai-906', - products: '4', - totalEmployees: '50', - createdBy: 'Abdul (Manager)', - createdOn: '18/10/2025', - lastUpdated: 'Abdul', - contactName: 'Freshly Frozen Foods Factory L.L.C', - contactEmirate: 'Dubai', - corporateName: 'Freshly Frozen Foods Factory L.L.C', - }, - { - ...createEmptyProfile(), - establishmentName: 'Sahar Food Industry (L.L.C)', - emirate: 'Dubai', - isicCode: '1095', - establishmentId: 'MSCensus-Dubai-472', - products: '8', - totalEmployees: '80', - createdBy: 'Amend (Owner)', - createdOn: '18/10/2025', - lastUpdated: 'Abdul', - contactName: 'Sahar Food Industry (L.L.C)', - contactEmirate: 'Dubai', - corporateName: 'Sahar Food Industry (L.L.C)', - }, - { - ...createEmptyProfile(), - establishmentName: 'Continental Food Processing LLC', - emirate: 'Ajman', - isicCode: '0035', - establishmentId: 'MSCensus-23-06-005496', - products: '5', - totalEmployees: '400', - createdBy: 'Sara (Admin)', - createdOn: '18/10/2025', - lastUpdated: 'Abdul', - contactName: 'Continental Food Processing LLC', - contactEmirate: 'Ajman', - corporateName: 'Continental Food Processing LLC', - }, - { - ...createEmptyProfile(), - establishmentName: 'Al Khazna Poultry Farm', - emirate: 'Abu Dhabi', - isicCode: '0986', - establishmentId: 'MSCensus-23-05-002320', - products: '7', - totalEmployees: '800', - createdBy: 'Sara (Admin)', - createdOn: '18/10/2025', - lastUpdated: 'Fathima', - contactName: 'Al Khazna Poultry Farm', - contactEmirate: 'Abu Dhabi', - corporateName: 'Al Khazna Poultry Farm', - }, - { - ...createEmptyProfile(), - establishmentName: 'Diamond Meat Processing L.L.C', - emirate: 'Abu Dhabi', - isicCode: '8766', - establishmentId: 'MSCensus-23-05-002899', - products: '7', - totalEmployees: '300', - createdBy: 'Sara (Admin)', - createdOn: '18/10/2025', - lastUpdated: 'Abdul', - contactName: 'Diamond Meat Processing L.L.C', - contactEmirate: 'Abu Dhabi', - corporateName: 'Diamond Meat Processing L.L.C', - }, - { - ...createEmptyProfile(), - establishmentName: 'Alliance Foods Co L.L.C', - emirate: 'Abu Dhabi', - isicCode: '9883', - establishmentId: 'MSCensus-Dubai-128', - products: '7', - totalEmployees: '200', - createdBy: 'Amend (Owner)', - createdOn: '18/10/2025', - lastUpdated: 'Abdul', - contactName: 'Alliance Foods Co L.L.C', - contactEmirate: 'Abu Dhabi', - corporateName: 'Alliance Foods Co L.L.C', - }, - { - ...createEmptyProfile(), - establishmentName: 'Krustasia Foods L.L.C', - emirate: 'Dubai', - isicCode: '9986', - establishmentId: 'MSCensus-23-05-002320', - products: '8', - totalEmployees: '500', - createdBy: 'Sara (Admin)', - createdOn: '18/10/2025', - lastUpdated: 'Fathima', - contactName: 'Krustasia Foods L.L.C', - contactEmirate: 'Dubai', - corporateName: 'Krustasia Foods L.L.C', - }, -]; +// const companyProfilesSeed = [ +// { +// ...createEmptyProfile(), +// establishmentName: 'CASCADE MARINE FOODS LLC', +// emirate: 'Sharjah', +// isicCode: '2098', +// establishmentId: 'MSCensus-23-04-001276', +// products: '10', +// totalEmployees: '300', +// createdBy: 'Amend (Owner)', +// createdOn: '18/10/2025', +// lastUpdated: 'Omar', +// contactName: 'CASCADE MARINE FOODS LLC', +// contactEmirate: 'Sharjah', +// corporateName: 'CASCADE MARINE FOODS LLC', +// }, +// { +// ...createEmptyProfile(), +// establishmentName: 'Khazan Meat Factory', +// emirate: 'Sharjah', +// isicCode: '1098', +// establishmentId: 'MSCensus-23-05-002829', +// products: '6', +// totalEmployees: '100', +// createdBy: 'Sara (Admin)', +// createdOn: '18/10/2025', +// lastUpdated: 'Abdul', +// contactName: 'Khazan Meat Factory', +// contactEmirate: 'Sharjah', +// corporateName: 'Khazan Meat Factory', +// }, +// { +// ...createEmptyProfile(), +// establishmentName: 'Spinneys Fresh Food Industries L.L.C', +// emirate: 'Dubai', +// isicCode: '3198', +// establishmentId: 'MSCensus-Dubai-1407', +// products: '8', +// totalEmployees: '40', +// createdBy: 'Shaik (Admin)', +// createdOn: '18/10/2025', +// lastUpdated: 'Abdul', +// contactName: 'Spinneys Fresh Food Industries L.L.C', +// contactEmirate: 'Dubai', +// corporateName: 'Spinneys Fresh Food Industries L.L.C', +// }, +// { +// ...createEmptyProfile(), +// establishmentName: 'Freshly Frozen Foods Factory L.L.C', +// emirate: 'Dubai', +// isicCode: '2098', +// establishmentId: 'MSCensus-Dubai-906', +// products: '4', +// totalEmployees: '50', +// createdBy: 'Abdul (Manager)', +// createdOn: '18/10/2025', +// lastUpdated: 'Abdul', +// contactName: 'Freshly Frozen Foods Factory L.L.C', +// contactEmirate: 'Dubai', +// corporateName: 'Freshly Frozen Foods Factory L.L.C', +// }, +// { +// ...createEmptyProfile(), +// establishmentName: 'Sahar Food Industry (L.L.C)', +// emirate: 'Dubai', +// isicCode: '1095', +// establishmentId: 'MSCensus-Dubai-472', +// products: '8', +// totalEmployees: '80', +// createdBy: 'Amend (Owner)', +// createdOn: '18/10/2025', +// lastUpdated: 'Abdul', +// contactName: 'Sahar Food Industry (L.L.C)', +// contactEmirate: 'Dubai', +// corporateName: 'Sahar Food Industry (L.L.C)', +// }, +// { +// ...createEmptyProfile(), +// establishmentName: 'Continental Food Processing LLC', +// emirate: 'Ajman', +// isicCode: '0035', +// establishmentId: 'MSCensus-23-06-005496', +// products: '5', +// totalEmployees: '400', +// createdBy: 'Sara (Admin)', +// createdOn: '18/10/2025', +// lastUpdated: 'Abdul', +// contactName: 'Continental Food Processing LLC', +// contactEmirate: 'Ajman', +// corporateName: 'Continental Food Processing LLC', +// }, +// { +// ...createEmptyProfile(), +// establishmentName: 'Al Khazna Poultry Farm', +// emirate: 'Abu Dhabi', +// isicCode: '0986', +// establishmentId: 'MSCensus-23-05-002320', +// products: '7', +// totalEmployees: '800', +// createdBy: 'Sara (Admin)', +// createdOn: '18/10/2025', +// lastUpdated: 'Fathima', +// contactName: 'Al Khazna Poultry Farm', +// contactEmirate: 'Abu Dhabi', +// corporateName: 'Al Khazna Poultry Farm', +// }, +// { +// ...createEmptyProfile(), +// establishmentName: 'Diamond Meat Processing L.L.C', +// emirate: 'Abu Dhabi', +// isicCode: '8766', +// establishmentId: 'MSCensus-23-05-002899', +// products: '7', +// totalEmployees: '300', +// createdBy: 'Sara (Admin)', +// createdOn: '18/10/2025', +// lastUpdated: 'Abdul', +// contactName: 'Diamond Meat Processing L.L.C', +// contactEmirate: 'Abu Dhabi', +// corporateName: 'Diamond Meat Processing L.L.C', +// }, +// { +// ...createEmptyProfile(), +// establishmentName: 'Alliance Foods Co L.L.C', +// emirate: 'Abu Dhabi', +// isicCode: '9883', +// establishmentId: 'MSCensus-Dubai-128', +// products: '7', +// totalEmployees: '200', +// createdBy: 'Amend (Owner)', +// createdOn: '18/10/2025', +// lastUpdated: 'Abdul', +// contactName: 'Alliance Foods Co L.L.C', +// contactEmirate: 'Abu Dhabi', +// corporateName: 'Alliance Foods Co L.L.C', +// }, +// { +// ...createEmptyProfile(), +// establishmentName: 'Krustasia Foods L.L.C', +// emirate: 'Dubai', +// isicCode: '9986', +// establishmentId: 'MSCensus-23-05-002320', +// products: '8', +// totalEmployees: '500', +// createdBy: 'Sara (Admin)', +// createdOn: '18/10/2025', +// lastUpdated: 'Fathima', +// contactName: 'Krustasia Foods L.L.C', +// contactEmirate: 'Dubai', +// }, +// ]; const CompanyProfile = () => { - const [profiles, setProfiles] = React.useState(companyProfilesSeed); + const [profiles, setProfiles] = React.useState([]); + const [isLoading, setIsLoading] = React.useState(false); const [form, setForm] = React.useState(createEmptyProfile()); const [modalMode, setModalMode] = React.useState(null); const [editingRow, setEditingRow] = React.useState(null); @@ -306,6 +292,8 @@ const CompanyProfile = () => { const [currentPage, setCurrentPage] = React.useState(1); const [pageSize, setPageSize] = React.useState(pageSizeOptions[0]); const [searchTerm, setSearchTerm] = React.useState(''); + const [selectedEmirateFilter, setSelectedEmirateFilter] = React.useState(''); + const [selectedStatusFilter, setSelectedStatusFilter] = React.useState(''); const [debouncedSearch, setDebouncedSearch] = React.useState(''); const [sortConfig, setSortConfig] = React.useState({ field: 'establishmentName', direction: 'asc' }); const [activeStep, setActiveStep] = React.useState(0); @@ -316,12 +304,29 @@ const CompanyProfile = () => { const [saveWarning, setSaveWarning] = React.useState(false); const [saveError, setSaveError] = React.useState(''); const [toast, setToast] = React.useState(null); + const [emirateOptions, setEmirateOptions] = React.useState([]); + const [emirateLookup, setEmirateLookup] = React.useState({}); + const [contactCityOptions, setContactCityOptions] = React.useState([]); + const [corporateCityOptions, setCorporateCityOptions] = React.useState([]); const [fieldErrors, setFieldErrors] = React.useState({}); const [isDirty, setIsDirty] = React.useState(false); const initialSnapshotRef = React.useRef(createEmptyProfile()); const toastTimeoutRef = React.useRef(null); const [isDeletingApi, setIsDeletingApi] = React.useState(false); + const showToast = React.useCallback((type, message) => { + if (!message) return; + if (toastTimeoutRef.current) { + window.clearTimeout(toastTimeoutRef.current); + toastTimeoutRef.current = null; + } + setToast({ type, message }); + toastTimeoutRef.current = window.setTimeout(() => { + setToast(null); + toastTimeoutRef.current = null; + }, 3000); + }, []); + const computeEmploymentTotals = React.useCallback((nextForm) => { const emiratiMale = Number(nextForm.employmentEmiratiMale) || 0; const emiratiFemale = Number(nextForm.employmentEmiratiFemale) || 0; @@ -562,16 +567,6 @@ const CompanyProfile = () => { required error={fieldErrors.contactAddress} /> - { required error={fieldErrors.contactEmirate} /> + { error={fieldErrors.corporateAddress} readOnly={form.corporateSameAs} /> - { error={fieldErrors.corporateEmirate} readOnly={form.corporateSameAs} /> + + { 'Created By', renderSortableHeader('Created on', 'createdOn'), renderSortableHeader('Last Updated', 'lastUpdated'), + 'Status', 'Actions', ]; @@ -999,7 +1006,8 @@ const CompanyProfile = () => { base[7] = 152; // Created By base[8] = 148; // Created on base[9] = 136; // Last Updated - base[10] = 119; // Actions + base[10] = 120; // Status + base[11] = 119; // Actions return base; }, [headers.length]); @@ -1008,7 +1016,9 @@ const CompanyProfile = () => { contactName: 'corporateName', contactAddress: 'corporateAddress', contactCityTown: 'corporateCityTown', + contactCityTownId: 'corporateCityTownId', contactEmirate: 'corporateEmirate', + contactEmirateId: 'corporateEmirateId', contactPostalCode: 'corporatePostalCode', contactPoBox: 'corporatePoBox', contactMakaniNumber: 'corporateMakaniNumber', @@ -1133,6 +1143,24 @@ const CompanyProfile = () => { return items; }, [filteredProfiles, sortConfig]); + const renderStatusBadge = React.useCallback((status) => { + const normalized = typeof status === 'string' ? status.trim().toLowerCase() : ''; + const isActiveStatus = normalized !== 'inactive'; + const label = isActiveStatus ? 'Active' : 'Inactive'; + const baseClasses = + 'inline-flex items-center justify-center px-3 py-1 text-xs font-medium rounded-md border'; + const activeClasses = 'text-[#1A7F37] bg-[#ECFDF3] border-[#ABEFC6]'; + const inactiveClasses = 'text-[#344054] bg-[#F8F9FC] border-[#D0D5DD]'; + return ( + + {label} + + ); + }, []); + const displayedRows = sortedProfiles.map((item) => { const isEditing = editingRow !== null && profiles[editingRow]?.establishmentId === item.establishmentId; @@ -1150,6 +1178,7 @@ const CompanyProfile = () => { item.createdBy, item.createdOn, item.lastUpdated, + renderStatusBadge(item.status), (
- @@ -1851,19 +2175,25 @@ const CompanyProfile = () => { - + {isLoading ? ( +
+ +
+ ) : ( +
+ )} {modalMode && (
diff --git a/ipi-survey-platform/src/services/establishments/establishmentService.js b/ipi-survey-platform/src/services/establishments/establishmentService.js index dc15d1c..a4adc76 100644 --- a/ipi-survey-platform/src/services/establishments/establishmentService.js +++ b/ipi-survey-platform/src/services/establishments/establishmentService.js @@ -4,8 +4,38 @@ import resolveEstablishmentId from '../utils/establishment.js'; const dashboardEndpoint = '/establishment_dashboard'; const establishmentsEndpoint = '/establishments'; -export const fetchEstablishments = async (config = {}) => { - const response = await getRequest(establishmentsEndpoint, config); +const buildEstablishmentQueryParams = (params = {}) => { + const { + page, + limit, + search, + emirateId, + isicCode, + status, + sortBy, + sortOrder, + export: exportFormat, + } = params; + + const query = {}; + if (page !== undefined) query.page = page; + if (limit !== undefined) query.limit = limit; + if (search) query.search = search; + if (emirateId) query.emirate_id = emirateId; + if (isicCode) query.isic_code = isicCode; + if (status) query.status = status; + if (sortBy) query.sort_by = sortBy; + if (sortOrder) query.sort_order = sortOrder; + if (exportFormat) query.export = exportFormat; + return query; +}; + +export const fetchEstablishments = async ({ params, ...config } = {}) => { + const query = buildEstablishmentQueryParams(params); + const response = await getRequest(establishmentsEndpoint, { + ...config, + params: { ...(config.params || {}), ...query }, + }); return response.data; }; diff --git a/ipi-survey-platform/src/services/masters/masterService.js b/ipi-survey-platform/src/services/masters/masterService.js index f60f5df..944cdde 100644 --- a/ipi-survey-platform/src/services/masters/masterService.js +++ b/ipi-survey-platform/src/services/masters/masterService.js @@ -5,6 +5,8 @@ const endpoints = { zeroTargetReasons: '/zero_target_reason', products: '/products', units: '/unit_master', + emirates: '/emirates', + cityTowns: '/city-towns', }; const extractReasons = (payload) => { @@ -72,6 +74,38 @@ const toUnitOption = (item) => { return null; }; +const toEmirateOption = (item) => { + if (item === undefined || item === null) return null; + if (typeof item === 'string' || typeof item === 'number') { + const value = toStringOrNull(item); + return value ? { label: value, value } : null; + } + if (typeof item === 'object') { + const id = toStringOrNull(item.id ?? item.value ?? item.code); + const name = toStringOrNull(item.name ?? item.label ?? item.description); + const finalLabel = name ?? id; + if (!finalLabel) return null; + return { label: finalLabel, value: id ?? finalLabel, raw: item }; + } + return null; +}; + +const toCityOption = (item) => { + if (item === undefined || item === null) return null; + if (typeof item === 'string' || typeof item === 'number') { + const value = toStringOrNull(item); + return value ? { label: value, value } : null; + } + if (typeof item === 'object') { + const id = toStringOrNull(item.id ?? item.value ?? item.code); + const name = toStringOrNull(item.name ?? item.label ?? item.description); + const finalLabel = name ?? id; + if (!finalLabel) return null; + return { label: finalLabel, value: id ?? finalLabel, raw: item }; + } + return null; +}; + export const getVariationReasons = async (config = {}) => { const response = await getRequest(endpoints.variationReasons, config); return response.data; @@ -116,6 +150,30 @@ export const fetchUnits = async ({ signal } = {}) => { return list.map(toUnitOption).filter(Boolean); }; +export const getEmirates = async (config = {}) => { + const response = await getRequest(endpoints.emirates, config); + return response.data; +}; + +export const fetchEmirates = async ({ signal } = {}) => { + const data = await getEmirates({ signal }); + const list = extractReasons(data); + return list.map(toEmirateOption).filter(Boolean); +}; + +export const getCityTowns = async (emirateId, config = {}) => { + const params = { ...(config.params || {}), emirate_id: emirateId }; + const response = await getRequest(endpoints.cityTowns, { ...config, params }); + return response.data; +}; + +export const fetchCityTowns = async ({ emirateId, signal } = {}) => { + if (!emirateId) return []; + const data = await getCityTowns(emirateId, { signal }); + const list = extractReasons(data); + return list.map(toCityOption).filter(Boolean); +}; + export default { getVariationReasons, fetchVariationReasons, @@ -125,4 +183,8 @@ export default { fetchProducts, getUnits, fetchUnits, + getEmirates, + fetchEmirates, + getCityTowns, + fetchCityTowns, };