Skip to content

Commit

Permalink
Display errors before warnings (#33)
Browse files Browse the repository at this point in the history
Extend hitbox for downloading templates to the entire button and not the text

Update error page with download example link, extend design-system dropdown, set max height and overflow scroll

Update upload loader

Refactor error page - initial pass at breaking out the error page

Add successes and errors section headers

Reverse the loading and animation, replace with loading spinner and static text

Fix copy

Update comments, change component names, update affected components

Fix hasErrorsOrWarnings logic

More clean up - add comments

Fix warnings, move loading logic positioning, add useEffect to update selected system to fix bug

Update copy, update copy for 0 errors, and remove TODO

Move error/warning desc to own func

Change invalid metric to other, always render continue button

fix lint warning

Change Continue to Review button

Co-authored-by: Mahmoud <mahmoud@Mahmouds-MBP.cable.rcn.com>
  • Loading branch information
mxosman and Mahmoud authored Sep 23, 2022
1 parent 3a6fd0a commit 22f267a
Show file tree
Hide file tree
Showing 9 changed files with 341 additions and 178 deletions.
74 changes: 59 additions & 15 deletions publisher/src/components/DataUpload/DataUpload.styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export const ButtonWrapper = styled.div`
margin: 13px 0;
`;

export const UploadErrorButtonWrapper = styled(ButtonWrapper)`
export const ErrorWarningButtonWrapper = styled(ButtonWrapper)`
width: 100%;
justify-content: space-between;
Expand Down Expand Up @@ -258,7 +258,7 @@ export const Button = styled.div<{ type?: ButtonTypes }>`
}
`;

export const DownloadTemplateBox = styled.div`
export const DownloadTemplateBox = styled.a`
${typography.sizeCSS.normal};
display: flex;
align-items: center;
Expand All @@ -270,7 +270,15 @@ export const DownloadTemplateBox = styled.div`
border: 1px solid ${palette.highlight.grey4};
border-radius: 4px;
a {
&:hover {
background: ${palette.highlight.grey1};
}
`;

export const DownloadTemplateSystem = styled.div`
color: ${palette.solid.darkgrey};
span {
${typography.sizeCSS.small};
display: block;
width: fit-content;
Expand Down Expand Up @@ -360,7 +368,7 @@ export const DragDropContainer = styled.div<{ dragging?: boolean }>`
color: ${palette.solid.white};
`;

export const UserPromptContainer = styled.div`
export const Container = styled.div`
width: 100%;
min-height: 100%;
display: flex;
Expand All @@ -370,7 +378,7 @@ export const UserPromptContainer = styled.div`
padding-bottom: 80px;
`;

export const UserPromptWrapper = styled.div`
export const Wrapper = styled.div`
width: 100%;
max-width: 50%;
display: flex;
Expand All @@ -379,11 +387,11 @@ export const UserPromptWrapper = styled.div`
align-items: flex-start;
`;

export const UserPromptTitle = styled.div`
export const Title = styled.div`
${typography.sizeCSS.title};
`;

export const UserPromptDescription = styled.div`
export const ErrorWarningDescription = styled.div`
${typography.sizeCSS.medium};
margin: 8px 0;
Expand All @@ -392,13 +400,20 @@ export const UserPromptDescription = styled.div`
}
`;

export const UserPromptErrorContainer = styled.div`
export const MessagesContainer = styled.div`
width: 100%;
margin-top: 19px;
`;

export const UserPromptError = styled.div`
margin-bottom: 40px;
export const Message = styled.div``;

export const SectionHeader = styled.div`
${typography.sizeCSS.title};
margin: 10px 0;
&:not(:first-child) {
margin: 40px 0 10px 0;
}
`;

export const MetricTitle = styled.div`
Expand All @@ -418,28 +433,28 @@ export const MetricTitle = styled.div`
}
`;

export const ErrorIconWrapper = styled.div`
export const IconWrapper = styled.div`
display: flex;
align-items: center;
gap: 5px;
`;
export const ErrorMessageWrapper = styled.div`
export const MessageBody = styled.div`
${typography.sizeCSS.medium};
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
`;

export const ErrorMessageTitle = styled.div`
export const MessageTitle = styled.div`
display: block;
`;

