feat: production deployment - full update with providers, admin, glossaries, pricing, tests
Major changes across backend, frontend, infrastructure: - Provider system with model selection (Google, DeepL, OpenAI, Ollama, Google Cloud) - Admin panel: user management, pricing, settings - Glossary system with CSV import/export - Subscription and tier quota management - Security hardening (rate limiting, API key auth, path traversal fixes) - Docker compose for dev, prod, and IONOS deployment - Alembic migrations for new tables - Frontend: dashboard, pricing page, landing page, i18n (en/fr) - Test suite and verification scripts Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { useRef } from 'react';
|
||||
import { Upload } from 'lucide-react';
|
||||
import { Upload, FileSpreadsheet, FileText, Presentation } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useI18n } from '@/lib/i18n';
|
||||
import type { UseFileUploadReturn } from './types';
|
||||
|
||||
interface FileDropZoneProps {
|
||||
@@ -11,40 +12,72 @@ interface FileDropZoneProps {
|
||||
|
||||
export function FileDropZone({ upload }: FileDropZoneProps) {
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const { t } = useI18n();
|
||||
|
||||
const handleClick = () => {
|
||||
inputRef.current?.click();
|
||||
};
|
||||
const handleClick = () => inputRef.current?.click();
|
||||
|
||||
return (
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label={t('dashboard.translate.dropzone.uploadAria')}
|
||||
className={cn(
|
||||
'relative flex flex-col items-center justify-center gap-3 rounded-lg border-2 border-dashed px-6 py-10 transition-colors cursor-pointer',
|
||||
'relative flex flex-col items-center justify-center gap-6 rounded-2xl border-2 border-dashed',
|
||||
'min-h-[320px] cursor-pointer select-none transition-all duration-200 px-8 py-12',
|
||||
upload.isDragOver
|
||||
? 'border-primary bg-primary/5'
|
||||
: 'border-border bg-muted/30 hover:border-muted-foreground/30'
|
||||
? 'border-primary bg-primary/8 scale-[1.01]'
|
||||
: 'border-border bg-muted/20 hover:border-primary/50 hover:bg-muted/40'
|
||||
)}
|
||||
onDragOver={upload.handleDragOver}
|
||||
onDragLeave={upload.handleDragLeave}
|
||||
onDrop={upload.handleDrop}
|
||||
onClick={handleClick}
|
||||
onKeyDown={(e) => e.key === 'Enter' || e.key === ' ' ? handleClick() : undefined}
|
||||
>
|
||||
<div className="flex size-12 items-center justify-center rounded-xl bg-secondary">
|
||||
<Upload className="size-5 text-muted-foreground" />
|
||||
{/* Icon */}
|
||||
<div className={cn(
|
||||
'flex size-20 items-center justify-center rounded-2xl transition-colors',
|
||||
upload.isDragOver ? 'bg-primary/15' : 'bg-secondary'
|
||||
)}>
|
||||
<Upload className={cn(
|
||||
'size-9 transition-colors',
|
||||
upload.isDragOver ? 'text-primary' : 'text-muted-foreground'
|
||||
)} />
|
||||
</div>
|
||||
<div className="flex flex-col items-center gap-1">
|
||||
<p className="text-sm font-medium text-foreground">
|
||||
Drag & drop your .xlsx, .docx, or .pptx file here
|
||||
|
||||
{/* Text */}
|
||||
<div className="flex flex-col items-center gap-2 text-center">
|
||||
<p className="text-lg font-semibold text-foreground">
|
||||
{t('dashboard.translate.dropzone.title')}
|
||||
</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{t('dashboard.translate.dropzone.subtitle')}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">or click to browse</p>
|
||||
</div>
|
||||
|
||||
{/* Format badges */}
|
||||
<div className="flex flex-wrap items-center justify-center gap-3">
|
||||
<span className="flex items-center gap-1.5 rounded-lg border border-border/60 bg-background px-3 py-1.5 text-xs font-medium text-muted-foreground">
|
||||
<FileSpreadsheet className="size-3.5 text-green-500" />
|
||||
Excel (.xlsx)
|
||||
</span>
|
||||
<span className="flex items-center gap-1.5 rounded-lg border border-border/60 bg-background px-3 py-1.5 text-xs font-medium text-muted-foreground">
|
||||
<FileText className="size-3.5 text-blue-500" />
|
||||
Word (.docx)
|
||||
</span>
|
||||
<span className="flex items-center gap-1.5 rounded-lg border border-border/60 bg-background px-3 py-1.5 text-xs font-medium text-muted-foreground">
|
||||
<Presentation className="size-3.5 text-orange-500" />
|
||||
PowerPoint (.pptx)
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="file"
|
||||
accept=".xlsx,.docx,.pptx"
|
||||
className="hidden"
|
||||
onChange={upload.handleFileSelect}
|
||||
aria-label="Upload file"
|
||||
aria-label={t('dashboard.translate.dropzone.uploadAria')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user