Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | 2x 2x 30x 84x 2x 16x 16x 16x 16x 16x 13x 12x 12x 30x | import { ArrowRight } from 'lucide-react';
import type { MenuItemConfig } from '@/components/action-menu';
import { DashboardCardWrapper } from './shared/dashboard-card-wrapper';
import { DashboardStateRenderer } from './shared/dashboard-state-renderer';
import { Heading } from '@/components/heading';
import { useConversionRates } from '../hooks/use-conversion-rates';
import { useCardVisibility } from '../hooks/use-card-visibility';
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
('use memo');
// Conversion data interfaces
interface ConversionItem {
currency: string;
rate: string;
}
interface ConversionColumnData {
title: string;
items: ConversionItem[];
}
interface ConversionRateCardProps {
columns: ConversionColumnData[];
actionItems?: MenuItemConfig[];
loading?: boolean;
error?: string | null;
onRetry?: () => void;
}
const ConversionColumn = ({ title, items }: ConversionColumnData) => (
<div>
<Heading
as="h3"
size="h6"
className="font-semibold bg-gradient-vertical bg-clip-text text-transparent mb-4"
>
{title}
</Heading>
<div className="space-y-3">
{items.map((item, index) => (
<div key={index} className="flex justify-between items-center py-2">
<span className="flex-1 text-sm text-default">{item.currency}</span>
<span className="flex-1 text-sm text-default">{item.rate}</span>
</div>
))}
</div>
</div>
);
export const ConversionRateCard = ({
actionItems,
}: ConversionRateCardProps) => {
// Manage card visibility
const { isVisible, hideCard } = useCardVisibility({
id: 'conversionCard',
defaultVisible: true,
});
// Use existing API data hook
const {
data: conversionRatesData,
isLoading: conversionLoading,
error: conversionError,
refetch: refetchConversionRates,
} = useConversionRates();
// Create action items with hide functionality
const cardActionItems: MenuItemConfig[] = actionItems || [
{ label: 'View' },
{
label: 'Delete',
variant: 'destructive',
onClick: hideCard,
},
];
// Don't render if card is hidden
Iif (!isVisible) {
return null;
}
return (
<DashboardCardWrapper
title="Conversion Rate to Naira"
actionItems={cardActionItems}
contentClassName="p-6 flex"
className="mt-8"
>
<DashboardStateRenderer
loading={conversionLoading}
error={conversionError?.message || null}
data={conversionRatesData || []}
isEmpty={data => (data as ConversionColumnData[]).length === 0}
onRetry={refetchConversionRates}
loadingMessage="Loading conversion rates..."
errorTitle=""
emptyMessage="No conversion rates available"
className="h-64"
>
{conversionData => {
const typedData = conversionData as ConversionColumnData[];
return (
<>
<div className="flex-1 grid grid-cols-3 gap-8">
{typedData.map((column, index) => (
<ConversionColumn key={index} {...column} />
))}
</div>
<button
className="self-center w-12 h-12 bg-gradient-vertical rounded-full flex items-center justify-center shadow-lg transition-all duration-200 hover:scale-105"
aria-label="View more conversion rates"
>
<ArrowRight className="w-6 h-6 text-white" aria-hidden="true" />
</button>
</>
);
}}
</DashboardStateRenderer>
</DashboardCardWrapper>
);
};
export type { ConversionItem, ConversionColumnData, ConversionRateCardProps };
|