- Updated CancelButton and SubmitButton to use i18next for localization. - Modified DataTableColumnHeader and DataTableFacetedFilter to include translations for sorting and filtering messages. - Enhanced DataTableSelectionColumn with localized aria-labels for accessibility. - Localized titles and messages in SimpleEmptyState and ErrorOverlay components. - Updated LayoutHeader to use i18next for navigation toggle label. - Integrated i18next into useLogout for error messages. - Localized alert dialog actions in useRemoveAlertDialog. - Added new translations in en.json and es.json for various UI components. - Updated breadcrumb and carousel components to use localized strings. - Enhanced pagination component with i18next for navigation labels. - Localized sheet component close button text.
79 lines
2.8 KiB
TypeScript
79 lines
2.8 KiB
TypeScript
"use client";
|
|
|
|
import { ErrorMessage } from "@/lib/hooks/useDownloader/types";
|
|
import { cn } from "@/lib/utils";
|
|
import { Button, Card, CardContent, CardHeader, CardTitle, Progress } from "@/ui";
|
|
import { FileTextIcon, Loader2Icon, XCircleIcon } from "lucide-react";
|
|
import { useEffect, useState } from "react";
|
|
import { t } from "i18next";
|
|
|
|
interface PDFGenerationLoadingProps {
|
|
className?: string;
|
|
isInProgress: boolean;
|
|
percentage: number;
|
|
elapsed: number;
|
|
cancel: () => void;
|
|
error: ErrorMessage;
|
|
}
|
|
|
|
export const PDFGenerationLoading = ({
|
|
isInProgress,
|
|
percentage,
|
|
elapsed,
|
|
cancel,
|
|
error,
|
|
className,
|
|
}: PDFGenerationLoadingProps) => {
|
|
const [estimatedTime, setEstimatedTime] = useState(10);
|
|
|
|
useEffect(() => {
|
|
if (isInProgress && percentage > 0) {
|
|
const estimatedTotal = (elapsed / percentage) * 100;
|
|
setEstimatedTime(Math.max(0, Math.round(estimatedTotal - elapsed)));
|
|
}
|
|
}, [isInProgress, percentage, elapsed]);
|
|
|
|
if (!isInProgress && !error?.errorMessage) return null;
|
|
|
|
return (
|
|
<Card className={cn("overflow-hidden", className)}>
|
|
<CardHeader>
|
|
<CardTitle className='flex items-center justify-between'>
|
|
{error?.errorMessage ? t("quotes.pdf_generation.error") : t("quotes.pdf_generation.title")}
|
|
{isInProgress && <Loader2Icon className='w-4 h-4 animate-spin' />}
|
|
{error?.errorMessage && <XCircleIcon className='w-4 h-4 text-destructive' />}
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
{error?.errorMessage ? (
|
|
<div className='text-destructive'>{error?.errorMessage}</div>
|
|
) : (
|
|
<div className='flex flex-col items-center space-y-4'>
|
|
<div className='relative w-32 h-40 overflow-hidden rounded-lg bg-muted'>
|
|
<div
|
|
className='absolute bottom-0 left-0 right-0 transition-all duration-1000 ease-out bg-primary'
|
|
style={{ height: `${percentage}%` }}
|
|
/>
|
|
<FileTextIcon
|
|
className='absolute transform -translate-x-1/2 -translate-y-1/2 animate-pulse top-1/2 left-1/2 text-muted-foreground'
|
|
size={48}
|
|
/>
|
|
</div>
|
|
<Progress value={percentage} className='w-full' />
|
|
<div className='text-sm text-center text-muted-foreground'>
|
|
<p>{t("quotes.pdf_generation.progress", { percentage })}</p>
|
|
<div className='hidden'>
|
|
<p>{t("quotes.pdf_generation.elapsed", { elapsed })}</p>
|
|
{estimatedTime > 0 && <p>{t("quotes.pdf_generation.remaining", { estimatedTime })}</p>}
|
|
</div>
|
|
</div>
|
|
<Button variant='destructive' onClick={cancel} className='hidden'>
|
|
{t("quotes.pdf_generation.cancel")}
|
|
</Button>
|
|
</div>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
};
|