raintrack-ui/src/components/ViewOwn.js

241 lines
7.8 KiB
JavaScript

import React, {useCallback, useContext, useEffect, useReducer, useState} from 'react';
import Navbar from "./Navbar";
import {AuthContext} from "../App";
import Griddle, {ColumnDefinition, plugins, RowDefinition} from "griddle-react";
import {query} from "../auth";
import "flatpickr/dist/themes/material_blue.css";
import "../styles/tables.css"
import Flatpickr from "react-flatpickr";
import {Input} from "../custom";
import {toast} from "react-toastify";
import {AiFillDelete, AiFillEdit} from "react-icons/ai";
import Modal from "react-modal"
import FileManualForm from "./FileManualForm";
const background = require('../assets/wave.png')
const defaultData = () => [{
ID: "No Data Found",
Date: "",
Precipitation: "",
Latitude: "",
Longitude: "",
Remarks: "",
Edit: "",
}]
function MyData({history, ...props}) {
const {authState} = useContext(AuthContext)
const [data, setData] = useState(defaultData())
const [items, setItems] = useState(10)
const [status, setStatus] = useState("")
const initialDates = () => {
const now = new Date()
const lastYear = new Date();
lastYear.setFullYear(lastYear.getFullYear() - 1)
return [lastYear, now]
}
const [dateRange, setDateRange] = useState([]);
const [editModal, setEditModal] = useState({open: false, data: {}})
const [updateData, dispatchEdit] = useReducer((state, action) => action, [])
useEffect(() => {
const params = new URLSearchParams(props.location.search)
let range = initialDates()
if (params.get("after")) range[0] = new Date(params.get("after"))
if (params.get("before")) range[1] = new Date(params.get("before"))
setDateRange(range)
}, [props.location])
useEffect(() => {
if (!authState.loggedIn) history.push("/login?return=mydata")
}, [authState, history])
const deleteRow = async (data) => {
const {status, json} = await query("/data/delete", data).catch(e => {
console.debug(e)
return {status: 500, json: {reason: "The upload server is offline!"}}
})
console.debug("Delete Row Response", json)
return {status, json}
}
const initiateData = useCallback(async () => {
if (dateRange.length !== 2 || !authState.username) return
let after = dateRange[0]
let before = dateRange[1]
before.setDate(before.getDate() + 1)
after.setDate(after.getDate() - 1)
const now = new Date();
now.setDate(now.getDate() + 5)
const hundred = new Date(1900, 0, 0)
if (after > now || after < hundred ||
before > now || before < hundred)
return toast.error("Invalid Date Range!")
setStatus("Loading Data...")
let {json, status} = await query("/data/query", {
token: authState.token,
after_date: after,
before_date: before,
username: authState.username,
}).catch(() => ({status: 500, json: {reason: "The authentication server is offline!"}}))
setStatus("")
if (status !== 200) return toast.error(json.reason)
let newData = defaultData()
const formatDate = (date) => {
return date.getFullYear() + "-" + (date.getMonth() + 1).toString().padStart(2, "0") + "-" + date.getDate().toString().padStart(2, "0")
}
json.entries.forEach((entry, index) => {
const date = new Date(entry.date);
const group = json.groups.find(gr => gr.id === entry.group_id)
newData[index] = {
ID: entry.id,
Date: formatDate(date),
Precipitation: entry.precipitation,
Latitude: group.latitude,
Longitude: group.longitude,
Verified: group.validated ? "Yes" : "No",
Remarks: entry.remarks,
}
})
setData(newData)
before.setDate(before.getDate() - 1)
after.setDate(after.getDate() + 1)
window.history.pushState("Search", "Rain Track", "/mydata?after=" + formatDate(after) + "&before=" + formatDate(before))
}, [setData, authState.token, dateRange, authState.username])
useEffect(() => {
(async () => {
initiateData()
})();
}, [setData, initiateData, dateRange, authState.username])
const styleConfig = {
classNames: {
Filter: "input h-8",
Table: "table table-bordered table-hover table-striped lg:overflow-x-auto overflow-y-scroll",
PreviousButton: "border border-gray-300 px-2 py-1 w-20 mr-2 rounded",
NextButton: "border border-gray-300 px-2 py-1 w-20 rounded ml-2"
}
}
useEffect(() => {
if (updateData.length !== 0) {
const row = data[updateData[1]]
if (!row) return
switch (updateData[0]) {
case 0:
setEditModal({open: true, data: row})
break;
case 1:
window.confirm("Are you sure you would like to delete this row?")
&& (async () => {
let {json, status} = await deleteRow({token: authState.token, id: row.ID})
if (status !== 200) return toast.error(json.reason)
toast.success("Entry successfully deleted")
dispatchEdit([])
setData(data.filter(r => r !== row))
})()
break;
default:
break;
}
}
}, [updateData, data, authState])
return (
<div className="w-screen h-screen overflow-x-hidden bg-cover bg-center text-white flex items-center flex-col"
style={{backgroundImage: `url(${background})`}}>
<Navbar history={history} color={"text-blue-600"} hover={"hover:border-blue-600"}/>
<div className="container text-gray-700 bg-white p-6 mt-12 mb-32 rounded">
<div className="flex">
<Flatpickr
value={dateRange}
onChange={date => setDateRange(date)}
options={{
dateFormat: "m-d-Y",
mode: "range",
wrap: true,
position: "below"
}}>
<div className="w-72">
<Input name="date" type='text' others={{"data-input": true}} className="input h-8"
placeholder="Select Date Range">
Select Date Range
</Input>
</div>
</Flatpickr>
<div className="italic text-sm ml-4 w-full flex items-center">{status}</div>
</div>
<hr className="bg-gray-400 mb-4"/>
<Griddle data={data} plugins={[plugins.LocalPlugin]} styleConfig={styleConfig}
pageProperties={{
currentPage: 1,
pageSize: items
}}
components={{
Layout: Layout(setItems)
}}>
<RowDefinition>
<ColumnDefinition id="ID"/>
<ColumnDefinition id="Date" title="Date"/>
<ColumnDefinition id="Precipitation"/>
<ColumnDefinition id="Latitude"/>
<ColumnDefinition id="Longitude"/>
<ColumnDefinition id="Remarks"/>
<ColumnDefinition id="Verified"/>
<ColumnDefinition id=" "
customComponent={(items) => <EditComponent {...items} dispatch={dispatchEdit}/>}/>
</RowDefinition>
</Griddle>
</div>
<Modal
onRequestClose={() => setEditModal({open: false, data: {ID: 0}})}
shouldCloseOnOverlayClick
isOpen={editModal.open}>
<div className="flex justify-center">
<FileManualForm title={"Edit Data"} id={editModal.data.ID} editType defaultData={editModal.data}/>
</div>
</Modal>
</div>
);
}
export default MyData;
const Layout = (setItems) => (({Table, Filter, Pagination}) => (
<div>
<div className="flex w-96 pb-4 h-12 justify-between">
<Filter/>
<select onChange={e => setItems(Number(e.target.value))}>
<option value="10">Show 10 items</option>
<option value="20">Show 20 items</option>
<option value="50">Show 50 items</option>
<option value="100">Show 100 items</option>
</select>
</div>
<div className="lg:overflow-x-auto overflow-x-scroll">
<Table/>
</div>
<Pagination/>
</div>
))
const EditComponent = ({griddleKey, dispatch}) => {
return <div className="flex justify-around">
<span onClick={() => dispatch([0, griddleKey])}><AiFillEdit/></span>
<span onClick={() => dispatch([1, griddleKey])}><AiFillDelete/></span>
</div>
}