Skip to content

Commit

Permalink
Merge pull request #2 from hotungkhanh/kan-25-26-27/spreadsheet-input…
Browse files Browse the repository at this point in the history
…-pages

kan-25-26-27/spreadsheet input pages
  • Loading branch information
NguyenDonLam authored Aug 24, 2024
2 parents 0c928b8 + 362f769 commit f93bea2
Show file tree
Hide file tree
Showing 25 changed files with 671 additions and 33 deletions.
1 change: 1 addition & 0 deletions frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
Expand Down
12 changes: 6 additions & 6 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "react-router-test",
"name": "frontend",
"private": true,
"version": "0.0.0",
"type": "module",
Expand All @@ -10,7 +10,7 @@
"preview": "vite preview"
},
"dependencies": {
"@emotion/react": "^11.13.0",
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
"@mui/base": "^5.0.0-beta.40",
"@mui/icons-material": "^5.16.7",
Expand Down
Binary file added frontend/src/assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions frontend/src/components/BackButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import { Button } from '@mui/material';

export default function BackButton() {
return (
<Button
variant='outlined'
startIcon={<ArrowBackIcon/>}
sx={{
color: 'white',
borderColor: 'white',
'&:hover': {
borderColor: 'white',
backgroundColor: 'rgba(255, 255, 255, 0.1)',
},
}}>
Back
</Button>
)
}
19 changes: 19 additions & 0 deletions frontend/src/components/DisplayFile.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Box } from "@mui/material";
import FilePresentIcon from "@mui/icons-material/FilePresent";

interface DisplayFileProps {
fileChosen: File | null;
}

export default function DisplayFile({fileChosen}: DisplayFileProps) {
if (fileChosen === null) {
return <Box/>;
} else {
return (
<Box>
<FilePresentIcon />
{fileChosen?.name}
</Box>
);
}
}
19 changes: 19 additions & 0 deletions frontend/src/components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Box } from "@mui/material";

export default function Footer({ children } : { children?: React.ReactNode }) {
const footerStyle = {
backgroundColor: "#f05a22",
textAlign: "center",
position: "fixed",
bottom: 0,
left: 0,
width: 100+"%",
height: 60+"px",
zIndex: 10000,
};

return (
<Box sx={footerStyle}>
{children}
</Box>);
}
21 changes: 21 additions & 0 deletions frontend/src/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Box } from "@mui/material";
import VIT_Logo from '../assets/logo.png';

export default function Header() {
const headerStyle = {
backgroundColor: "#F5F5f5",
color: "white",
padding: "20px",
textAlign: "left",
};
return (
<Box className="header" sx={headerStyle}>
<img
src={VIT_Logo}
alt="logo.exe"
width="150"
height="auto"
/>
</Box>
);
}
20 changes: 20 additions & 0 deletions frontend/src/components/NextButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
import { Button } from '@mui/material';

export default function NextButton() {
return (
<Button
variant='outlined'
endIcon={<ArrowForwardIcon/>}
sx={{
color: 'white',
borderColor: 'white',
'&:hover': {
borderColor: 'white',
backgroundColor: 'rgba(255, 255, 255, 0.1)',
},
}}>
Next
</Button>
)
}
15 changes: 15 additions & 0 deletions frontend/src/components/ProceedButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Button from "@mui/material/Button"
import { useNavigate } from "react-router-dom";

interface ProceedButtonProps {
fileChosen: File | null;
}

export default function ProceedButton({ fileChosen }:ProceedButtonProps) {
const navigate = useNavigate();
if (fileChosen === null) {
return <Button disabled> Proceed </Button>
} else {
return <Button onClick={() => navigate("/seminfo/campus")}> Proceed</Button>;
}
}` `
10 changes: 8 additions & 2 deletions frontend/src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,23 @@ import InboxIcon from "@mui/icons-material/MoveToInbox";

import { Link } from "react-router-dom";


interface SidebarProps {
marginTop: number,
width: number,
}
const drawerWidth = 240;

