Implemented data export
This commit is contained in:
@@ -22,6 +22,8 @@ import {
|
||||
import { Modal } from '../ui/Modal';
|
||||
import { HelpTooltip } from '../ui/HelpTooltip';
|
||||
import { useToast } from '../ui/Toast';
|
||||
import { ExportButton } from '../ui/ExportButton';
|
||||
import { ExportColumn } from '../../utils/exportUtils';
|
||||
import {
|
||||
Rule,
|
||||
Programme,
|
||||
@@ -231,6 +233,28 @@ export const RulesSection: React.FC<RulesSectionProps> = ({
|
||||
});
|
||||
}, [rules, selectedProgrammeFilter, statusFilter, searchTerm, programmeMap]);
|
||||
|
||||
// Export columns definition
|
||||
const ruleExportColumns: ExportColumn<Rule>[] = useMemo(
|
||||
() => [
|
||||
{ header: 'Rule ID', key: 'id' },
|
||||
{ header: 'Rule Name', key: 'name', format: (val) => val || 'Untitled Rule' },
|
||||
{
|
||||
header: 'Strategic Programme',
|
||||
key: 'programmeId',
|
||||
format: (val) => programmeMap.get(String(val))?.name || `Programme #${val}`,
|
||||
},
|
||||
{ header: 'Version', key: 'version', format: (val) => `v${val || 1}` },
|
||||
{
|
||||
header: 'Status',
|
||||
key: 'status',
|
||||
format: (val) => (Number(val) === ActivityStatus.Active ? 'Active' : 'Inactive'),
|
||||
},
|
||||
{ header: 'Rule Description', key: 'description', format: (val) => val || '—' },
|
||||
{ header: 'Created Date', key: 'createdAt', format: (val) => (val ? formatDate(val) : '—') },
|
||||
],
|
||||
[programmeMap]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{/* Top Filter and Actions Bar */}
|
||||
@@ -291,25 +315,37 @@ export const RulesSection: React.FC<RulesSectionProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Action Buttons */}
|
||||
{/* Action Buttons: Refresh, Export & Add */}
|
||||
<div className="flex items-center gap-2 self-end lg:self-center">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => refetch()}
|
||||
onClick={() => {
|
||||
refetch();
|
||||
success('Refreshed', 'Programme rules updated from API.');
|
||||
}}
|
||||
disabled={isFetching}
|
||||
className="inline-flex items-center gap-1.5 px-3 py-2 text-xs font-semibold text-slate-300 bg-slate-800/80 hover:bg-slate-700 rounded-xl border border-slate-700 transition cursor-pointer"
|
||||
title="Refresh Rules"
|
||||
className="inline-flex items-center justify-center gap-1.5 px-3.5 py-2 text-xs font-semibold text-slate-300 bg-[#0d121f] hover:bg-slate-800 border border-slate-700/80 rounded-xl transition cursor-pointer shadow-xs disabled:opacity-50"
|
||||
title="Refresh Programme Rules from API"
|
||||
>
|
||||
<RefreshCw className={`w-3.5 h-3.5 ${isFetching ? 'animate-spin' : ''}`} />
|
||||
Refresh
|
||||
<RefreshCw className={`w-3.5 h-3.5 text-blue-400 ${isFetching ? 'animate-spin' : ''}`} />
|
||||
<span>Refresh</span>
|
||||
</button>
|
||||
|
||||
<ExportButton
|
||||
title="Programme Rules Registry"
|
||||
subtitle="Statutory, regulatory, and eligibility rules governing strategic funding programmes"
|
||||
filename={`pfm-programme-rules-${new Date().toISOString().split('T')[0]}`}
|
||||
columns={ruleExportColumns}
|
||||
data={filteredRules}
|
||||
/>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => openCreateModal()}
|
||||
className="inline-flex items-center gap-1.5 px-4 py-2 text-xs font-semibold text-white bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-500 hover:to-indigo-500 rounded-xl shadow-md shadow-blue-500/20 transition cursor-pointer"
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
Add Rule
|
||||
<span>Add Rule</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user