Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added visualization_tool/public/icons/filter.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added visualization_tool/public/icons/sort.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 16 additions & 3 deletions visualization_tool/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {useState} from 'react';
import {Resource} from './types/resources';
import {Resource, availableResourceTypes} from './types/resources';

import Navbar from './components/Navbar/Navbar';
import ControlMenu from './components/ControlMenu/ControlMenu';
Expand All @@ -8,12 +8,25 @@ import ResourcesList from './components/ResourcesList/ResourcesList';
function App() {
const [resources, setResources] = useState<Resource[]>([]);
const [searchQuery, setSearchQuery] = useState<string>('');
const [sortAttribute, setSortAttribute] = useState<string>('date');
const [allowedTypes, setAllowedTypes] = useState<string[]>(
availableResourceTypes
);
return (
<>
<Navbar searchQuery={searchQuery} setSearchQuery={setSearchQuery} />
<main>
<ControlMenu setResources={setResources} />
<ResourcesList resources={resources} searchQuery={searchQuery} />
<ControlMenu
setResources={setResources}
setSortAttribute={setSortAttribute}
setAllowedTypes={setAllowedTypes}
/>
<ResourcesList
resources={resources}
searchQuery={searchQuery}
sortAttribute={sortAttribute}
allowedTypes={allowedTypes}
/>
</main>
</>
);
Expand Down
16 changes: 14 additions & 2 deletions visualization_tool/src/components/ControlMenu/ControlMenu.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,29 @@

.menu-item {
width: 100%;
min-height: 180px;
min-height: 150px;
background-color: white;
border-radius: 5px;
padding: 20px 10px 30px 10px;
box-shadow: 0px 4px 6px 0px rgba(0, 0, 0, 0.15);
margin-bottom: 20px;
}

.menu-item__header {
display: flex;
align-items: center;
margin-bottom: 10px;
margin-bottom: 8px;
}

.menu-item__content {
display: flex;
margin-top: 20px;
flex-direction: column;
gap: 10px;
}

.menu-item__content label {
padding-left: 10px;
}

.menu-item h3 {
Expand Down
119 changes: 13 additions & 106 deletions visualization_tool/src/components/ControlMenu/ControlMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,120 +1,27 @@
import {useState, useRef} from 'react';
import AddIcon from '@mui/icons-material/Add';
import CloseIcon from '@mui/icons-material/Close';
// validate schema with joi
import UploadMenu from './partials/UploadMenu';
import SortMenu from './partials/SortMenu';
import FilterMenu from './partials/FilterMenu';

import {Resource} from '../../types/resources';

import {parseData} from './Controller';

import './ControlMenu.css';

type ControlMenuProps = {
setResources: React.Dispatch<React.SetStateAction<Resource[]>>;
setSortAttribute: React.Dispatch<React.SetStateAction<string>>;
setAllowedTypes: React.Dispatch<React.SetStateAction<string[]>>;
};

const ControlMenu = ({setResources}: ControlMenuProps) => {
const fileInput = useRef<HTMLInputElement>(null);
const [files, setFiles] = useState<string[]>([]);
const [error, setError] = useState<string | null>(null);

const ControlMenu = ({
setResources,
setSortAttribute,
setAllowedTypes,
}: ControlMenuProps) => {
return (
<div className="control-menu">
<div className="menu-item">
<div className="menu-item__header">
<span>
<img src="./icons/upload.png" alt="" />
</span>
<h3>Upload</h3>
</div>
<form
className="upload-form"
onSubmit={e => {
e.preventDefault();
setError(null);
const file = fileInput.current?.files?.[0];

if (!file) {
setError('No file selected');
return;
}
// check if file is already uploaded
if (files.includes(file.name)) {
setError('File already uploaded');
return;
}

const reader = new FileReader();
reader.readAsText(file);
reader.onload = e => {
const result = e.target?.result as string;

try {
const data = JSON.parse(result);
const resources = parseData(data, file.name);
setResources((prevResources: Resource[]) => [
...prevResources,
...resources,
]);
setFiles([...files, file.name]);
} catch (err) {
setError('Invalid file');
return;
}
};
}}
>
<input
type="file"
name=""
id=""
accept=".json"
ref={fileInput}
className="add-input"
/>
<button type="submit" className="add-button">
<AddIcon
sx={{
fontSize: '2rem',
color: '#4285F4',
}}
/>
</button>
</form>
{error && <p className="error">{error}</p>}
{files.length > 0 && (
<div className="files-list">
{files.map(file => (
<div className="file-item" key={file}>
<p>{file}</p>
<button
className="remove-button"
onClick={() => {
setFiles(prevFiles => {
return prevFiles.filter(prevFile => prevFile !== file);
});
setResources(prevResources => {
return prevResources.filter(
prevResource => prevResource.file !== file
);
});
}}
>
<CloseIcon
sx={{
fontSize: '20px',
color: '#505050',
hover: {
color: '#4285F4',
},
}}
/>
</button>
</div>
))}
</div>
)}
</div>
<UploadMenu setResources={setResources} />
<SortMenu setSortAttribute={setSortAttribute} />
<FilterMenu setAllowedTypes={setAllowedTypes} />
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {availableResourceTypes} from '../../../types/resources';

type FilterMenuProps = {
setAllowedTypes: React.Dispatch<React.SetStateAction<string[]>>;
};

const FilterMenu = ({setAllowedTypes}: FilterMenuProps) => {
return (
<div className="menu-item">
<div className="menu-item__header">
<span>
<img src="./icons/filter.png" alt="" />
</span>
<h3>Resource Type</h3>
</div>
{availableResourceTypes.length > 0 && (
<div className="menu-item__content">
{availableResourceTypes.map(type => {
return (
<div key={type}>
<input
type="checkbox"
name="resource-type"
id={type}
defaultChecked
onChange={e => {
if (e.target.checked) {
setAllowedTypes(prevTypes => [...prevTypes, type]);
} else {
setAllowedTypes(prevTypes => {
return prevTypes.filter(prevType => prevType !== type);
});
}
}}
/>
<label htmlFor={type}>{type}</label>
</div>
);
})}
</div>
)}
</div>
);
};

export default FilterMenu;
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
type SortMenuProps = {
setSortAttribute: React.Dispatch<React.SetStateAction<string>>;
};

const SortMenu = ({setSortAttribute}: SortMenuProps) => {
return (
<div className="menu-item">
<div className="menu-item__header">
<span>
<img src="./icons/sort.png" alt="" />
</span>
<h3>Sort</h3>
</div>
<div className="menu-item__content">
<div>
<input
type="radio"
name="sort-type"
id="sort-name"
value="name"
onChange={e => {
setSortAttribute(e.target.value);
}}
/>
<label htmlFor="sort-name">Name</label>
</div>

<div>
<input
type="radio"
name="sort-type"
id="sort-date"
defaultChecked
value="date"
onChange={e => {
setSortAttribute(e.target.value);
}}
/>
<label htmlFor="sort-date">Creation Date</label>
</div>
</div>
</div>
);
};

export default SortMenu;
Loading