Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

feat(bulk-upload): add table for last uploads #654

Merged
merged 2 commits into from
Sep 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions client/src/components/Upload/Table/index.jsx
Original file line number Diff line number Diff line change
@@ -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)),
Comment on lines +21 to +25
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL about Intl - very good usage 👏

},
status: { name: "Status" },
info: { name: "Info" },
failedRecordsUrl: {
name: "Assets",
formatter: (url) =>
url ? (
<a href={url} target="_blank" rel="noopener noreferrer">
Download
</a>
) : (
"N/A"
),
},
};

return state === TABLE_STATES.LOADING_LAST_UPLOADS ? (
<div className={style.content}>
<h1 className={style.title}>Loading last uploads...</h1>
</div>
) : (
data.length > 0 && (
<div className={style.content}>
<h1 className={style.title}>Past 24 Hours Upload Status</h1>
<table className={style.tableContent}>
<tr>
{_.map(_.values(columns), ({ name }) => (
<th>{name}</th>
))}
</tr>
{_.map(data, (item) => (
<tr>
{_.map(_.keys(columns), (colKey) => (
<td>
{columns[colKey].formatter
? columns[colKey].formatter(item[colKey])
: item[colKey] || "N/A"}
</td>
))}
</tr>
))}
</table>
</div>
)
);
}

Table.propTypes = {
state: PT.any,
data: PT.array.isRequired,
};
53 changes: 53 additions & 0 deletions client/src/components/Upload/Table/style.module.scss
Original file line number Diff line number Diff line change
@@ -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;
}
}
78 changes: 55 additions & 23 deletions client/src/components/Upload/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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,
Expand All @@ -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 },
});

Expand All @@ -55,17 +62,17 @@ 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,
},
});
},
});

setState({
type: STATES.MESSAGE,
setUploadState({
type: UPLOAD_STATES.MESSAGE,
data: {
title: "Profiles uploaded successfully",
message:
Expand All @@ -77,33 +84,58 @@ 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 = (
<Message
message={state.data.message}
onClose={() => 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 = (
<Initial
onError={showError}
onUpload={upload}
templateId={templateId}
/>
);
break;
case STATES.UPLOADING:
content = <Progress progress={state.data.progress} />;
case UPLOAD_STATES.UPLOADING:
uploadSectionContent = <Progress progress={uploadState.data.progress} />;
break;
default:
throw Error("Invalid state");
}
return <Container>{content}</Container>;
return (
<div className={style.content}>
<Table state={tableState} data={lastUploads} />
<Container>{uploadSectionContent}</Container>
</div>
);
}

Upload.propTypes = {
Expand Down
8 changes: 8 additions & 0 deletions client/src/components/Upload/style.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.content {
background: #eee;
border-radius: 10px;
margin: auto;
position: relative;
user-select: none;
width: 80%;
}