105 lines
3.6 KiB
TypeScript
105 lines
3.6 KiB
TypeScript
import React from 'react';
|
|
import { Paper, Stack, Group, ThemeIcon, Text, SimpleGrid, ScrollArea } from '@mantine/core';
|
|
import { Info, CircleCheck, XCircle } from 'lucide-react';
|
|
|
|
export interface AggregatedResult {
|
|
totalItems: number;
|
|
totalSuccess: number;
|
|
totalFailed: number;
|
|
messages: string[];
|
|
}
|
|
|
|
const SummaryPanel = React.memo(function SummaryPanel({
|
|
result,
|
|
t,
|
|
}: {
|
|
result: AggregatedResult;
|
|
t: (key: string) => string;
|
|
}) {
|
|
const messages = result.messages ?? [];
|
|
|
|
return (
|
|
<Paper p="sm" radius="md" withBorder>
|
|
<Stack gap="sm">
|
|
{/* Stats row - Grid for compact and even distribution */}
|
|
<SimpleGrid cols={3} spacing="xs">
|
|
{/* Total Items Card */}
|
|
<Paper py="sm" px="md" radius="sm" withBorder bg="blue.0">
|
|
<Group gap="xs" justify="space-between" wrap="nowrap">
|
|
<Group gap={6} wrap="nowrap">
|
|
<ThemeIcon variant="transparent" color="blue.7" size="sm">
|
|
<Info size={16} strokeWidth={2.5} />
|
|
</ThemeIcon>
|
|
<Text size="sm" fw={600} c="blue.9">
|
|
{t('common:bulkAction.totalData')}
|
|
</Text>
|
|
</Group>
|
|
<Text size="sm" fw={700} c="blue.9">
|
|
{result.totalItems}
|
|
</Text>
|
|
</Group>
|
|
</Paper>
|
|
|
|
{/* Total Success Card */}
|
|
<Paper py="sm" px="md" radius="sm" withBorder bg="green.0">
|
|
<Group gap="xs" justify="space-between" wrap="nowrap">
|
|
<Group gap={6} wrap="nowrap">
|
|
<ThemeIcon variant="transparent" color="green.7" size="sm">
|
|
<CircleCheck size={16} strokeWidth={2.5} />
|
|
</ThemeIcon>
|
|
<Text size="sm" fw={600} c="green.9">
|
|
{t('common:bulkAction.totalSuccess')}
|
|
</Text>
|
|
</Group>
|
|
<Text size="sm" fw={700} c="green.9">
|
|
{result.totalSuccess}
|
|
</Text>
|
|
</Group>
|
|
</Paper>
|
|
|
|
{/* Total Failed Card */}
|
|
<Paper py="sm" px="md" radius="sm" withBorder bg="red.0">
|
|
<Group gap="xs" justify="space-between" wrap="nowrap">
|
|
<Group gap={6} wrap="nowrap">
|
|
<ThemeIcon variant="transparent" color="red.7" size="sm">
|
|
<XCircle size={16} strokeWidth={2.5} />
|
|
</ThemeIcon>
|
|
<Text size="sm" fw={600} c="red.9">
|
|
{t('common:bulkAction.totalFailed')}
|
|
</Text>
|
|
</Group>
|
|
<Text size="sm" fw={700} c="red.9">
|
|
{result.totalFailed}
|
|
</Text>
|
|
</Group>
|
|
</Paper>
|
|
</SimpleGrid>
|
|
|
|
{/* Messages list area (Log style) */}
|
|
{messages.length > 0 && (
|
|
<Stack gap={4} mt={4}>
|
|
<Text size="xs" fw={600} c="dimmed" tt="uppercase">
|
|
{t('common:bulkAction.messages')}
|
|
</Text>
|
|
|
|
{/* Locks the maximum height and adds scroll if there are many messages */}
|
|
<ScrollArea h={messages.length > 3 ? 120 : undefined} type="auto" offsetScrollbars>
|
|
<Stack gap={6}>
|
|
{messages.map((msg, idx) => (
|
|
<Paper key={idx} p={8} px="sm" radius="sm" bg="white" withBorder>
|
|
<Text size="xs" c="gray.7" lh={1.4}>
|
|
{msg}
|
|
</Text>
|
|
</Paper>
|
|
))}
|
|
</Stack>
|
|
</ScrollArea>
|
|
</Stack>
|
|
)}
|
|
</Stack>
|
|
</Paper>
|
|
);
|
|
});
|
|
|
|
export default SummaryPanel;
|