mirror of
https://github.com/janishutz/fundamentals-of-webengineering.git
synced 2025-11-25 05:44:24 +00:00
Task 3: Backend
This commit is contained in:
@@ -1,9 +1,9 @@
|
|||||||
import "./App.css";
|
import "./css/App.css";
|
||||||
import '@fortawesome/fontawesome-free/css/all.css';
|
import '@fortawesome/fontawesome-free/css/all.css';
|
||||||
import { readCSV } from './csv';
|
import { readCSV } from './csv';
|
||||||
import { CSV_Data, fileInfo } from './types';
|
import { CSV_Data, fileInfo } from './types';
|
||||||
|
|
||||||
import React, { useState } from "react";
|
import React, { useState, useRef } from "react";
|
||||||
import Layout from "./Layout";
|
import Layout from "./Layout";
|
||||||
import CSVCard from "./components/CSVCard";
|
import CSVCard from "./components/CSVCard";
|
||||||
import InfoCard from "./components/InfoCard";
|
import InfoCard from "./components/InfoCard";
|
||||||
@@ -18,6 +18,8 @@ function App() {
|
|||||||
rowcount: 0
|
rowcount: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const formRef = useRef(null);
|
||||||
|
|
||||||
// This is triggered in CSVCard
|
// This is triggered in CSVCard
|
||||||
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>): Promise<void> => {
|
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>): Promise<void> => {
|
||||||
const file = e.target.files?.[0];
|
const file = e.target.files?.[0];
|
||||||
@@ -33,11 +35,22 @@ function App() {
|
|||||||
}
|
}
|
||||||
setInfo(newFileInfo);
|
setInfo(newFileInfo);
|
||||||
setData(data);
|
setData(data);
|
||||||
|
|
||||||
|
if (formRef.current) {
|
||||||
|
// Upload to server
|
||||||
|
const formData = new FormData(formRef.current);
|
||||||
|
const res = await fetch("/upload", {
|
||||||
|
method: "POST",
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
const result = await res.json();
|
||||||
|
console.log(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<CSVCard handleChange={handleFileChange}></CSVCard>
|
<CSVCard handleChange={handleFileChange} formRef={formRef}></CSVCard>
|
||||||
<InfoCard info={info}></InfoCard>
|
<InfoCard info={info}></InfoCard>
|
||||||
<DataTable data={data}></DataTable>
|
<DataTable data={data}></DataTable>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import "./Layout.css";
|
import "./css/Layout.css";
|
||||||
|
|
||||||
const Layout = (props: { children: React.ReactNode }) => {
|
const Layout = (props: { children: React.ReactNode }) => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import "../Layout.css";
|
import "../css/Layout.css";
|
||||||
|
|
||||||
const CSVCard = (props: {
|
const CSVCard = (props: {
|
||||||
handleChange: (e: React.ChangeEvent<HTMLInputElement>) => void
|
handleChange: (e: React.ChangeEvent<HTMLInputElement>) => void,
|
||||||
|
formRef: React.RefObject<HTMLFormElement>
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<article>
|
<article>
|
||||||
<header>
|
<header>
|
||||||
<h2>Select CSV data</h2>
|
<h2>Select CSV data</h2>
|
||||||
</header>
|
</header>
|
||||||
<form>
|
<form ref={props.formRef} action="/upload" method="post" encType="multipart/form-data" >
|
||||||
<label htmlFor="file-input" className="custom-file-upload">
|
<label htmlFor="file-input" className="custom-file-upload">
|
||||||
<i className="fa fa-file-csv"></i> Select CSV file to explore
|
<i className="fa fa-file-csv"></i> Select CSV file to explore
|
||||||
</label>
|
</label>
|
||||||
<input id="file-input" type="file" aria-describedby="fileHelp" accept="text/csv" onChange={props.handleChange}/>
|
<input id="file-input" type="file" name="dataFile" aria-describedby="fileHelp" accept="text/csv" onChange={props.handleChange}/>
|
||||||
<small>Please upload a CSV file, where the first row is the header.</small>
|
<small>Please upload a CSV file, where the first row is the header.</small>
|
||||||
</form>
|
</form>
|
||||||
</article>
|
</article>
|
||||||
|
|||||||
@@ -35,30 +35,37 @@ const DataTable = (props: {data: CSV_Data}) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<table id="table-content">
|
<article className="table-container">
|
||||||
<thead>
|
<header>
|
||||||
<tr>
|
<h2>Data table</h2>
|
||||||
{
|
</header>
|
||||||
header.map( (col) => (
|
<div className="table-scroll-wrapper">
|
||||||
<ColHeader col={col} sortingHandle={sortingHandler} isSelected={col == sortCol} sortType={sortType}></ColHeader>
|
<table id="table-content">
|
||||||
))
|
<thead>
|
||||||
}
|
<tr>
|
||||||
</tr>
|
{
|
||||||
</thead>
|
header.map( (col) => (
|
||||||
<tbody>
|
<ColHeader col={col} sortingHandle={sortingHandler} isSelected={col == sortCol} sortType={sortType}></ColHeader>
|
||||||
{
|
))
|
||||||
props.data.map( (row, i) => (
|
}
|
||||||
<tr key={i}>
|
|
||||||
{
|
|
||||||
header.map( (col) => (
|
|
||||||
<Row col={col} content={row[col] as String}></Row>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</tr>
|
</tr>
|
||||||
))
|
</thead>
|
||||||
}
|
<tbody>
|
||||||
</tbody>
|
{
|
||||||
</table>
|
props.data.map( (row, i) => (
|
||||||
|
<tr key={i}>
|
||||||
|
{
|
||||||
|
header.map( (col) => (
|
||||||
|
<Row col={col} content={row[col] as String}></Row>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</tr>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import "../Layout.css";
|
|
||||||
import { fileInfo } from "../types";
|
import { fileInfo } from "../types";
|
||||||
|
|
||||||
const InfoCard = (props: {
|
const InfoCard = (props: {
|
||||||
|
|||||||
@@ -1,10 +1,27 @@
|
|||||||
import express from "express";
|
import express from "express";
|
||||||
import ViteExpress from "vite-express";
|
import ViteExpress from "vite-express";
|
||||||
|
import multer from "multer";
|
||||||
|
|
||||||
// creates the expres app do not change
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
// add your routes here
|
const storage = multer.diskStorage({
|
||||||
|
destination: "./src/server/uploads",
|
||||||
|
filename: (_req, file, cb) => {
|
||||||
|
// Suggested in Multer's readme
|
||||||
|
const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1E9);
|
||||||
|
cb(null, file.fieldname + "-" + uniqueSuffix)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const upload = multer({ storage: storage });
|
||||||
|
|
||||||
|
app.post(
|
||||||
|
"/upload",
|
||||||
|
upload.single("dataFile"),
|
||||||
|
(req, res, next) => {
|
||||||
|
console.log(req, res, next)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
// example route which returns a message
|
// example route which returns a message
|
||||||
app.get("/hello", async function (_req, res) {
|
app.get("/hello", async function (_req, res) {
|
||||||
|
|||||||
6421
task_3_react/src/server/uploads/dataFile-1763300594057-221106251
Normal file
6421
task_3_react/src/server/uploads/dataFile-1763300594057-221106251
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user