diff --git a/client/src/components/Upload/Table/index.jsx b/client/src/components/Upload/Table/index.jsx
new file mode 100644
index 0000000..7b37f87
--- /dev/null
+++ b/client/src/components/Upload/Table/index.jsx
@@ -0,0 +1,76 @@
+/**
+ * Content of the Table component.
+ */
+
+import React from "react";
+import PT from "prop-types";
+import _ from "lodash";
+
+import style from "./style.module.scss";
+
+export const TABLE_STATES = {
+ LOADING_LAST_UPLOADS: "LOADING_LAST_UPLOADS",
+ RESULT: "RESULT",
+};
+
+export default function Table({ state, data }) {
+ const columns = {
+ created: {
+ name: "Upload Date",
+ formatter: (date) =>
+ new Intl.DateTimeFormat("en", {
+ year: "numeric",
+ month: "short",
+ day: "2-digit",
+ }).format(new Date(date)),
+ },
+ status: { name: "Status" },
+ info: { name: "Info" },
+ failedRecordsUrl: {
+ name: "Assets",
+ formatter: (url) =>
+ url ? (
+
+ Download
+
+ ) : (
+ "N/A"
+ ),
+ },
+ };
+
+ return state === TABLE_STATES.LOADING_LAST_UPLOADS ? (
+
+
Loading last uploads...
+
+ ) : (
+ data.length > 0 && (
+
+
Past 24 Hours Upload Status
+
+
+ {_.map(_.values(columns), ({ name }) => (
+ {name} |
+ ))}
+
+ {_.map(data, (item) => (
+
+ {_.map(_.keys(columns), (colKey) => (
+
+ {columns[colKey].formatter
+ ? columns[colKey].formatter(item[colKey])
+ : item[colKey] || "N/A"}
+ |
+ ))}
+
+ ))}
+
+
+ )
+ );
+}
+
+Table.propTypes = {
+ state: PT.any,
+ data: PT.array.isRequired,
+};
diff --git a/client/src/components/Upload/Table/style.module.scss b/client/src/components/Upload/Table/style.module.scss
new file mode 100644
index 0000000..e7fd9e1
--- /dev/null
+++ b/client/src/components/Upload/Table/style.module.scss
@@ -0,0 +1,53 @@
+.content {
+ margin-top: 15px;
+ margin-bottom: 15px;
+}
+
+.title {
+ text-align: center;
+ color: #252526;
+ font: 500 14pt Inter;
+}
+
+.tableContent {
+ margin-top: 15px;
+ margin-bottom: 15px;
+ margin-left: auto;
+ margin-right: auto;
+ width: 70%;
+}
+
+table {
+ font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
+ border-collapse: collapse;
+}
+
+th {
+ padding-top: 12px;
+ padding-bottom: 12px;
+ text-align: center;
+ background-color: #3cd656;
+ color: white;
+}
+
+td {
+ border: 1px solid #ddd;
+ padding: 8px;
+ text-align: center;
+}
+
+tr:nth-child(even) {
+ background-color: #f2f2f2;
+}
+tr:hover {
+ background-color: #ddd;
+}
+
+a {
+ color: #30a2c7;
+ text-decoration: none;
+ &:hover {
+ color: #56ccf2;
+ text-decoration: underline;
+ }
+}
diff --git a/client/src/components/Upload/index.jsx b/client/src/components/Upload/index.jsx
index e364533..708296d 100644
--- a/client/src/components/Upload/index.jsx
+++ b/client/src/components/Upload/index.jsx
@@ -4,15 +4,18 @@ import FormData from "form-data";
import PT from "prop-types";
import Container from "./Container";
+import Table, { TABLE_STATES } from "./Table";
import Initial from "./Initial";
import Message from "./Message";
import Progress from "./Progress";
+import style from "./style.module.scss";
+
import config from "../../config";
import api from "../../services/api";
import { getSingleOrg } from "../../services/user-org";
-const STATES = {
+const UPLOAD_STATES = {
INITIAL: "INITIAL",
MESSAGE: "MESSAGE",
RESULT: "RESULT",
@@ -21,15 +24,19 @@ const STATES = {
export default function Upload({ templateId }) {
const apiClient = api();
- const [state, setState] = React.useState({
- type: STATES.INITIAL,
+ const [uploadState, setUploadState] = React.useState({
+ type: UPLOAD_STATES.INITIAL,
data: null,
});
+ const [tableState, setTableState] = React.useState(
+ TABLE_STATES.LOADING_LAST_UPLOADS
+ );
+ const [lastUploads, setLastUploads] = React.useState([]);
const showError = (error) => {
const { message } = error.toJSON ? error.toJSON() : error;
- setState({
- type: STATES.MESSAGE,
+ setUploadState({
+ type: UPLOAD_STATES.MESSAGE,
data: {
title: "Error Occured",
message,
@@ -44,8 +51,8 @@ export default function Upload({ templateId }) {
data.append("upload", file);
data.append("organizationId", getSingleOrg());
- setState({
- type: STATES.UPLOADING,
+ setUploadState({
+ type: UPLOAD_STATES.UPLOADING,
data: { progress: 0 },
});
@@ -55,8 +62,8 @@ export default function Upload({ templateId }) {
"Content-Type": "multipart/form-data",
},
onUploadProgress: ({ loaded, total }) => {
- setState({
- type: STATES.UPLOADING,
+ setUploadState({
+ type: UPLOAD_STATES.UPLOADING,
data: {
progress: loaded / total,
},
@@ -64,8 +71,8 @@ export default function Upload({ templateId }) {
},
});
- setState({
- type: STATES.MESSAGE,
+ setUploadState({
+ type: UPLOAD_STATES.MESSAGE,
data: {
title: "Profiles uploaded successfully",
message:
@@ -77,19 +84,39 @@ export default function Upload({ templateId }) {
}
};
- let content;
- switch (state.type) {
- case STATES.MESSAGE:
- content = (
+ React.useEffect(() => {
+ async function fetchUploads() {
+ const url = `${config.API_PREFIX}/uploads`;
+
+ setTableState(TABLE_STATES.LOADING_LAST_UPLOADS);
+
+ try {
+ const { data } = await apiClient.get(url);
+
+ setTableState(TABLE_STATES.RESULT);
+ console.log("response", data);
+ setLastUploads(data);
+ } catch (error) {
+ setTableState(TABLE_STATES.RESULT);
+ setLastUploads([]);
+ }
+ }
+ fetchUploads();
+ }, [apiClient]);
+
+ let uploadSectionContent;
+ switch (uploadState.type) {
+ case UPLOAD_STATES.MESSAGE:
+ uploadSectionContent = (
setState({ type: STATES.INITIAL })}
- title={state.data.title}
+ message={uploadState.data.message}
+ onClose={() => setUploadState({ type: UPLOAD_STATES.INITIAL })}
+ title={uploadState.data.title}
/>
);
break;
- case STATES.INITIAL:
- content = (
+ case UPLOAD_STATES.INITIAL:
+ uploadSectionContent = (
);
break;
- case STATES.UPLOADING:
- content = ;
+ case UPLOAD_STATES.UPLOADING:
+ uploadSectionContent = ;
break;
default:
throw Error("Invalid state");
}
- return {content};
+ return (
+
+
+
{uploadSectionContent}
+
+ );
}
Upload.propTypes = {
diff --git a/client/src/components/Upload/style.module.scss b/client/src/components/Upload/style.module.scss
new file mode 100644
index 0000000..da79ddf
--- /dev/null
+++ b/client/src/components/Upload/style.module.scss
@@ -0,0 +1,8 @@
+.content {
+ background: #eee;
+ border-radius: 10px;
+ margin: auto;
+ position: relative;
+ user-select: none;
+ width: 80%;
+}