last changed
parent
9d6f948c51
commit
71b88f91d8
@ -1,8 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
# Datasource local storage ignored files
|
|
||||||
/dataSources/
|
|
||||||
/dataSources.local.xml
|
|
||||||
# Editor-based HTTP Client requests
|
|
||||||
/httpRequests/
|
|
@ -1,5 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<state>
|
|
||||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
|
||||||
</state>
|
|
||||||
</component>
|
|
@ -1,11 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
|
||||||
<data-source source="LOCAL" name="hamza@dev.teamortix.com" uuid="84aa8c1d-dc47-44b7-8255-6c8c16c0c001">
|
|
||||||
<driver-ref>postgresql</driver-ref>
|
|
||||||
<synchronize>true</synchronize>
|
|
||||||
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
|
||||||
<jdbc-url>jdbc:postgresql://dev.teamortix.com:5432/hamza</jdbc-url>
|
|
||||||
</data-source>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -1,7 +0,0 @@
|
|||||||
<component name="ProjectDictionaryState">
|
|
||||||
<dictionary name="dev">
|
|
||||||
<words>
|
|
||||||
<w>navbar</w>
|
|
||||||
</words>
|
|
||||||
</dictionary>
|
|
||||||
</component>
|
|
@ -1,11 +0,0 @@
|
|||||||
<component name="InspectionProjectProfileManager">
|
|
||||||
<profile version="1.0">
|
|
||||||
<option name="myName" value="Project Default" />
|
|
||||||
<inspection_tool class="CssInvalidAtRule" enabled="false" level="ERROR" enabled_by_default="false" />
|
|
||||||
<inspection_tool class="ES6CheckImport" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
|
||||||
<inspection_tool class="JSCheckFunctionSignatures" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
|
||||||
<inspection_tool class="JSUnresolvedFunction" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
|
||||||
<inspection_tool class="JSUnresolvedVariable" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
|
||||||
<inspection_tool class="JSUnusedGlobalSymbols" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
||||||
</profile>
|
|
||||||
</component>
|
|
@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="JavaScriptSettings">
|
|
||||||
<option name="languageLevel" value="JSX" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectRootManager">
|
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/raintrack-ui.iml" filepath="$PROJECT_DIR$/raintrack-ui.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -0,0 +1,243 @@
|
|||||||
|
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 Admin({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)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log(authState)
|
||||||
|
if (!authState.loggedIn) history.push("/login?return=admin")
|
||||||
|
if (!authState.admin) history.push("/")
|
||||||
|
}, [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 Admin;
|
||||||
|
|
||||||
|
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>
|
||||||
|
}
|
@ -0,0 +1,241 @@
|
|||||||
|
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>
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
table{border-collapse:collapse}caption{padding-top:0.75rem;padding-bottom:0.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}.table{width:100%;max-width:100%;margin-bottom:1rem;background-color:transparent}.table td,.table th{padding:0.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table td{border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table .table{background-color:#fff}.table-sm td,.table-sm th{padding:0.3rem}.table-bordered{border:1px solid #dee2e6}.table-bordered td,.table-bordered th{border:1px solid #dee2e6}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{background-color:rgba(0,0,0,.075)}.table-primary,.table-primary > td,.table-primary > th{background-color:#b8daff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover > td,.table-hover .table-primary:hover > th{background-color:#9fcdff}.table-secondary,.table-secondary > td,.table-secondary > th{background-color:#d6d8db}.table-hover .table-secondary:hover{background-color:#c8cbcf}.table-hover .table-secondary:hover > td,.table-hover .table-secondary:hover > th{background-color:#c8cbcf}.table-success,.table-success > td,.table-success > th{background-color:#c3e6cb}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover > td,.table-hover .table-success:hover > th{background-color:#b1dfbb}.table-info,.table-info > td,.table-info > th{background-color:#bee5eb}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover > td,.table-hover .table-info:hover > th{background-color:#abdde5}.table-warning,.table-warning > td,.table-warning > th{background-color:#ffeeba}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover > td,.table-hover .table-warning:hover > th{background-color:#ffe8a1}.table-danger,.table-danger > td,.table-danger > th{background-color:#f5c6cb}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover > td,.table-hover .table-danger:hover > th{background-color:#f1b0b7}.table-light,.table-light > td,.table-light > th{background-color:#fdfdfe}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover > td,.table-hover .table-light:hover > th{background-color:#ececf6}.table-dark,.table-dark > td,.table-dark > th{background-color:#c6c8ca}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover > td,.table-hover .table-dark:hover > th{background-color:#b9bbbe}.table-active,.table-active > td,.table-active > th{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover > td,.table-hover .table-active:hover > th{background-color:rgba(0,0,0,.075)}.table .thead-dark th{color:#fff;background-color:#212529;border-color:#32383e}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#dee2e6}.table-dark{color:#fff;background-color:#212529}.table-dark td,.table-dark th,.table-dark thead th{border-color:#32383e}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-dark.table-hover tbody tr:hover{background-color:rgba(255,255,255,.075)}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive > .table-bordered{border:0}.table-borderless tbody+tbody,.table-borderless td,.table-borderless th,.table-borderless thead th{border:0}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-sm > .table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-sm > .table-bordered{border:0}}@media (max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-sm > .table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-sm > .table-bordered{border:0}}
|
Loading…
Reference in New Issue