mirror of
https://github.com/responsively-org/responsively-app
synced 2024-11-10 06:44:13 +00:00
feature
This commit is contained in:
parent
d205f0e272
commit
744cdff065
11 changed files with 148 additions and 3 deletions
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"devices": [
|
||||
{
|
||||
"id": "10007",
|
||||
"name": "iPhone XR",
|
||||
"width": 414,
|
||||
"height": 896,
|
||||
"dpi": 2,
|
||||
"capabilities": ["touch", "mobile"],
|
||||
"userAgent":
|
||||
"Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1",
|
||||
"type": "phone",
|
||||
"isTouchCapable": true,
|
||||
"isMobileCapable": true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -7,16 +7,35 @@ import {
|
|||
} from 'renderer/store/features/device-manager';
|
||||
import { CreateSuiteButton } from './CreateSuiteButton';
|
||||
import { Suite } from './Suite';
|
||||
import { useState } from 'react';
|
||||
|
||||
export const PreviewSuites = () => {
|
||||
const suites = useSelector(selectSuites);
|
||||
const activeSuite = useSelector(selectActiveSuite);
|
||||
|
||||
const [open, setOpen] = useState<boolean>(false);
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<p className="mb-6 flex items-center gap-2 text-lg">
|
||||
<div className="mb-6 flex items-center gap-2 text-lg">
|
||||
<Icon icon="heroicons:swatch" /> Preview Suites
|
||||
</p>
|
||||
<div className="space-between">
|
||||
<Button className="aspect-square w-16" onClick={() => setOpen(true)}>
|
||||
<Icon
|
||||
icon="mdi:folder-upload"
|
||||
fontSize={8}
|
||||
onClick={() => setOpen(true)}
|
||||
/>{' '}
|
||||
Import Devices
|
||||
</Button>
|
||||
<Button className="aspect-square" onClick={() => setOpen(true)}>
|
||||
<Icon
|
||||
icon="mdi:folder-download"
|
||||
fontSize={8}
|
||||
onClick={() => setOpen(true)}
|
||||
/>
|
||||
Export Devices
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex w-full items-center gap-4 overflow-x-auto">
|
||||
<div className="flex flex-shrink-0 gap-4">
|
||||
{suites.map((suite) => (
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { FileUploader } from './FileUploader';
|
||||
import useFileUpload from './hooks/useFileUpload';
|
||||
|
||||
jest.mock('./hooks/useFileUpload');
|
||||
|
||||
const mockHandleFileUpload = jest.fn();
|
||||
const mockHandleUpload = jest.fn();
|
||||
const mockResetUploadedFile = jest.fn();
|
||||
|
||||
describe('FileUploader', () => {
|
||||
beforeEach(() => {
|
||||
useFileUpload.mockReturnValue({
|
||||
uploadedFile: null,
|
||||
handleUpload: mockHandleUpload,
|
||||
resetUploadedFile: mockResetUploadedFile,
|
||||
});
|
||||
});
|
||||
|
||||
it('renders the component', () => {
|
||||
render(<FileUploader handleFileUpload={mockHandleFileUpload} />);
|
||||
expect(screen.getByText('Upload a File')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole('button', { name: /Remove file/i })
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls handleUpload when file input changes', () => {
|
||||
render(<FileUploader handleFileUpload={mockHandleFileUpload} />);
|
||||
const fileInput = screen.getByRole('textbox');
|
||||
fireEvent.change(fileInput, {
|
||||
target: { files: [new File(['content'], 'file.txt')] },
|
||||
});
|
||||
expect(mockHandleUpload).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('calls resetUploadedFile when remove button is clicked', () => {
|
||||
render(<FileUploader handleFileUpload={mockHandleFileUpload} />);
|
||||
const removeButton = screen.getByRole('button', { name: /Remove file/i });
|
||||
fireEvent.click(removeButton);
|
||||
expect(mockResetUploadedFile).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('calls handleFileUpload when uploadedFile is set', () => {
|
||||
const mockFile = new File(['content'], 'file.txt');
|
||||
useFileUpload.mockReturnValue({
|
||||
uploadedFile: mockFile,
|
||||
handleUpload: mockHandleUpload,
|
||||
resetUploadedFile: mockResetUploadedFile,
|
||||
});
|
||||
render(<FileUploader handleFileUpload={mockHandleFileUpload} />);
|
||||
expect(mockHandleFileUpload).toHaveBeenCalledWith(mockFile);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,29 @@
|
|||
import { useEffect } from 'react';
|
||||
import { Icon } from '@iconify/react';
|
||||
import useFileUpload from './useFileUpload';
|
||||
import Button from '../Button';
|
||||
|
||||
export const FileUploader = ({
|
||||
handleFileUpload,
|
||||
}: {
|
||||
handleFileUpload?: (file: File) => void;
|
||||
}) => {
|
||||
const { uploadedFile, handleUpload, resetUploadedFile } = useFileUpload();
|
||||
|
||||
useEffect(() => {
|
||||
if (uploadedFile && handleFileUpload) {
|
||||
handleFileUpload(uploadedFile);
|
||||
}
|
||||
}, [handleFileUpload, uploadedFile]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<h2>Upload a File</h2>
|
||||
<input type="file" onChange={handleUpload} multiple={false} />
|
||||
<Button onClick={resetUploadedFile}>
|
||||
<Icon icon="mdi:delete" fontSize={8} />
|
||||
Remove file
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
import { useState } from 'react';
|
||||
|
||||
const useFileUpload = () => {
|
||||
const [uploadedFile, setUploadedFile] = useState<File | null>(null);
|
||||
|
||||
const handleUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (event?.target?.files || event?.target?.files?.length) {
|
||||
setUploadedFile(event.target.files[0]);
|
||||
}
|
||||
};
|
||||
|
||||
const resetUploadedFile = () => {
|
||||
setUploadedFile(null);
|
||||
};
|
||||
|
||||
return {
|
||||
uploadedFile,
|
||||
handleUpload,
|
||||
resetUploadedFile,
|
||||
};
|
||||
};
|
||||
|
||||
export default useFileUpload;
|
|
@ -81,6 +81,8 @@ export const SettingsContent = ({ onClose }: Props) => {
|
|||
</>
|
||||
)}
|
||||
|
||||
<div>the import function</div>
|
||||
|
||||
<Button
|
||||
className="mt-6 px-5 py-1"
|
||||
onClick={onSave}
|
||||
|
|
Loading…
Reference in a new issue