export default function Sidebar() {
export default function Sidebar({ marginTop, width }: SidebarProps) {
return (
<Drawer
sx={{
width: drawerWidth,
width: width,
flexShrink: 0,
"& .MuiDrawer-paper": {
width: drawerWidth,
boxSizing: "border-box",
marginTop: marginTop,
},
}}
variant="permanent"
Expand Down
189 changes: 189 additions & 0 deletions frontend/src/components/Spreadsheet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import { useRef, useEffect } from "react";
import jspreadsheet, { CellValue, JspreadsheetInstance, JspreadsheetInstanceElement, JSpreadsheetOptions } from "jspreadsheet-ce";
import "../../node_modules/jspreadsheet-ce/dist/jspreadsheet.css";
import "../styles/spreadsheet.css"
import Button from "@mui/material/Button";

interface SpreadsheetProps {
headers: string[];
storageKey: string;
}

type SavedSpreadsheetOpt = {
cellvalues: CellValue[][];
}

export default function Spreadsheet({ headers, storageKey }: SpreadsheetProps) {
const jRef = useRef<null | JspreadsheetInstanceElement>(null);

// spreadsheet init options: columns property
const columns = headers.map((headerName) => {
return { title: headerName, width: 200 };
});

// spreadsheet init options: contextMenu property
const contextMenu = (instance: JspreadsheetInstance, _col: string | null, row: string | null, _evn: PointerEvent) => {

var items: object[] = [];
if (row === null) {
return items;
}

if (!instance.options.text) {
return items;
}

// insert row before
items.push({
title: instance.options.text.insertANewRowBefore,
onclick: function () {
instance.insertRow(1, parseInt(row), 1);
}
});

// insert row after
items.push({
title: instance.options.text.insertANewRowAfter,
onclick: function () {
instance.insertRow(1, parseInt(row));
}
});

// delete selected rows
items.push({
title: instance.options.text.deleteSelectedRows,
onclick: function () {
instance.deleteRow(instance.getSelectedRows().length ? undefined : parseInt(row));
}
});

// clear value of selected cells
items.push({
title: "Clear selected cells",
onclick: function () {
const selectedCols = instance.getSelectedColumns();
const selectedRows = instance.getSelectedRows(true) as number[];
for (let i of selectedCols) {
for (let j of selectedRows) {
instance.setValueFromCoords(i, j, "", false);
}
}
}
});

return items;
};

// spreadsheet init: options
const options: jspreadsheet.JSpreadsheetOptions = {
columns: columns,
data: [[]],
minDimensions: [headers.length, 10],
minSpareRows: 1,
allowManualInsertColumn: false,
allowInsertColumn: false,
includeHeadersOnDownload: true,
tableOverflow: true,
tableWidth: '1150px',
tableHeight: '400px',
contextMenu: contextMenu,
// toolbar:[
// {
// type: 'i',
// id: 'undo',
// content: 'undo',
// onclick: function() {
// undo();
// }
// },
// {
// type: 'i',
// id: 'redo',
// content: 'redo',
// onclick: function() {
// redo();
// }
// },
// ],
};

// mount: create spreadsheet using data from sessionStorage (if exist),
// otherwise create a blank default.
useEffect(() => {
// console.log(`Mount ${storageKey}`);
if (jRef.current && !jRef.current.jspreadsheet) {
const savedSpreadsheetData = sessionStorage.getItem(storageKey);

if (savedSpreadsheetData) {
const ssd: SavedSpreadsheetOpt = JSON.parse(savedSpreadsheetData);
options.data = ssd.cellvalues;
}

jspreadsheet(jRef.current, options);
}
});

// unmount: save spreadsheet data to sessionStorage
useEffect(() => {
const instanceElem: JspreadsheetInstanceElement | null = jRef.current;

function cleanup() {
// console.log(`Unmount ${storageKey}`);
if (instanceElem) {
const newOpts: SavedSpreadsheetOpt = {
cellvalues: instanceElem.jspreadsheet.getData(),
};
sessionStorage.setItem(storageKey, JSON.stringify(newOpts));
}
else {
throw new Error(
"JspreadsheetInstanceElement is null"
)
}
}

return cleanup;
})

const addRow = () => {
if (jRef.current && jRef.current.jexcel) {
jRef.current.jexcel.insertRow();
}
};

// const undo = () => {
// if (jRef.current && jRef.current.jexcel) {
// jRef.current.jexcel.undo();
// }
// }

// const redo = () => {
// if (jRef.current && jRef.current.jexcel) {
// jRef.current.jexcel.redo();
// }
// }

return (
<div>
<div ref={jRef} />
<br />
<Button
variant="outlined"
size="small"
onClick={addRow}
sx={{
color: "black",
borderColor: "black",
'&:hover': {
color: "#f05a22",
borderColor: "#f05a22",
backgroundColor: 'rgba(255, 255, 255, 0.1)',
},
borderRadius: "3px",
marginTop: "5px",
}}>
Add new row
</Button>
</div >
);
}
Loading

0 comments on commit f93bea2

Please sign in to comment.