# All files / src/components/features DocumentUploader.tsx

0% Statements 0/25
0% Branches 0/20
0% Functions 0/6
0% Lines 0/22

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

     import { useCallback, useState } from 'react';
    import { Upload } from 'lucide-react';
    import { SUPPORTED_FILE_TYPES, MAX_FILE_SIZE } from '../../api/types';
    import { useTranslation } from 'react-i18next';

    interface DocumentUploaderProps {
      onUpload: (file: File) => void;
      loading?: boolean;
    }

    function DocumentUploader({ onUpload, loading }: DocumentUploaderProps) {
      const { t } = useTranslation();
      const [dragOver, setDragOver] = useState(false);

      const handleDrop = useCallback((e: React.DragEvent) => {
        e.preventDefault();
        setDragOver(false);
        const file = e.dataTransfer.files[0];
        if (file && validateFile(file)) onUpload(file);
      }, [onUpload]);

      const handleFileChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
        const file = e.target.files?.[0];
        if (file && validateFile(file)) onUpload(file);
      }, [onUpload]);

      const validateFile = (file: File): boolean => {
        const ext = '.' + file.name.split('.').pop()?.toLowerCase();
        if (!SUPPORTED_FILE_TYPES.includes(ext)) {
          alert(`${t('document.upload.unsupportedFormat')} ${SUPPORTED_FILE_TYPES.join(', ')}`);
          return false;
        }
        if (file.size > MAX_FILE_SIZE) {
          alert(t('document.upload.fileTooLarge'));
          return false;
        }
        return true;
      };

      return (
        <div
          onDragOver={e => { e.preventDefault(); setDragOver(true); }}
          onDragLeave={() => setDragOver(false)}
          onDrop={handleDrop}
          className={`
            relative border-2 border-dashed rounded-card p-12 text-center transition-colors cursor-pointer
            ${dragOver
              ? 'border-accent bg-accent-bg'
              : 'border-accent/30 hover:border-accent/50'
            }
            ${loading ? 'pointer-events-none opacity-50' : ''}
          `}
        >
          <input
            type="file"
            accept={SUPPORTED_FILE_TYPES.join(',')}
            onChange={handleFileChange}
            className="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
            disabled={loading}
          />
          <div className="flex flex-col items-center gap-3">
            <div className={`p-4 rounded-card bg-surface-secondary`}>
              <Upload className={`w-8 h-8 ${dragOver ? 'text-accent' : 'text-text-tertiary'}`} />
            </div>
            <div>
              <p className="text-[15px] font-medium text-text-primary">
                {loading ? t('document.upload.uploading') : t('document.upload.drag')}
              </p>
              <p className="text-[12px] text-text-tertiary mt-1">
                {t('document.upload.formats')}
              </p>
            </div>
          </div>
        </div>
      );
    }

    export { DocumentUploader };