export const ErrorMessageDescription = styled.div`
export const MessageSubtitle = styled.div`
display: block;
`;

export const ErrorAdditionalInfo = styled.div`
export const MessageDescription = styled.div`
${typography.sizeCSS.normal};
margin: 8px 0 13px 0;
`;
Expand Down Expand Up @@ -530,3 +545,32 @@ export const OrangeText = styled.span`
export const StrikethroughText = styled.span`
text-decoration: line-through;
`;

export const BlueText = styled.span`
color: ${palette.solid.blue};
`;

export const DataUploadLoading = styled.div`
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
`;

export const LoadingHeader = styled.div`
${typography.sizeCSS.large};
display: flex;
margin: 20px 0 5px 0;
gap: 3px;
`;

export const LoadingSubheader = styled.div`
${typography.sizeCSS.normal};
`;

export const CheckIcon = styled.img`
width: 16px;
margin-right: 5px;
`;
97 changes: 67 additions & 30 deletions publisher/src/components/DataUpload/DataUpload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,30 @@
// =============================================================================

import { observer } from "mobx-react-lite";
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";

import { AgencySystems } from "../../shared/types";
import { useStore } from "../../stores";
import logoImg from "../assets/jc-logo-vector.png";
import { Logo, LogoContainer } from "../Header";
import { Loading } from "../Loading";
import { Loader } from "../Loading";
import { showToast } from "../Toast";
import {
Button,
DataUploadContainer,
DataUploadHeader,
DataUploadLoading,
LoadingHeader,
LoadingSubheader,
SystemSelection,
UploadFile,
} from ".";
import {
DataUploadResponseBody,
ErrorsWarningsMetrics,
MetricErrors,
UploadedMetric,
} from "./types";
import { UploadErrorsWarnings } from "./UploadErrorsWarnings";

Expand Down Expand Up @@ -82,6 +86,7 @@ export const systemToTemplateSpreadsheetFileName: { [system: string]: string } =
export const DataUpload: React.FC = observer(() => {
const { userStore, reportStore } = useStore();
const navigate = useNavigate();
// eslint-disable-next-line react-hooks/exhaustive-deps
const userSystems =
userStore.currentAgency?.systems.filter(
(system) => !EXCLUDED_SYSTEMS.includes(system)
Expand All @@ -93,7 +98,7 @@ export const DataUpload: React.FC = observer(() => {
const [selectedFile, setSelectedFile] = useState<File>();
const [selectedSystem, setSelectedSystem] = useState<
AgencySystems | undefined
>(userSystems.length === 1 ? userSystems[0] : undefined);
>();

const handleFileUpload = async (
file: File,
Expand All @@ -118,12 +123,15 @@ export const DataUpload: React.FC = observer(() => {
const data = await response?.json();

const errorsWarningsAndMetrics = processUploadResponseBody(data);
const hasErrorsOrWarnings =
(errorsWarningsAndMetrics.preIngestErrors &&
errorsWarningsAndMetrics.preIngestErrors.length > 0) ||
errorsWarningsAndMetrics.errorSheetsAndSuccessfulMetrics.errorSheets
.length > 0 ||
errorsWarningsAndMetrics.errorSheetsAndSuccessfulMetrics.hasWarnings;
setIsLoading(false);

if (
errorsWarningsAndMetrics.errorCount ||
errorsWarningsAndMetrics.warningCount
) {
if (hasErrorsOrWarnings) {
return setErrorsWarningsMetrics(errorsWarningsAndMetrics);
}

Expand All @@ -137,35 +145,56 @@ export const DataUpload: React.FC = observer(() => {
const processUploadResponseBody = (
data: DataUploadResponseBody
): ErrorsWarningsMetrics => {
const metricErrors = data.metrics.reduce(
(acc, metric) => [...acc, ...metric.sheets],
[] as MetricErrors[]
);
const errorWarningCount = metricErrors.reduce(
(acc, sheet) => {
sheet.messages.forEach((msg) => {
if (msg.type === "ERROR") acc.errorCount += 1;
if (msg.type === "WARNING") acc.warningCount += 1;
const errorSheetsAndSuccessfulMetrics = data.metrics.reduce(
(acc, metric) => {
/**
* Peek into the `messages` array to look for any error messages within
* the sheet and return `true` if no errors are found
*/
const noErrorsInCurrentSheet =
metric.sheets.filter(
(sheet) =>
sheet.messages.filter((msg) => msg.type === "ERROR").length > 0
).length === 0;

if (metric.sheets.length === 0 || noErrorsInCurrentSheet) {
acc.successfulMetrics.push(metric);
}

metric.sheets.forEach((sheet) => {
sheet.messages.forEach((message) => {
if (message.type === "ERROR") {
acc.errorSheets.push(sheet);
}
if (message.type === "WARNING" && acc.hasWarnings === false) {
acc.hasWarnings = true;
}
});
});

return acc;
},
{
errorCount: 0,
warningCount: 0,
successfulMetrics: [] as UploadedMetric[],
errorSheets: [] as MetricErrors[],
hasWarnings: false,
}
);

/**
* Pre-Ingest errors: errors that are not associated with a metric.
* @example: user uploads an excel file that contains a sheet not associated
* with a metric.
*/
if (data.pre_ingest_errors) {
errorWarningCount.errorCount += data.pre_ingest_errors.length;
return {
metricErrors,
...errorWarningCount,
errorSheetsAndSuccessfulMetrics,
metrics: data.metrics,
preIngestErrors: data.pre_ingest_errors,
};
}

return { metricErrors, ...errorWarningCount, metrics: data.metrics };
return { errorSheetsAndSuccessfulMetrics, metrics: data.metrics };
};

const handleSystemSelection = (file: File, system: AgencySystems) => {
Expand All @@ -181,14 +210,6 @@ export const DataUpload: React.FC = observer(() => {
setSelectedSystem(userSystems.length === 1 ? userSystems[0] : undefined);
};

if (isLoading) {
return (
<DataUploadContainer>
<Loading />
</DataUploadContainer>
);
}

const renderCurrentUploadStep = (): JSX.Element => {
/**
* There are ~4 steps in the upload phase before reaching the metrics confirmation page.
Expand Down Expand Up @@ -241,6 +262,22 @@ export const DataUpload: React.FC = observer(() => {
);
};

useEffect(() => {
setSelectedSystem(userSystems.length === 1 ? userSystems[0] : undefined);
}, [userSystems]);

if (isLoading) {
return (
<DataUploadContainer>
<DataUploadLoading>
<Loader />
<LoadingHeader>We are processing your data...</LoadingHeader>
<LoadingSubheader>This might take a few minutes.</LoadingSubheader>
</DataUploadLoading>
</DataUploadContainer>
);
}

return (
<DataUploadContainer>
<DataUploadHeader transparent={!selectedFile && !errorsWarningsMetrics}>
Expand Down
18 changes: 9 additions & 9 deletions publisher/src/components/DataUpload/InstructionsTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { ReactComponent as SpreadsheetIcon } from "../assets/microsoft-excel-ico
import {
ButtonWrapper,
DownloadTemplateBox,
DownloadTemplateSystem,
systemToTemplateSpreadsheetFileName,
} from ".";

Expand Down Expand Up @@ -202,18 +203,17 @@ export const GeneralInstructions: React.FC<
const systemFileName = systemToTemplateSpreadsheetFileName[system];

return (
<DownloadTemplateBox key={system}>
<DownloadTemplateBox
key={system}
href={`./assets/${systemFileName}`}
download={systemFileName}
>
<SpreadsheetIcon />

<span>
<DownloadTemplateSystem>
{systemName}
<a
href={`./assets/${systemFileName}`}
download={systemFileName}
>
Download
</a>
</span>
<span>Download</span>
</DownloadTemplateSystem>
</DownloadTemplateBox>
);
})}
Expand Down
Loading

0 comments on commit 22f267a

Please sign in to comment.