<commit_before>/**
 * @component
 */

import classNames from 'clsx';
import PropTypes from 'prop-types';
import React, { PureComponent } from 'react';
import Icon from '../../react-chayns-icon/component/Icon';
import { isFunction } from '../../utils/is';
import fileInputCall from '../utils/fileInputCall';
import supportsFileInput from '../utils/supportsFileInput';
import compressImage from '../../utils/compressImage';

/**
 * Accepts specified file types via dialog or drag and drop.
 */
export default class FileInput extends PureComponent {
    constructor(props) {
        super(props);
        this.itemRefs = [];
        this.fileInputRefs = [];
        this.needAppCall = !supportsFileInput();
        this.state = {
            hasMemoryAccess: !(
                chayns.env.isAndroid &&
                (chayns.env.isApp || chayns.env.isMyChaynsApp) &&
                (chayns.env.myChaynsAppVersion || chayns.env.appVersion) >= 6244
            ),
        };
    }

    onDragEnter = (event, item, index) => {
        if (this.checkFileType(event.dataTransfer.items[0].type, item.types)) {
            this.itemRefs[index].classList.add('cc__file-input--hover');
        }
    };

    onDragLeave = (index) => {
        this.itemRefs[index].classList.remove('cc__file-input--hover');
    };

    onError = (item, errorMessage) => {
        if (isFunction(item.onError)) {
            return item.onError(errorMessage);
        }
        return chayns.dialog.alert('', errorMessage);
    };

    onChange = async (event, item, index) => {
        const { errorMessages } = this.props;
        const { files } = event.target;
        this.onDragLeave(index);
        if (files && files.length > 0) {
            const invalidFiles = [];
            const validFiles = [];
            for (let i = 0, l = files.length; i < l; i++) {
                const file = files[i];
                if (!this.checkFileType(file.type, item.types)) {
                    invalidFiles.push(file);
                    this.onError(item, errorMessages.wrongFileType);
                } else if (
                    item.maxNumberOfFiles > 0 &&
                    validFiles.length >= item.maxNumberOfFiles
                ) {
                    invalidFiles.push(file);
                    this.onError(
                        item,
                        errorMessages.tooMuchFiles.replace(
                            '##NUMBER##',
                            item.maxNumberOfFiles
                        )
                    );
                } else if (
                    item.maxFileSize > 0 &&
                    file.size > item.maxFileSize
                ) {
                    // eslint-disable-next-line no-await-in-loop
                    await compressImage(file, item.maxFileSize)
                        .then((result) => validFiles.push(result))
                        .catch(() => {
                            this.onError(
                                item,
                                errorMessages.fileTooBig.replace(
                                    '##SIZE##',
                                    `${Math.ceil(
                                        item.maxFileSize / (1024 * 1024)
                                    )} MB`
                                )
                            );
                            invalidFiles.push(file);
                        });
                } else {
                    validFiles.push(file);
                }
            }
            item.onChange(validFiles, invalidFiles);
        }
        this.fileInputRefs[index].value = null;
    };

    onClick = async (event, item, index) => {
        const { hasMemoryAccess } = this.state;
        const { stopPropagation, errorMessages } = this.props;
        if (stopPropagation) event.stopPropagation();
        if (isFunction(item.onClick)) item.onClick(event);
        if (item.onChange) {
            if (this.needAppCall) {<commit_msg>:bug: Fix usage of compress image for non-image files<commit_after>/**
 * @component
 */

import classNames from 'clsx';
import PropTypes from 'prop-types';
import React, { PureComponent } from 'react';
import Icon from '../../react-chayns-icon/component/Icon';
import { isFunction } from '../../utils/is';
import fileInputCall from '../utils/fileInputCall';
import supportsFileInput from '../utils/supportsFileInput';
import compressImage from '../../utils/compressImage';

/**
 * Accepts specified file types via dialog or drag and drop.
 */
export default class FileInput extends PureComponent {
    constructor(props) {
        super(props);
        this.itemRefs = [];
        this.fileInputRefs = [];
        this.needAppCall = !supportsFileInput();
        this.state = {
            hasMemoryAccess: !(
                chayns.env.isAndroid &&
                (chayns.env.isApp || chayns.env.isMyChaynsApp) &&
                (chayns.env.myChaynsAppVersion || chayns.env.appVersion) >= 6244
            ),
        };
    }

    onDragEnter = (event, item, index) => {
        if (this.checkFileType(event.dataTransfer.items[0].type, item.types)) {
            this.itemRefs[index].classList.add('cc__file-input--hover');
        }
    };

    onDragLeave = (index) => {
        this.itemRefs[index].classList.remove('cc__file-input--hover');
    };

    onError = (item, errorMessage) => {
        if (isFunction(item.onError)) {
            return item.onError(errorMessage);
        }
        return chayns.dialog.alert('', errorMessage);
    };

    onChange = async (event, item, index) => {
        const { errorMessages } = this.props;
        const { files } = event.target;
        this.onDragLeave(index);
        if (files && files.length > 0) {
            const invalidFiles = [];
            const validFiles = [];
            for (let i = 0, l = files.length; i < l; i++) {
                const file = files[i];
                if (!this.checkFileType(file.type, item.types)) {
                    invalidFiles.push(file);
                    this.onError(item, errorMessages.wrongFileType);
                } else if (
                    item.maxNumberOfFiles > 0 &&
                    validFiles.length >= item.maxNumberOfFiles
                ) {
                    invalidFiles.push(file);
                    this.onError(
                        item,
                        errorMessages.tooMuchFiles.replace(
                            '##NUMBER##',
                            item.maxNumberOfFiles
                        )
                    );
                } else if (
                    item.maxFileSize > 0 &&
                    file.size > item.maxFileSize
                ) {
                    if (file.type?.startsWith('image')) {
                        try {
                            // eslint-disable-next-line no-await-in-loop
                            const result = await compressImage(
                                file,
                                item.maxFileSize
                            );
                            validFiles.push(result);
                            // eslint-disable-next-line no-continue
                            continue;
                        } catch {
                            // fallback to error dialog for too big files
                        }
                    }
                    this.onError(
                        item,
                        errorMessages.fileTooBig.replace(
                            '##SIZE##',
                            `${Math.ceil(item.maxFileSize / (1024 * 1024))} MB`
                        )
                    );
                    invalidFiles.push(file);
                } else {
                    validFiles.push(file);
                }
            }
            item.onChange(validFiles, invalidFiles);
        }
        this.fileInputRefs[index].value = null;
    };

    onClick = async (event, item, index) => {
        const { hasMemoryAccess } = this.state;
        const { stopPropagation, errorMessages } = this.props;
        if (stopPropagation) event.stopPropagation();
        if (isFunction(item.onClick)) item.onClick(event);
        if (item.onChange) {
            if (this.needAppCall) {
{'fraction_non_alphanumeric': 0.11525875651436189, 'fraction_numerical': 0.004120712640892013, 'mean_word_length': 1.28840820854132, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2762505', 'n_tokens_mistral': 2166, 'n_tokens_neox': 2068, 'n_words': 399}