Browse Source

Custom CSV parser for fixing parsing issues and manual

master
Denis Thiessen 10 months ago
parent
commit
c470241f09
  1. 122
      src/components/SingleFileUpload.jsx
  2. 4
      src/components/TimelineAreaChart.jsx
  3. 15
      src/index.js

122
src/components/SingleFileUpload.jsx

@ -1,52 +1,43 @@
import React, { useState, useEffect } from "react"
import csv from "csvtojson"
import PropTypes from "prop-types"
export var fileContent = "{}";
var uploadFailed = false;
export var fileContent = "{}"
var uploadFailed = false
function SingleFileUpload({ onFileUploaded }) {
const [, setFile] = useState()
const [fileUploaded, setFileUploaded] = useState(false);
const [fileUploaded, setFileUploaded] = useState(false)
useEffect(() => {
if (fileUploaded) {
onFileUploaded()
}
if(uploadFailed && !fileUploaded) {
onFileUploaded();
if (uploadFailed && !fileUploaded) {
onFileUploaded()
}
}, [fileUploaded])
// Reads file.
var readCallback = function (content) {
csv()
.fromString(content)
.preRawData((csvRawData) => {
if(!checkCSVValidity(csvRawData)) {
alert("Invalid CSV File");
uploadFailed = true;
setFileUploaded(false);
fileContent = {};
return "{}";
var readCallback = function (csvRawData) {
if (!checkCSVValidity(csvRawData)) {
alert("Invalid CSV File")
uploadFailed = true
setFileUploaded(false)
fileContent = {}
return "{}"
}
csvRawData = csvRawData.replaceAll("Start Date", "Start_Date");
csvRawData = csvRawData.replaceAll("Start Time", "Start_Time");
csvRawData = csvRawData.replaceAll("End Date", "End_Date");
csvRawData = csvRawData.replaceAll("End Time", "End_Time");
csvRawData = csvRawData.replaceAll("Duration (decimal)", "Duration_Decimal");
uploadFailed = false;
csvRawData = csvRawData.replaceAll("Start Date", "Start_Date")
csvRawData = csvRawData.replaceAll("Start Time", "Start_Time")
csvRawData = csvRawData.replaceAll("End Date", "End_Date")
csvRawData = csvRawData.replaceAll("End Time", "End_Time")
csvRawData = csvRawData.replaceAll("Duration (decimal)", "Duration_Decimal")
uploadFailed = false
return csvRawData
})
.then((csvRow) => {
if(!uploadFailed) {
fileContent = csvRow;
setFileUploaded(true);
if (!uploadFailed) {
fileContent = csvJSON(csvRawData)
setFileUploaded(true)
}
})
}
function handleChange(event) {
@ -56,11 +47,11 @@ function SingleFileUpload({ onFileUploaded }) {
const reader = new FileReader()
reader.readAsText(changedFile)
reader.onload = function (evt) {
var uploadedFile = document.getElementById('fileInput').files[0];
var uploadedFile = document.getElementById("fileInput").files[0]
if (uploadedFile.type != "application/vnd.ms-excel") {
alert("Wrong file type");
fileContent = "{}";
return;
alert("Wrong file type")
fileContent = "{}"
return
}
readCallback(evt.target.result)
}
@ -76,19 +67,58 @@ function SingleFileUpload({ onFileUploaded }) {
)
}
function csvJSON(csvText) {
let lines = []
const linesArray = csvText.split("\n")
// for trimming and deleting extra space
linesArray.forEach((e) => {
const row = e.replace(/[\s]+[,]+|[,]+[\s]+/g, ",").trim()
lines.push(row)
})
// for removing empty record
lines.splice(lines.length - 1, 1)
const result = []
const headers = lines[0].split(",")
for (let i = 1; i < lines.length; i++) {
const obj = {}
const currentline = lines[i].split(",")
for (let j = 0; j < headers.length; j++) {
obj[headers[j]] = currentline[j]
}
result.push(obj)
}
var resultString = JSON.stringify(result)
resultString = resultString.replaceAll('\\"', "")
return JSON.parse(resultString)
}
function checkCSVValidity(rawCSV) {
const containsProjectKey = rawCSV.includes("\"Project\"");
const containsDescriptionKey = rawCSV.includes("\"Description\"");
const containsTaskKey = rawCSV.includes("\"Task\"");
const containsUserKey = rawCSV.includes("\"User\"");
const containsStartDateKey = rawCSV.includes("\"Start Date\"");
const containsStartTimeKey = rawCSV.includes("\"Start Time\"");
const containsEndDateKey = rawCSV.includes("\"End Date\"");
const containsEndTimeKey = rawCSV.includes("\"End Time\"");
const containsDurationHourKey = rawCSV.includes("\"Duration (h)\"");
const containsDurationDecimalKey = rawCSV.includes("\"Duration (decimal)\"");
return containsProjectKey && containsDescriptionKey && containsTaskKey && containsUserKey && containsStartDateKey && containsStartTimeKey && containsEndDateKey && containsEndTimeKey && containsDurationHourKey && containsDurationDecimalKey;
const containsProjectKey = rawCSV.includes('"Project"')
const containsDescriptionKey = rawCSV.includes('"Description"')
const containsTaskKey = rawCSV.includes('"Task"')
const containsUserKey = rawCSV.includes('"User"')
const containsStartDateKey = rawCSV.includes('"Start Date"')
const containsStartTimeKey = rawCSV.includes('"Start Time"')
const containsEndDateKey = rawCSV.includes('"End Date"')
const containsEndTimeKey = rawCSV.includes('"End Time"')
const containsDurationHourKey = rawCSV.includes('"Duration (h)"')
const containsDurationDecimalKey = rawCSV.includes('"Duration (decimal)"')
return (
containsProjectKey &&
containsDescriptionKey &&
containsTaskKey &&
containsUserKey &&
containsStartDateKey &&
containsStartTimeKey &&
containsEndDateKey &&
containsEndTimeKey &&
containsDurationHourKey &&
containsDurationDecimalKey
)
}
SingleFileUpload.propTypes = {

4
src/components/TimelineAreaChart.jsx

@ -4,8 +4,8 @@ import HighchartsReact from "highcharts-react-official"
import { fileContent } from "./SingleFileUpload"
// Date, Map
var projectDataMap = new Map();
var allSeriesEnabled = true;
var projectDataMap = new Map()
var allSeriesEnabled = true
export default function AreaChart() {
const chartComponent = useRef(null)

15
src/index.js

@ -3,17 +3,17 @@ import ReactDOM from "react-dom/client"
import "./index.css"
import TimelineAreaChart from "./components/TimelineAreaChart"
import TotalPieChart from "./components/TotalPieChart"
import SingleFileUploader, {fileContent} from "./components/SingleFileUpload"
import SingleFileUploader, { fileContent } from "./components/SingleFileUpload"
import { GeistProvider, CssBaseline, Tabs } from "@geist-ui/core"
export default function App() {
const [fileUploaded, setFileUploaded] = useState(false)
const handleUploadedFile = function () {
if(Array.isArray(fileContent)) {
setFileUploaded(true);
if (Array.isArray(fileContent)) {
setFileUploaded(true)
} else {
setFileUploaded(false);
setFileUploaded(false)
}
}
@ -23,6 +23,13 @@ export default function App() {
<Tabs initialValue="1">
<Tabs.Item label="Upload File" value="1">
<SingleFileUploader onFileUploaded={handleUploadedFile} />
<br />
<hr />
<h3>How to upload a file</h3>
<p>
Go to Clockify Reports Summary Time Report (Detailed) Export (As
a CSV file)
</p>
</Tabs.Item>
<Tabs.Item label="Project timeline" value="2" disabled={!fileUploaded}>
<TimelineAreaChart />

Loading…
Cancel
Save