All files / src/components FileUploader.jsx

100% Statements 28/28
68.42% Branches 13/19
100% Functions 3/3
100% Lines 27/27

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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115                    26x 26x 26x 26x 26x 26x   26x 7x 7x   6x 6x   6x 6x 6x   5x         5x 5x         1x 1x         6x   6x 6x         26x   1x 1x   1x     26x                                                                                                          
import { useRef, useState, useCallback } from 'react';
import { useParametersActions, useParameters } from '../context/ParametersContext';
import { parseParameterFile } from '../simulation/fileReader';
import './FileUploader.css';
 
/**
 * File Uploader Component
 * Handles ReaxFF parameter file uploads
 */
function FileUploader() {
  const fileInputRef = useRef(null);
  const [status, setStatus] = useState({ type: '', message: '' });
  const [isLoading, setIsLoading] = useState(false);
  const [loadedFileName, setLoadedFileName] = useState('');
  const { setParameters } = useParametersActions();
  const parameters = useParameters();
 
  const handleFileChange = useCallback(async (event) => {
    const file = event.target.files?.[0];
    if (!file) return;
 
    setIsLoading(true);
    setStatus({ type: 'info', message: 'Loading parameters...' });
 
    try {
      const text = await file.text();
      const params = parseParameterFile(text);
      
      setParameters({
        r_ij: 1.2,
        ...params,
      });
 
      setLoadedFileName(file.name);
      setStatus({ 
        type: 'success', 
        message: `✓ ${file.name} loaded!` 
      });
    } catch (error) {
      console.error('Error parsing file:', error);
      setStatus({ 
        type: 'error', 
        message: `Error: ${error.message}` 
      });
    } finally {
      setIsLoading(false);
      // Reset input so same file can be uploaded again
      Eif (fileInputRef.current) {
        fileInputRef.current.value = '';
      }
    }
  }, [setParameters]);
 
  const handleClick = () => {
    // Reset the input value before clicking to ensure onChange fires even for same file
    Eif (fileInputRef.current) {
      fileInputRef.current.value = '';
    }
    fileInputRef.current?.click();
  };
 
  return (
    <div className={`file-uploader ${parameters.isLoaded ? 'loaded' : ''}`}>
      <h3>📁 Load Parameters</h3>
      
      <input
        ref={fileInputRef}
        type="file"
        accept=".ff,.txt,text/plain"
        onChange={handleFileChange}
        className="file-input-hidden"
      />
 
      {parameters.isLoaded ? (
        <div className="loaded-indicator">
          <div className="loaded-badge">
            <span className="check-icon">✓</span>
            <span className="loaded-text">ReaxFF Active</span>
          </div>
          <div className="loaded-file">{loadedFileName || 'Parameters loaded'}</div>
          <button 
            className="upload-button compact"
            onClick={handleClick}
            disabled={isLoading}
          >
            Load Different File
          </button>
        </div>
      ) : (
        <button 
          className="upload-button"
          onClick={handleClick}
          disabled={isLoading}
        >
          {isLoading ? '⟳ Loading...' : '⬆ Select ReaxFF File'}
        </button>
      )}
 
      {status.message && !parameters.isLoaded && (
        <div className={`status-message ${status.type}`}>
          {status.message}
        </div>
      )}
 
      {!parameters.isLoaded && (
        <p className="file-hint">
          Formats: <code>.ff</code> <code>.txt</code>
        </p>
      )}
    </div>
  );
}
 
export default FileUploader;