changes in inline styles

This commit is contained in:
Malini 2026-01-23 11:26:55 +05:30
parent fce67c8e02
commit 1796b3aea4
18 changed files with 287 additions and 358 deletions

View File

@ -1,16 +1,13 @@
import React from 'react'; import React from 'react';
const StatCard = ({ icon = null, label, value, tooltipText, width = 200.4 }) => { const StatCard = ({ icon = null, label, value, tooltipText, width = 200.4 }) => {
const resolvedWidth = typeof width === 'number' ? `${width}px` : width;
return ( return (
<div <div
className="relative group flex flex-col items-center justify-center rounded-[8px] border border-[#E3E5E8] bg-white px-5 py-5 shadow-[0_8px_20px_rgba(42,47,66,0.06)]" className={`relative group flex flex-col items-center justify-center rounded-lg border border-gray-200 bg-white px-5 py-5 shadow-sm ${typeof width === 'number' ? `w-[${width}px]` : `w-${width}`} min-h-[120px]`}
style={{ width: resolvedWidth, minHeight: '120px' }}
> >
<div className="flex items-center justify-center gap-2 whitespace-nowrap"> <div className="flex items-center justify-center gap-2 whitespace-nowrap">
{icon && <div className="flex items-center justify-center w-5 h-5">{icon}</div>} {icon && <div className="flex items-center justify-center w-5 h-5">{icon}</div>}
<span className="text-[15px] font-medium text-[#5F646D] leading-[22px] text-center truncate"> <span className="text-sm font-medium text-gray-600 leading-5 text-center truncate">
{label} {label}
</span> </span>
</div> </div>

View File

@ -324,10 +324,9 @@ const tableRows = filtered.map((item) => [
return ( return (
<div <div
className="border border-[#E5E7EB] bg-white shadow-[0_8px_16px_rgba(15,23,42,0.05)] rounded-[6px] w-full overflow-hidden py-2" className={`border border-gray-200 bg-white shadow-sm rounded-md w-full overflow-hidden py-2 ${
style={{ filtered.length === 0 || loading ? 'min-h-auto' : 'min-h-[200px]'
minHeight: filtered.length === 0 || loading ? 'auto' : '200px', }`}
}}
> >
<div className="flex justify-between items-center px-4 pr-6 py-2 mt-3"> <div className="flex justify-between items-center px-4 pr-6 py-2 mt-3">
<h2 className="text-[18px] leading-[28px] font-medium text-[#232528]"> <h2 className="text-[18px] leading-[28px] font-medium text-[#232528]">

View File

@ -13,19 +13,10 @@ const CustomToast = ({ message, type = 'success', onClose, duration = 4000 }) =>
: 'bg-red-50 border border-red-500 text-red-700'; : 'bg-red-50 border border-red-500 text-red-700';
const Icon = isSuccess ? CheckCircle : XCircle; const Icon = isSuccess ? CheckCircle : XCircle;
// In CustomToast.jsx return (
// return ( <div
// In CustomToast.jsx className={`fixed top-4 left-1/2 -translate-x-1/2 flex items-start gap-3 p-4 rounded-lg shadow-md ${bgColor} z-[10000] min-w-[320px] max-w-[90%] animate-[fadeIn_0.3s_ease-out]`}
return ( >
<div
className={`fixed top-4 left-1/2 -translate-x-1/2 flex items-start gap-3 p-4 rounded-lg shadow-md ${bgColor} animate-fade-in`}
style={{
zIndex: 10000,
minWidth: '320px',
maxWidth: '90%',
animation: 'fadeIn 0.3s ease-out',
}}
>
<Icon className="w-5 h-5 mt-0.5 flex-shrink-0" /> <Icon className="w-5 h-5 mt-0.5 flex-shrink-0" />
<div className="flex-1 text-sm font-medium">{message}</div> <div className="flex-1 text-sm font-medium">{message}</div>
<button <button

View File

@ -363,14 +363,14 @@ export const SelectField = ({
} }
}; };
return ( return (
<div style={wrapperStyle} className="w-full"> <div className={`w-full ${wrapperStyle ? '' : ''}`} style={wrapperStyle || {}}>
{label && ( {label && (
<label htmlFor={id || name} className="block text-[14px] leading-[20px] font-medium text-[#232528] mb-1"> <label htmlFor={id || name} className="block text-sm font-medium text-gray-900 mb-1">
{label} {label}
{required && <span className="text-[#B91C1C] ml-1">*</span>} {required && <span className="text-red-700 ml-1">*</span>}
</label> </label>
)} )}
<div className="relative" style={{ width: '100%' }}> <div className="relative w-full">
<select <select
id={id || name} id={id || name}
name={name} name={name}

View File

@ -139,8 +139,12 @@ const Table = ({
<div className={`overflow-hidden rounded-lg bg-white ${className}`}> <div className={`overflow-hidden rounded-lg bg-white ${className}`}>
{beforeHeader} {beforeHeader}
<div <div
className={`${disableHorizontalScroll ? 'overflow-x-hidden' : 'overflow-x-auto'} px-6 pt-2 pb-6`} className={`
style={disableHorizontalScroll ? undefined : { scrollbarWidth: 'thin' }} ${disableHorizontalScroll
? 'overflow-x-hidden'
: 'overflow-x-auto scrollbar-thin'}
px-6 pt-2 pb-6
`}
> >
<table <table
className={`min-w-[720px] w-full table-fixed rounded-2xl px-4 py-4${ className={`min-w-[720px] w-full table-fixed rounded-2xl px-4 py-4${
@ -190,13 +194,9 @@ const Table = ({
return ( return (
<td <td
key={ci} key={ci}
className={`px-6 py-2 text-sm text-[#232528] border-b border-[#C3C6CB] align-top ${getCellClass ? getCellClass(ri, ci) : ''}`} className={`px-6 py-2 text-sm text-gray-900 border-b border-gray-300 align-top whitespace-normal break-words ${getCellClass ? getCellClass(ri, ci) : ''} ${
style={{ widthValue ? `w-[${typeof widthValue === 'number' ? `${widthValue}px` : widthValue}] min-w-[${typeof widthValue === 'number' ? `${widthValue}px` : widthValue}]` : 'max-w-[200px]'
...widthStyle, }`}
whiteSpace: 'normal',
wordWrap: 'break-word',
maxWidth: widthValue || '200px'
}}
> >
{renderCell ? renderCell(cell, ri, ci) : cell} {renderCell ? renderCell(cell, ri, ci) : cell}
</td> </td>

View File

@ -329,14 +329,11 @@ const Card = ({ children }) => (
</div> </div>
); );
const SectionBox = ({ title, children, badgeBg = '#ffffff', badgeText = '#374151' }) => ( const SectionBox = ({ title, children, badgeBg = 'bg-white', badgeText = 'text-gray-700' }) => (
<div className="rounded-md ring-1 ring-gray-200 bg-white"> <div className="rounded-md ring-1 ring-gray-200 bg-white">
<div className="p-5"> <div className="p-5">
<div className="font-medium mb-2"> <div className="font-medium mb-2">
<span <span className={`inline-flex items-center rounded text-sm font-medium px-2 py-1 ${badgeBg} ${badgeText}`}>
className="inline-flex items-center rounded text-sm font-medium px-2 py-1"
style={{ backgroundColor: badgeBg, color: badgeText }}
>
{title} {title}
</span> </span>
</div> </div>
@ -1501,7 +1498,7 @@ const location = useLocation();
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">
{quarterPeriods?.previous_month?.previous_period_one } Qty {quarterPeriods?.previous_month?.previous_period_one } Qty
</label> </label>
<div className="flex items-center h-10 px-3 py-2 text-sm text-gray-700 rounded-md w-24" style={{ border: '1px solid #E6D7A2' }}> <div className="flex items-center h-10 px-3 py-2 text-sm text-gray-700 rounded-md w-24 border border-amber-200">
{p.octQuantity || '0'} {p.octQuantity || '0'}
</div> </div>
</div> </div>
@ -1509,7 +1506,7 @@ const location = useLocation();
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">
{quarterPeriods?.previous_month?.previous_period_two } Qty {quarterPeriods?.previous_month?.previous_period_two } Qty
</label> </label>
<div className="flex items-center h-10 px-3 py-2 text-sm text-gray-700 rounded-md w-24" style={{ border: '1px solid #E6D7A2' }}> <div className="flex items-center h-10 px-3 py-2 text-sm text-gray-700 rounded-md w-24 border border-amber-200">
{p.novQuantity || '0'} {p.novQuantity || '0'}
</div> </div>
</div> </div>
@ -1517,7 +1514,7 @@ const location = useLocation();
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">
{quarterPeriods?.previous_month?.previous_period_three} Qty {quarterPeriods?.previous_month?.previous_period_three} Qty
</label> </label>
<div className="flex items-center h-10 px-3 py-2 text-sm text-gray-700 rounded-md w-24" style={{ border: '1px solid #E6D7A2' }}> <div className="flex items-center h-10 px-3 py-2 text-sm text-gray-700 rounded-md w-24 border border-amber-200">
{p.decQuantity || '0'} {p.decQuantity || '0'}
</div> </div>
</div> </div>
@ -1527,7 +1524,7 @@ const location = useLocation();
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">
{quarterPeriods?.previous_month?.previous_period_one } Cost (<img src={uae_currency} alt="AED" className="inline-block w-5 h-5 -mt-0.5 -mb-2.4 opacity-100 -mr-1 -ml-1" />) {quarterPeriods?.previous_month?.previous_period_one } Cost (<img src={uae_currency} alt="AED" className="inline-block w-5 h-5 -mt-0.5 -mb-2.4 opacity-100 -mr-1 -ml-1" />)
</label> </label>
<div className="flex items-center h-10 px-3 py-2 text-sm text-gray-700 rounded-md w-24" style={{ border: '1px solid #E6D7A2' }}> <div className="flex items-center h-10 px-3 py-2 text-sm text-gray-700 rounded-md w-24 border border-amber-200">
{p.octCost || '0'} {p.octCost || '0'}
</div> </div>
</div> </div>
@ -1535,7 +1532,7 @@ const location = useLocation();
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">
{quarterPeriods?.previous_month?.previous_period_two } Cost (<img src={uae_currency} alt="AED" className="inline-block w-5 h-5 -mt-0.5 -mb-2.4 opacity-100 -mr-1 -ml-1" />) {quarterPeriods?.previous_month?.previous_period_two } Cost (<img src={uae_currency} alt="AED" className="inline-block w-5 h-5 -mt-0.5 -mb-2.4 opacity-100 -mr-1 -ml-1" />)
</label> </label>
<div className="flex items-center h-10 px-3 py-2 text-sm text-gray-700 rounded-md w-24" style={{ border: '1px solid #E6D7A2' }}> <div className="flex items-center h-10 px-3 py-2 text-sm text-gray-700 rounded-md w-24 border border-amber-200">
{p.novCost || '0'} {p.novCost || '0'}
</div> </div>
</div> </div>
@ -1543,7 +1540,7 @@ const location = useLocation();
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">
{quarterPeriods?.previous_month?.previous_period_three } Cost (<img src={uae_currency} alt="AED" className="inline-block w-5 h-5 -mt-0.5 -mb-2.4 opacity-100 -mr-1 -ml-1" />) {quarterPeriods?.previous_month?.previous_period_three } Cost (<img src={uae_currency} alt="AED" className="inline-block w-5 h-5 -mt-0.5 -mb-2.4 opacity-100 -mr-1 -ml-1" />)
</label> </label>
<div className="flex items-center h-10 px-3 py-2 text-sm text-gray-700 rounded-md w-24" style={{ border: '1px solid #E6D7A2' }}> <div className="flex items-center h-10 px-3 py-2 text-sm text-gray-700 rounded-md w-24 border border-amber-200">
{p.decCost || '0'} {p.decCost || '0'}
</div> </div>
</div> </div>

View File

@ -147,35 +147,40 @@ const AdminDashboard = () => {
<StatCard <StatCard
label="Total Establishments" label="Total Establishments"
value={loading ? '--' : summary.total_establishments} value={loading ? '--' : summary.total_establishments}
width={290} width={200}
className="flex-1 min-w-0"
icon={<img src={surveyIconSrc} alt="Total Establishments" className="h-5 w-5" />} icon={<img src={surveyIconSrc} alt="Total Establishments" className="h-5 w-5" />}
tooltipText="Total establishments enrolled in the survey for selected quarter." tooltipText="Total establishments enrolled in the survey for selected quarter."
/> />
<StatCard <StatCard
label="Submitted" label="Submitted"
value={loading ? '--' : summary.submitted} value={loading ? '--' : summary.submitted}
width={190} width={200}
className="flex-1 min-w-0"
icon={<img src={submittedIconSrc} alt="Submitted" className="h-5 w-5" />} icon={<img src={submittedIconSrc} alt="Submitted" className="h-5 w-5" />}
tooltipText="Establishments that have submitted all products for this quarter." tooltipText="Establishments that have submitted all products for this quarter."
/> />
<StatCard <StatCard
label="Approved" label="Approved"
value={loading ? '--' : summary.approved} value={loading ? '--' : summary.approved}
width={190} width={200}
className="flex-1 min-w-0"
icon={<img src={approvedIconSrc} alt="Approved" className="h-5 w-5" />} icon={<img src={approvedIconSrc} alt="Approved" className="h-5 w-5" />}
tooltipText="Submissions fully validated and approved." tooltipText="Submissions fully validated and approved."
/> />
<StatCard <StatCard
label="Rejected" label="Rejected"
value={loading ? '--' : summary.rejected} value={loading ? '--' : summary.rejected}
width={190} width={200}
className="flex-1 min-w-0"
icon={<img src={rejectedIconSrc} alt="Rejected" className="h-5 w-5" />} icon={<img src={rejectedIconSrc} alt="Rejected" className="h-5 w-5" />}
tooltipText="Submissions rejected and pending resubmission." tooltipText="Submissions rejected and pending resubmission."
/> />
<StatCard <StatCard
label="Not Started" label="Not Started"
value={loading ? '--' : summary.not_started} value={loading ? '--' : summary.not_started}
width={190} width={200}
className="flex-1 min-w-0"
icon={<img src={overdueIconSrc} alt="Not Started" className="h-5 w-5" />} icon={<img src={overdueIconSrc} alt="Not Started" className="h-5 w-5" />}
tooltipText="Establishments past submission deadline." tooltipText="Establishments past submission deadline."
/> />
@ -186,7 +191,8 @@ const AdminDashboard = () => {
(selectedQuarter === 'All' || selectedYear === 'All') ? 'NA' : (selectedQuarter === 'All' || selectedYear === 'All') ? 'NA' :
(quarterlyWindows.end_date ? new Date(quarterlyWindows.end_date).toLocaleDateString('en-GB') : '--')} (quarterlyWindows.end_date ? new Date(quarterlyWindows.end_date).toLocaleDateString('en-GB') : '--')}
valueClassName="text-sm" valueClassName="text-sm"
width={190} width={200}
className="flex-1 min-w-0"
icon={<img src={dueDateIconSrc} alt="Due Date" className="h-5 w-5" />} icon={<img src={dueDateIconSrc} alt="Due Date" className="h-5 w-5" />}
tooltipText={selectedQuarter === 'All' || selectedYear === 'All' ? tooltipText={selectedQuarter === 'All' || selectedYear === 'All' ?
"Due date is not applicable when viewing all quarters or years" : "Due date is not applicable when viewing all quarters or years" :

View File

@ -11,6 +11,15 @@ const caretUpSrc = '/assets/images/caret-up.svg';
import apiClient from '@/services/api/apiClient'; import apiClient from '@/services/api/apiClient';
import { putRequest } from '@/services/api/CommonService'; import { putRequest } from '@/services/api/CommonService';
const STATUS_CLASSES = {
Approved: 'bg-green-50 text-green-800 border-green-50',
Pending: 'bg-blue-50 text-blue-600 border-blue-50',
Rejected: 'bg-red-50 text-red-700 border-red-50',
Resubmitted: 'bg-amber-50 text-amber-800 border-amber-200',
Submitted: 'bg-blue-50 text-blue-600 border-blue-50',
default: 'bg-gray-50 text-gray-600 border-gray-200'
};
const STATUS_VARIANTS = { const STATUS_VARIANTS = {
Approved: { background: '#F3FAF4', text: '#2F663C', border: '#F3FAF4' }, Approved: { background: '#F3FAF4', text: '#2F663C', border: '#F3FAF4' },
Pending: { background: '#E7F5FF', text: '#286CFF', border: '#E7F5FF' }, Pending: { background: '#E7F5FF', text: '#286CFF', border: '#E7F5FF' },
@ -45,15 +54,11 @@ const formatDateTime = (value) => {
}); });
return formatted; return formatted;
}; };
const Badge = ({ children, status }) => {
const variant = STATUS_VARIANTS[status] || { background: '#F2F4F7', text: '#475467', border: '#EAECF0' };
return (
<span
// className={`inline-flex h-6 min-w-[67px] items-center justify-center rounded px-2 text-xs font-medium border ${variant.background} ${variant.text} ${variant.border}`}
className="inline-flex h-6 min-w-[67px] items-center justify-center rounded px-2 text-xs font-medium"
style={{ background: variant.background, color: variant.text, border: `1px solid ${variant.border}` }}
> const Badge = ({ children, status }) => {
const variantClass = STATUS_CLASSES[status] || STATUS_CLASSES.default;
return (
<span className={`inline-flex h-6 min-w-[67px] items-center justify-center rounded px-2 text-xs font-medium border ${variantClass}`}>
{children} {children}
</span> </span>
); );

View File

@ -35,8 +35,7 @@ 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)]"> <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)]">
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<span <span
className="flex h-12 w-12 items-center justify-center rounded-full" className={`flex h-12 w-12 items-center justify-center rounded-full ${iconBg ? `bg-[${iconBg}]` : 'bg-[#FDF7EB]'}`}
style={{ backgroundColor: iconBg }}
> >
{icon && <img src={icon} alt={label} className="h-6 w-6" />} {icon && <img src={icon} alt={label} className="h-6 w-6" />}
</span> </span>

View File

@ -989,10 +989,7 @@ const CompanyProfile = () => {
<h4 className="text-[16px] font-semibold text-[#232528]">Details</h4> <h4 className="text-[16px] font-semibold text-[#232528]">Details</h4>
{/* Responsive grid */} {/* Responsive grid */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-2 w-full overflow-x-hidden" style={{ <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-2 w-full overflow-x-hidden [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]">
msOverflowStyle: 'none', /* IE and Edge */
scrollbarWidth: 'none', /* Firefox */
}}>
<div> <div>
<TextField <TextField
label="Permanent Factory Code" label="Permanent Factory Code"
@ -1043,7 +1040,7 @@ const CompanyProfile = () => {
</div> </div>
</div> </div>
<div className="mt-4 w-full" style={{ width: 'calc(100% - 1px)' }}> <div className="mt-4 w-[calc(100%-1px)]">
<TextField <TextField
label="Description" label="Description"
value={form.industryDescription} value={form.industryDescription}
@ -1055,7 +1052,7 @@ const CompanyProfile = () => {
</div> </div>
{form.industryCodeProduction && form.industryCodeBusiness != null && form.industryCodeBusiness !== form.industryCodeProduction && ( {form.industryCodeProduction && form.industryCodeBusiness != null && form.industryCodeBusiness !== form.industryCodeProduction && (
<div className="mt-4 w-full" style={{ width: 'calc(100% - 1px)' }}> <div className="mt-4 w-[calc(100%-1px)]">
<TextField <TextField
label="Remarks" label="Remarks"
value={form.industryCodeMismatchRemarks} value={form.industryCodeMismatchRemarks}
@ -3376,17 +3373,7 @@ const handleImport = async () => {
<div className="fixed inset-0 z-50"> <div className="fixed inset-0 z-50">
<div className="absolute inset-0 bg-black/40" onClick={closeModal} /> <div className="absolute inset-0 bg-black/40" onClick={closeModal} />
<div <div
className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-[8px] bg-white" className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-lg bg-white w-[1300px] max-w-[calc(100vw-32px)] max-h-[94vh] shadow-xl border border-slate-200 overflow-hidden flex flex-col"
style={{
width: '1300px',
maxWidth: 'calc(100vw - 32px)',
maxHeight: '94vh',
boxShadow: '0 24px 40px rgba(27, 29, 33, 0.16)',
border: '1px solid #CBD5E1',
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
}}
> >
<div className="flex items-center justify-between px-6 py-4 border-b border-[#F1F2F4]"> <div className="flex items-center justify-between px-6 py-4 border-b border-[#F1F2F4]">
<h3 className="text-[18px] font-medium text-[#232528]"> <h3 className="text-[18px] font-medium text-[#232528]">
@ -3406,7 +3393,7 @@ const handleImport = async () => {
</div> </div>
<div className="flex flex-1 overflow-hidden"> <div className="flex flex-1 overflow-hidden">
<aside className="w-64 bg-[#F9FAFB] border-r border-[#E5E7EB] overflow-y-auto" style={{ maxHeight: 'calc(94vh - 120px)' }}> <aside className="w-64 bg-[#F9FAFB] border-r border-[#E5E7EB] overflow-y-auto max-h-[calc(94vh-120px)]">
<ol className="py-6 px-4 space-y-2"> <ol className="py-6 px-4 space-y-2">
{formSteps.map((step, index) => { {formSteps.map((step, index) => {
const isActive = index === activeStep; const isActive = index === activeStep;
@ -3447,7 +3434,7 @@ const handleImport = async () => {
})} })}
</ol> </ol>
</aside> </aside>
<div className="flex-1 overflow-y-auto" style={{ maxHeight: 'calc(94vh - 120px)' }}> <div className="flex-1 overflow-y-auto max-h-[calc(94vh-120px)]">
<div className="px-6 py-6"> <div className="px-6 py-6">
{renderStepContent()} {renderStepContent()}
</div> </div>
@ -3548,20 +3535,11 @@ const handleImport = async () => {
onClick={isDeletingApi ? undefined : closeDeleteConfirm} onClick={isDeletingApi ? undefined : closeDeleteConfirm}
/> />
<div <div
className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-lg bg-white border" className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-lg bg-white border border-[#CBD5E1] w-[480px] max-w-[92vw] shadow-lg"
style={{
width: '480px',
maxWidth: '92vw',
borderColor: '#CBD5E1',
boxShadow: '0 20px 45px rgba(0,0,0,0.12)',
}}
> >
<div className="px-8 py-6 space-y-6"> <div className="px-8 py-6 space-y-6">
<div className="flex items-start gap-3"> <div className="flex items-start gap-3">
<span <span className="flex items-center justify-center w-8 h-9">
className="flex items-center justify-center"
style={{ width: '32px', height: '36px' }}
>
<img src={deleteIconSrc} alt="Delete" className="h-6 w-6" /> <img src={deleteIconSrc} alt="Delete" className="h-6 w-6" />
</span> </span>
<div className="flex-1"> <div className="flex-1">

View File

@ -67,13 +67,7 @@ const EmailTemplates = () => {
value={form.body} value={form.body}
onChange={handleChange('body')} onChange={handleChange('body')}
rows={10} rows={10}
className="w-full text-sm focus:outline-none" className="w-full text-sm focus:outline-none border-2 border-[#CBA344] rounded p-3"
style={{
width: '100%',
border: '2px solid #CBA344',
borderRadius: '4px',
padding: '12px 16px',
}}
/> />
</div> </div>
</div> </div>
@ -81,8 +75,7 @@ const EmailTemplates = () => {
<div className="px-6 pb-6 flex items-center justify-end gap-3"> <div className="px-6 pb-6 flex items-center justify-end gap-3">
<button <button
type="button" type="button"
className="h-9 px-5 rounded-md border text-[#92722A] bg-white cursor-pointer" className="h-9 px-5 rounded-md border border-[#92722A] text-[#92722A] bg-white cursor-pointer"
style={{ borderColor: '#92722A' }}
onClick={handleCancel} onClick={handleCancel}
> >
Cancel Cancel

View File

@ -307,8 +307,7 @@ const Establishment = () => {
<div className="px-6 py-4 border-t border-[#E5E7EB] flex items-center justify-end gap-3"> <div className="px-6 py-4 border-t border-[#E5E7EB] flex items-center justify-end gap-3">
<button <button
type="button" type="button"
className="h-9 px-5 rounded-md border text-[#92722A] bg-white cursor-pointer" className="h-9 px-5 rounded-md border border-[#92722A] text-[#92722A] bg-white cursor-pointer"
style={{ borderColor: '#92722A' }}
onClick={closeModal} onClick={closeModal}
> >
Cancel Cancel

View File

@ -1613,9 +1613,8 @@ const handleExportCSV = () => {
onChange={handleFormChange("description")} onChange={handleFormChange("description")}
disabled={modalMode === "view"} disabled={modalMode === "view"}
rows={1} rows={1}
className="w-full px-3 py-2 text-sm border border-[#CBA344] rounded-md focus:outline-none focus:ring-1 focus:ring-[#92722A] focus:border-[#92722A] min-h-[38px]" className="w-full px-3 py-2 text-sm border border-[#CBA344] rounded-md focus:outline-none focus:ring-1 focus:ring-[#92722A] focus:border-[#92722A] min-h-[38px] resize-y"
placeholder="Enter product description" placeholder="Enter product description"
style={{ resize: 'vertical' }}
/> />
</div> </div>
{/* <div> {/* <div>
@ -1671,12 +1670,7 @@ const handleExportCSV = () => {
<div className="fixed inset-0 z-50"> <div className="fixed inset-0 z-50">
<div className="absolute inset-0 bg-black/40" onClick={closeDeleteConfirm} /> <div className="absolute inset-0 bg-black/40" onClick={closeDeleteConfirm} />
<div <div
className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-lg bg-white border" className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-lg bg-white border border-[#CBD5E1] w-[480px] shadow-lg"
style={{
width: '480px',
borderColor: '#CBD5E1',
boxShadow: '0 20px 45px rgba(0,0,0,0.12)',
}}
> >
<div className="px-8 py-6 space-y-6"> <div className="px-8 py-6 space-y-6">
<div className="flex items-start gap-3"> <div className="flex items-start gap-3">

View File

@ -90,25 +90,25 @@ const QuarterlyWindows = () => {
const [isLoading, setIsLoading] = React.useState(false); const [isLoading, setIsLoading] = React.useState(false);
const [validationErrors, setValidationErrors] = React.useState({}); const [validationErrors, setValidationErrors] = React.useState({});
const [toastData, setToastData] = React.useState(null); const [toastData, setToastData] = React.useState(null);
const [isSaving, setIsSaving] = React.useState(false); // Add this line const [isSaving, setIsSaving] = React.useState(false); // Add this line
const [sortConfig, setSortConfig] = React.useState({ const [sortConfig, setSortConfig] = React.useState({
key: null, key: null,
direction: 'asc' direction: 'asc'
}); });
const extractText = (node) => { const extractText = (node) => {
if (typeof node === "string") return node; if (typeof node === "string") return node;
if (typeof node === "number") return String(node); if (typeof node === "number") return String(node);
if (node?.props?.children) { if (node?.props?.children) {
if (Array.isArray(node.props.children)) { if (Array.isArray(node.props.children)) {
return node.props.children.map(extractText).join(" "); return node.props.children.map(extractText).join(" ");
}
return extractText(node.props.children);
} }
return extractText(node.props.children);
} return "";
};
return "";
};
// Format date to yyyy-MM-dd for input fields // Format date to yyyy-MM-dd for input fields
const formatDateForInput = (dateString) => { const formatDateForInput = (dateString) => {
@ -172,29 +172,29 @@ const QuarterlyWindows = () => {
const getSortedData = (data) => { const getSortedData = (data) => {
if (!sortConfig.key) return data; if (!sortConfig.key) return data;
return [...data].sort((a, b) => { return [...data].sort((a, b) => {
let aValue = a[sortConfig.key]; let aValue = a[sortConfig.key];
let bValue = b[sortConfig.key]; let bValue = b[sortConfig.key];
// Handle numeric comparisons // Handle numeric comparisons
if (['year', 'assigned', 'responded', 'not_responded', 'submissionCount'].includes(sortConfig.key)) { if (['year', 'assigned', 'responded', 'not_responded', 'submissionCount'].includes(sortConfig.key)) {
aValue = Number(aValue) || 0; aValue = Number(aValue) || 0;
bValue = Number(bValue) || 0; bValue = Number(bValue) || 0;
return sortConfig.direction === 'asc' ? aValue - bValue : bValue - aValue; return sortConfig.direction === 'asc' ? aValue - bValue : bValue - aValue;
} }
// Handle date comparisons // Handle date comparisons
if (['startDate', 'endDate'].includes(sortConfig.key)) { if (['startDate', 'endDate'].includes(sortConfig.key)) {
aValue = aValue ? new Date(aValue).getTime() : 0; aValue = aValue ? new Date(aValue).getTime() : 0;
bValue = bValue ? new Date(bValue).getTime() : 0; bValue = bValue ? new Date(bValue).getTime() : 0;
return sortConfig.direction === 'asc' ? aValue - bValue : bValue - aValue; return sortConfig.direction === 'asc' ? aValue - bValue : bValue - aValue;
} }
// Default string comparison // Default string comparison
aValue = String(aValue || '').toLowerCase(); aValue = String(aValue || '').toLowerCase();
bValue = String(bValue || '').toLowerCase(); bValue = String(bValue || '').toLowerCase();
if (aValue < bValue) { if (aValue < bValue) {
return sortConfig.direction === 'asc' ? -1 : 1; return sortConfig.direction === 'asc' ? -1 : 1;
} }
@ -206,88 +206,88 @@ const QuarterlyWindows = () => {
}; };
const headers = [ const headers = [
{ {
name: 'Survey Name', name: 'Survey Name',
key: 'survey_name', key: 'survey_name',
sortable: true, sortable: true,
className: 'whitespace-nowrap text-left' className: 'whitespace-nowrap text-left'
}, },
{ {
name: 'Year', name: 'Year',
key: 'year', key: 'year',
sortable: true, sortable: true,
className: 'whitespace-nowrap text-left' className: 'whitespace-nowrap text-left'
}, },
{ {
name: 'Quarter', name: 'Quarter',
key: 'quarter', key: 'quarter',
sortable: true, sortable: true,
className: 'whitespace-nowrap text-left' className: 'whitespace-nowrap text-left'
}, },
{ {
name: 'Start Date', name: 'Start Date',
key: 'startDate', key: 'startDate',
sortable: true, sortable: true,
className: 'whitespace-nowrap text-left' className: 'whitespace-nowrap text-left'
}, },
{ {
name: 'End Date', name: 'End Date',
key: 'endDate', key: 'endDate',
sortable: true, sortable: true,
className: 'whitespace-nowrap text-left' className: 'whitespace-nowrap text-left'
}, },
{ {
name: 'Grace Period', name: 'Grace Period',
key: 'gracePeriod', key: 'gracePeriod',
sortable: false, sortable: false,
className: 'whitespace-nowrap text-left' className: 'whitespace-nowrap text-left'
}, },
{ {
name: 'Assigned', name: 'Assigned',
key: 'assigned', key: 'assigned',
sortable: false, sortable: false,
className: 'whitespace-nowrap text-left' className: 'whitespace-nowrap text-left'
}, },
{ {
name: 'Responded', name: 'Responded',
key: 'responded', key: 'responded',
sortable: false, sortable: false,
className: 'whitespace-nowrap text-left' className: 'whitespace-nowrap text-left'
}, },
{ {
name: 'Not Responded', name: 'Not Responded',
key: 'not_responded', key: 'not_responded',
sortable: false, sortable: false,
className: 'whitespace-nowrap text-left' className: 'whitespace-nowrap text-left'
}, },
{ {
name: 'Submission Count', name: 'Submission Count',
key: 'submissionCount', key: 'submissionCount',
sortable: false, sortable: false,
className: 'whitespace-nowrap text-left' className: 'whitespace-nowrap text-left'
}, },
{ {
name: 'Status', name: 'Status',
key: 'status', key: 'status',
sortable: false, sortable: false,
className: 'whitespace-nowrap text-left' className: 'whitespace-nowrap text-left'
}, },
].map(header => { ].map(header => {
if (!header.sortable) return { name: header.name, className: header.className }; if (!header.sortable) return { name: header.name, className: header.className };
const isActive = sortConfig.key === header.key; const isActive = sortConfig.key === header.key;
const isAsc = sortConfig.direction === 'asc'; const isAsc = sortConfig.direction === 'asc';
return { return {
name: ( name: (
<div <div
className="flex items-center cursor-pointer gap-1" className="flex items-center cursor-pointer gap-1"
onClick={() => handleSort(header.key)} onClick={() => handleSort(header.key)}
> >
<span>{header.name}</span> <span>{header.name}</span>
<img <img
src={isActive ? "/assets/images/active-sort.svg" : "/assets/images/inactive-sort.svg"} src={isActive ? "/assets/images/active-sort.svg" : "/assets/images/inactive-sort.svg"}
alt="Sort" alt="Sort"
className={`w-3 h-3 transition-transform ${isActive && isAsc ? 'transform rotate-180' : ''}`} className={`w-3 h-3 transition-transform ${isActive && isAsc ? 'transform rotate-180' : ''}`}
/> />
</div> </div>
@ -295,7 +295,7 @@ const QuarterlyWindows = () => {
className: header.className className: header.className
}; };
}); });
const columnwidth = [ const columnwidth = [
220, // Survey Name 220, // Survey Name
100, // Year 100, // Year
@ -309,16 +309,16 @@ const QuarterlyWindows = () => {
140, // Submission Count 140, // Submission Count
120 // Actions 120 // Actions
]; ];
const filteredRows = React.useMemo(() => { const filteredRows = React.useMemo(() => {
const term = searchTerm.trim().toLowerCase(); const term = searchTerm.trim().toLowerCase();
return quarterData.filter((item) => { return quarterData.filter((item) => {
// Apply year filter // Apply year filter
if (yearFilter !== 'all' && item.year !== yearFilter) return false; if (yearFilter !== 'all' && item.year !== yearFilter) return false;
// Apply quarter filter // Apply quarter filter
if (quarterFilter !== 'all' && item.quarter !== quarterFilter) return false; if (quarterFilter !== 'all' && item.quarter !== quarterFilter) return false;
// Apply search term // Apply search term
if (!term) return true; if (!term) return true;
const haystack = [ const haystack = [
@ -345,18 +345,17 @@ const QuarterlyWindows = () => {
<div className="flex items-center gap-1 group relative"> <div className="flex items-center gap-1 group relative">
<span>{children}</span> <span>{children}</span>
<div className="relative group cursor-pointer" title={text}> <div className="relative group cursor-pointer" title={text}>
<img <img
src="/assets/images/tooltip.svg" src="/assets/images/tooltip.svg"
alt="info" alt="info"
className="w-4 h-4" className="w-4 h-4 grayscale opacity-70"
style={{ filter: 'invert(45%) sepia(6%) saturate(323%) hue-rotate(175deg) brightness(93%) contrast(82%)' }}
/> />
</div> </div>
</div> </div>
); );
const sortedRows = getSortedData(filteredRows); const sortedRows = getSortedData(filteredRows);
const rows = sortedRows.map((item) => [ const rows = sortedRows.map((item) => [
item.survey_name || '-', item.survey_name || '-',
item.year, item.year,
@ -364,13 +363,13 @@ const QuarterlyWindows = () => {
item.startDate ? formatDateForDisplay(item.startDate) : '-', item.startDate ? formatDateForDisplay(item.startDate) : '-',
item.endDate ? formatDateForDisplay(item.endDate) : '-', item.endDate ? formatDateForDisplay(item.endDate) : '-',
item.gracePeriod, item.gracePeriod,
<Tooltip text="Number of establishments assigned this survey"> <Tooltip key="assigned" text="Number of establishments assigned this survey">
{item.assigned || '0'} {item.assigned || '0'}
</Tooltip>, </Tooltip>,
<Tooltip text="Number of establishments that have responded"> <Tooltip key="responded" text="Number of establishments that have responded">
{item.responded || '0'} {item.responded || '0'}
</Tooltip>, </Tooltip>,
<Tooltip text="Number of establishments yet to respond"> <Tooltip key="not-responded" text="Number of establishments yet to respond">
{item.not_responded || '0'} {item.not_responded || '0'}
</Tooltip>, </Tooltip>,
item.submissionCount, item.submissionCount,
@ -381,19 +380,19 @@ const QuarterlyWindows = () => {
const yearOptions = React.useMemo(() => { const yearOptions = React.useMemo(() => {
const currentYear = new Date().getFullYear(); const currentYear = new Date().getFullYear();
const years = new Set(['all']); const years = new Set(['all']);
// Add years from 2022 to current year // Add years from 2022 to current year
for (let y = 2022; y <= currentYear; y++) { for (let y = 2022; y <= currentYear; y++) {
years.add(y.toString()); years.add(y.toString());
} }
// Add any additional years that might be in the data // Add any additional years that might be in the data
quarterData.forEach(item => { quarterData.forEach(item => {
if (item.year && !years.has(item.year)) { if (item.year && !years.has(item.year)) {
years.add(item.year); years.add(item.year);
} }
}); });
// Sort years in descending order (newest first) // Sort years in descending order (newest first)
return Array.from(years).sort((a, b) => { return Array.from(years).sort((a, b) => {
if (a === 'all') return -1; if (a === 'all') return -1;
@ -401,7 +400,7 @@ const QuarterlyWindows = () => {
return parseInt(b) - parseInt(a); return parseInt(b) - parseInt(a);
}); });
}, [quarterData]); }, [quarterData]);
const quarterOptions = ['all', 'Q1', 'Q2', 'Q3', 'Q4']; const quarterOptions = ['all', 'Q1', 'Q2', 'Q3', 'Q4'];
const openAddModal = () => { const openAddModal = () => {
@ -420,18 +419,18 @@ const QuarterlyWindows = () => {
const openEditModal = async (index) => { const openEditModal = async (index) => {
try { try {
setIsLoading(true); setIsLoading(true);
// Calculate the actual index in the filtered data based on pagination // Calculate the actual index in the filtered data based on pagination
const actualIndex = (currentPage - 1) * pageSize + index; const actualIndex = (currentPage - 1) * pageSize + index;
const selected = filteredRows[actualIndex]; const selected = filteredRows[actualIndex];
if (!selected || !selected.id) { if (!selected || !selected.id) {
throw new Error('Invalid quarterly window selected'); throw new Error('Invalid quarterly window selected');
} }
// Fetch the latest data for this quarter // Fetch the latest data for this quarter
const response = await getQuarterlyWindowById(selected.id); const response = await getQuarterlyWindowById(selected.id);
if (response && response.data) { if (response && response.data) {
const quarterData = response.data; const quarterData = response.data;
const formData = { const formData = {
@ -449,7 +448,7 @@ const QuarterlyWindows = () => {
not_responded: quarterData.not_responded?.toString() || '0', not_responded: quarterData.not_responded?.toString() || '0',
status: quarterData.is_active ? 'Active' : 'Inactive' status: quarterData.is_active ? 'Active' : 'Inactive'
}; };
setEditingRow(actualIndex); setEditingRow(actualIndex);
setForm(formData); setForm(formData);
setOriginalForm(formData); setOriginalForm(formData);
@ -525,7 +524,7 @@ const QuarterlyWindows = () => {
const handleFormChange = (field) => (value) => { const handleFormChange = (field) => (value) => {
setForm(prev => ({ ...prev, [field]: value })); setForm(prev => ({ ...prev, [field]: value }));
// Clear validation error when user starts typing // Clear validation error when user starts typing
if (validationErrors[field]) { if (validationErrors[field]) {
setValidationErrors(prev => ({ setValidationErrors(prev => ({
@ -535,125 +534,125 @@ const QuarterlyWindows = () => {
} }
}; };
const handleSave = async () => { const handleSave = async () => {
try { try {
if (!validateForm()) { if (!validateForm()) {
return;
}
setIsSaving(true);
const startDate = new Date(form.startDate);
const endDate = new Date(form.endDate);
const formattedData = {
survey_name: form.survey_name || '',
year: form.year ? parseInt(form.year, 10) : 0,
quarter: form.quarter || '',
start_date: startDate.toISOString().split('T')[0],
end_date: endDate.toISOString().split('T')[0],
grace_periods_days: form.gracePeriod ? parseInt(form.gracePeriod.split(' ')[0], 10) || 0 : 0,
assigned: form.assigned || 0,
responded: form.responded || 0,
not_responded: form.not_responded || 0,
is_active: form.status === 'Active',
establishment: form.establishment || '-',
};
if (modalMode === 'add') {
const response = await createQuarterlyWindow(formattedData);
if (response.status === 'success') {
// Fetch the latest data from the server
const latestData = await getQuarterlyWindows();
if (latestData.status === 'success' && Array.isArray(latestData.data)) {
const formattedData = latestData.data.map(item => ({
id: item.id,
survey_name: item.survey_name || '',
establishment: item.establishment || '-',
year: item.year?.toString() || '',
quarter: item.quarter || '',
startDate: item.start_date || '',
endDate: item.end_date || '',
gracePeriod: item.grace_periods_days ? `${item.grace_periods_days} days` : '0 days',
submissionCount: item.submission_count?.toString() || '-',
assigned: item.assigned?.toString() || '0',
responded: item.responded?.toString() || '0',
not_responded: item.not_responded?.toString() || '0',
status: item.is_active ? 'Active' : 'Inactive'
}));
setQuarterData(formattedData);
}
setToastData({
message: 'Quarterly survey created successfully!',
type: 'success'
});
} else {
const errorMessage = response.message || 'Failed to add quarterly window';
setToastData({
message: errorMessage,
type: 'error'
});
console.error('Failed to add quarterly window:', errorMessage);
}
} else if (modalMode === 'edit' && editingRow !== null) {
const itemId = quarterData[editingRow]?.id;
if (!itemId) {
setToastData({
message: 'Error: Could not find the item to update',
type: 'error'
});
console.error('Error: Could not find the item to update');
return; return;
} }
const response = await updateQuarterlyWindow(itemId, formattedData);
if (response.status === 'success') { setIsSaving(true);
// Fetch the latest data from the server
const latestData = await getQuarterlyWindows(); const startDate = new Date(form.startDate);
if (latestData.status === 'success' && Array.isArray(latestData.data)) { const endDate = new Date(form.endDate);
const formattedData = latestData.data.map(item => ({
id: item.id, const formattedData = {
survey_name: item.survey_name || '', survey_name: form.survey_name || '',
establishment: item.establishment || '-', year: form.year ? parseInt(form.year, 10) : 0,
year: item.year?.toString() || '', quarter: form.quarter || '',
quarter: item.quarter || '', start_date: startDate.toISOString().split('T')[0],
startDate: item.start_date || '', end_date: endDate.toISOString().split('T')[0],
endDate: item.end_date || '', grace_periods_days: form.gracePeriod ? parseInt(form.gracePeriod.split(' ')[0], 10) || 0 : 0,
gracePeriod: item.grace_periods_days ? `${item.grace_periods_days} days` : '0 days', assigned: form.assigned || 0,
submissionCount: item.submission_count?.toString() || '-', responded: form.responded || 0,
assigned: item.assigned?.toString() || '0', not_responded: form.not_responded || 0,
responded: item.responded?.toString() || '0', is_active: form.status === 'Active',
not_responded: item.not_responded?.toString() || '0', establishment: form.establishment || '-',
status: item.is_active ? 'Active' : 'Inactive' };
}));
setQuarterData(formattedData); if (modalMode === 'add') {
const response = await createQuarterlyWindow(formattedData);
if (response.status === 'success') {
// Fetch the latest data from the server
const latestData = await getQuarterlyWindows();
if (latestData.status === 'success' && Array.isArray(latestData.data)) {
const formattedData = latestData.data.map(item => ({
id: item.id,
survey_name: item.survey_name || '',
establishment: item.establishment || '-',
year: item.year?.toString() || '',
quarter: item.quarter || '',
startDate: item.start_date || '',
endDate: item.end_date || '',
gracePeriod: item.grace_periods_days ? `${item.grace_periods_days} days` : '0 days',
submissionCount: item.submission_count?.toString() || '-',
assigned: item.assigned?.toString() || '0',
responded: item.responded?.toString() || '0',
not_responded: item.not_responded?.toString() || '0',
status: item.is_active ? 'Active' : 'Inactive'
}));
setQuarterData(formattedData);
}
setToastData({
message: 'Quarterly survey created successfully!',
type: 'success'
});
} else {
const errorMessage = response.message || 'Failed to add quarterly window';
setToastData({
message: errorMessage,
type: 'error'
});
console.error('Failed to add quarterly window:', errorMessage);
}
} else if (modalMode === 'edit' && editingRow !== null) {
const itemId = quarterData[editingRow]?.id;
if (!itemId) {
setToastData({
message: 'Error: Could not find the item to update',
type: 'error'
});
console.error('Error: Could not find the item to update');
return;
}
const response = await updateQuarterlyWindow(itemId, formattedData);
if (response.status === 'success') {
// Fetch the latest data from the server
const latestData = await getQuarterlyWindows();
if (latestData.status === 'success' && Array.isArray(latestData.data)) {
const formattedData = latestData.data.map(item => ({
id: item.id,
survey_name: item.survey_name || '',
establishment: item.establishment || '-',
year: item.year?.toString() || '',
quarter: item.quarter || '',
startDate: item.start_date || '',
endDate: item.end_date || '',
gracePeriod: item.grace_periods_days ? `${item.grace_periods_days} days` : '0 days',
submissionCount: item.submission_count?.toString() || '-',
assigned: item.assigned?.toString() || '0',
responded: item.responded?.toString() || '0',
not_responded: item.not_responded?.toString() || '0',
status: item.is_active ? 'Active' : 'Inactive'
}));
setQuarterData(formattedData);
}
setToastData({
message: 'Quarterly survey updated successfully!',
type: 'success'
});
} else {
const errorMessage = response.message || 'Failed to update quarterly window';
setToastData({
message: errorMessage,
type: 'error'
});
console.error('Failed to update quarterly window:', errorMessage);
} }
setToastData({
message: 'Quarterly survey updated successfully!',
type: 'success'
});
} else {
const errorMessage = response.message || 'Failed to update quarterly window';
setToastData({
message: errorMessage,
type: 'error'
});
console.error('Failed to update quarterly window:', errorMessage);
} }
handleCloseModal();
} catch (error) {
const errorMessage = error.response?.data?.message || error.message || 'An error occurred while saving';
setToastData({
message: errorMessage,
type: 'error'
});
console.error('Error saving quarterly window:', error);
} finally {
setIsSaving(false);
} }
handleCloseModal(); };
} catch (error) {
const errorMessage = error.response?.data?.message || error.message || 'An error occurred while saving';
setToastData({
message: errorMessage,
type: 'error'
});
console.error('Error saving quarterly window:', error);
} finally {
setIsSaving(false);
}
};
return ( return (
<div className="w-full max-w-[1280px] rounded-lg border border-[#C3C6CB] bg-white min-h-[348px] pb-6"> <div className="w-full max-w-[1280px] rounded-lg border border-[#C3C6CB] bg-white min-h-[348px] pb-6">
@ -669,7 +668,7 @@ const handleSave = async () => {
</div> </div>
</div> </div>
)} )}
<div className="px-6 py-4"> <div className="px-6 py-4">
<div className="flex flex-col gap-3 md:h-12 md:flex-row md:items-center md:justify-between"> <div className="flex flex-col gap-3 md:h-12 md:flex-row md:items-center md:justify-between">
<h3 className="text-[18px] leading-[28px] font-medium text-[#232528]">Manage Surveys ({filteredRows.length})</h3> <h3 className="text-[18px] leading-[28px] font-medium text-[#232528]">Manage Surveys ({filteredRows.length})</h3>
@ -727,9 +726,9 @@ const handleSave = async () => {
// .map((h) => `"${h.name}"`) // .map((h) => `"${h.name}"`)
// .join(','); // .join(',');
const csvHeader = headers const csvHeader = headers
.filter((h) => extractText(h.name) !== "") // remove Actions .filter((h) => extractText(h.name) !== "") // remove Actions
.map((h) => `"${extractText(h.name)}"` ) // extract plain text .map((h) => `"${extractText(h.name)}"`) // extract plain text
.join(','); .join(',');
const csvRows = filteredRows.map((item) => { const csvRows = filteredRows.map((item) => {
const rowData = [ const rowData = [
item.survey_name || '', item.survey_name || '',
@ -758,21 +757,21 @@ const handleSave = async () => {
document.body.removeChild(link); document.body.removeChild(link);
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
}} }}
className={`h-10 px-5 rounded-[6px] border text-sm inline-flex items-center gap-3 ${ className={`h-10 min-w-[143px] px-5 rounded-[6px] border text-sm inline-flex items-center gap-3
filteredRows.length ${filteredRows.length
? 'bg-[#F7F7F7] border-[#C3C6CB] text-[#232528]' ? 'bg-[#F7F7F7] border-[#C3C6CB] text-[#232528]'
: 'bg-[#F3F4F6] border-[#E5E7EB] text-[#9CA3AF] cursor-not-allowed' : 'bg-[#F3F4F6] border-[#E5E7EB] text-[#9CA3AF] cursor-not-allowed'
}`} }
`}
disabled={!filteredRows.length} disabled={!filteredRows.length}
style={{ minWidth: '143px' }}
> >
<img src={downloadIconSrc} alt="Export" className="h-5 w-5" /> <img src={downloadIconSrc} alt="Export" className="h-5 w-5" />
<span className="font-medium">Export CSV</span> <span className="font-medium">Export CSV</span>
</button> </button>
<button <button
onClick={openAddModal} onClick={openAddModal}
className="h-10 px-5 rounded-[6px] bg-[#92722A] text-white text-sm inline-flex items-center gap-3 cursor-pointer" className="h-10 px-5 rounded-[6px] bg-[#92722A] text-white text-sm inline-flex items-center gap-3 cursor-pointer md:min-w-[148px]"
style={{ minWidth: '148px' }}
> >
<img src={addIconSrc} alt="Add" className="h-5 w-5" /> <img src={addIconSrc} alt="Add" className="h-5 w-5" />
<span className="font-medium">Create Survey</span> <span className="font-medium">Create Survey</span>
@ -833,13 +832,7 @@ const handleSave = async () => {
<div className="fixed inset-0 z-50"> <div className="fixed inset-0 z-50">
<div className="absolute inset-0 bg-black/40" onClick={handleCloseModal} /> <div className="absolute inset-0 bg-black/40" onClick={handleCloseModal} />
<div <div
className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-[16px] bg-white" className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-[16px] bg-white w-[628px] max-w-[92vw] shadow-[0_24px_40px_rgba(27,29,33,0.16)] border border-[#E5E7EB]"
style={{
width: '628px',
maxWidth: '92vw',
boxShadow: '0 24px 40px rgba(27, 29, 33, 0.16)',
border: '1px solid #E5E7EB',
}}
> >
<div className="flex items-center justify-between px-6 py-4 border-b border-[#F1F2F4]"> <div className="flex items-center justify-between px-6 py-4 border-b border-[#F1F2F4]">
<h3 className="text-[18px] font-medium text-[#232528]"> <h3 className="text-[18px] font-medium text-[#232528]">
@ -893,7 +886,7 @@ const handleSave = async () => {
<p className="mt-1 text-sm text-red-600"></p> <p className="mt-1 text-sm text-red-600"></p>
)} )}
</div> </div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<SelectField <SelectField
@ -914,7 +907,7 @@ const handleSave = async () => {
<p className="mt-1 text-sm text-red-600"></p> <p className="mt-1 text-sm text-red-600"></p>
)} )}
</div> </div>
<div> <div>
<SelectField <SelectField
label={ label={
@ -937,7 +930,7 @@ const handleSave = async () => {
<p className="mt-1 text-sm text-red-600"></p> <p className="mt-1 text-sm text-red-600"></p>
)} )}
</div> </div>
<div> <div>
<DateField <DateField
label={ label={
@ -957,7 +950,7 @@ const handleSave = async () => {
<p className="mt-1 text-sm text-red-500">{validationErrors.startDate}</p> <p className="mt-1 text-sm text-red-500">{validationErrors.startDate}</p>
)} )}
</div> </div>
<div> <div>
<DateField <DateField
label={ label={
@ -978,7 +971,7 @@ const handleSave = async () => {
)} )}
</div> </div>
</div> </div>
<div className="w-full"> <div className="w-full">
<SelectField <SelectField
label="Grace Period (Days)" label="Grace Period (Days)"

View File

@ -62,8 +62,7 @@ const SubmissionDeadlines = () => {
<div className="px-6 pb-6 flex items-center justify-end gap-3"> <div className="px-6 pb-6 flex items-center justify-end gap-3">
<button <button
type="button" type="button"
className="h-9 px-5 rounded-md border text-[#92722A] bg-white cursor-pointer" className="h-9 px-5 rounded-md border border-[#92722A] text-[#92722A] bg-white cursor-pointer"
style={{ borderColor: '#92722A' }}
onClick={handleCancel} onClick={handleCancel}
> >
Cancel Cancel

View File

@ -964,14 +964,8 @@ const downloadSampleCSV = async () => {
<div className="fixed inset-0 z-50"> <div className="fixed inset-0 z-50">
<div className="absolute inset-0 bg-black/40" onClick={closeModal} /> <div className="absolute inset-0 bg-black/40" onClick={closeModal} />
<div <div
className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-[16px] bg-white" className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-[16px] bg-white w-[628px] max-w-[92vw] shadow-[0_24px_40px_rgba(27,29,33,0.16)] border border-[#E5E7EB]"
style={{ >
width: '628px',
maxWidth: '92vw',
boxShadow: '0 24px 40px rgba(27, 29, 33, 0.16)',
border: '1px solid #E5E7EB',
}}
>
<div className="flex items-center justify-between px-6 py-4 border-b border-[#F1F2F4]"> <div className="flex items-center justify-between px-6 py-4 border-b border-[#F1F2F4]">
<h3 className="text-[18px] font-medium text-[#232528]"> <h3 className="text-[18px] font-medium text-[#232528]">
View Unit Master View Unit Master
@ -1028,14 +1022,8 @@ const downloadSampleCSV = async () => {
<div className="fixed inset-0 z-50"> <div className="fixed inset-0 z-50">
<div className="absolute inset-0 bg-black/40" onClick={closeModal} /> <div className="absolute inset-0 bg-black/40" onClick={closeModal} />
<div <div
className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-xl bg-white" className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-xl bg-white w-[628px] max-w-[92vw] shadow-[0_24px_40px_rgba(27,29,33,0.16)] border border-[#E5E7EB]"
style={{ >
width: '628px',
maxWidth: '92vw',
boxShadow: '0 24px 40px rgba(27, 29, 33, 0.16)',
border: '1px solid #E5E7EB',
}}
>
<div className="flex items-center justify-between px-6 py-4 border-b border-[#F1F2F4]"> <div className="flex items-center justify-between px-6 py-4 border-b border-[#F1F2F4]">
<h3 className="text-[18px] font-medium text-[#232528]"> <h3 className="text-[18px] font-medium text-[#232528]">
{modalMode === 'edit' ? 'Edit Unit Master' : 'Add Unit Master'} {modalMode === 'edit' ? 'Edit Unit Master' : 'Add Unit Master'}
@ -1108,20 +1096,11 @@ const downloadSampleCSV = async () => {
<div className="fixed inset-0 z-50"> <div className="fixed inset-0 z-50">
<div className="absolute inset-0 bg-black/40" onClick={closeDeleteConfirm} /> <div className="absolute inset-0 bg-black/40" onClick={closeDeleteConfirm} />
<div <div
className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-lg bg-white border" className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-lg bg-white border border-[#CBD5E1] w-[480px] max-w-[92vw] shadow-[0_20px_45px_rgba(0,0,0,0.12)]"
style={{
width: '480px',
maxWidth: '92vw',
borderColor: '#CBD5E1',
boxShadow: '0 20px 45px rgba(0,0,0,0.12)',
}}
> >
<div className="px-8 py-6 space-y-6"> <div className="px-8 py-6 space-y-6">
<div className="flex items-start gap-3"> <div className="flex items-start gap-3">
<span <span className="flex items-center justify-center w-8 h-9">
className="flex items-center justify-center"
style={{ width: '32px', height: '36px' }}
>
<img src={deleteIconSrc} alt="Delete" className="h-6 w-6" /> <img src={deleteIconSrc} alt="Delete" className="h-6 w-6" />
</span> </span>
<div className="flex-1"> <div className="flex-1">

View File

@ -56,17 +56,17 @@ const Faq = () => {
if (isOpen) { if (isOpen) {
ref.current.style.maxHeight = ref.current.scrollHeight + "px"; ref.current.style.maxHeight = ref.current.scrollHeight + "px";
} else { } else {
ref.current.style.maxHeight = "0px"; ref.current.classList.remove('max-h-md');
ref.current.classList.add('max-h-0');
} }
}, [isOpen]); }, [isOpen]);
return ( return (
<div <div
ref={ref} ref={ref}
className={`overflow-hidden transition-[max-height] duration-300 ${ className={`overflow-hidden transition-[max-height] duration-300 max-h-0 ${
isOpen ? "mt-3" : "" isOpen ? "mt-3" : ""
}`} }`}
style={{ maxHeight: "0px" }}
> >
{children} {children}
</div> </div>

View File

@ -516,7 +516,7 @@ const ManufacturingIndex = () => {
Next scheduled run: {nextScheduledRun} Next scheduled run: {nextScheduledRun}
</div> </div>
<div className="flex text-sm text-gray-600"> <div className="flex text-sm text-gray-600">
<InfoOutlinedIcon className="text-gray-400 mr-1 mt-0.5 flex-shrink-0" style={{ fontSize: '1rem' }} /> <InfoOutlinedIcon className="text-gray-400 text-base mr-1 mt-0.5 flex-shrink-0" />
<span className="whitespace-nowrap">Formula: Manufacturing index<sub>t</sub> = Σ (sector weight<sub>i</sub> × group index<sub>i,t</sub>)</span> <span className="whitespace-nowrap">Formula: Manufacturing index<sub>t</sub> = Σ (sector weight<sub>i</sub> × group index<sub>i,t</sub>)</span>
</div> </div>
</div> </div>