Skip to content

Commit

Permalink
Extract data skeleton (#200)
Browse files Browse the repository at this point in the history
* extractupload component

* added extract process and upload files

* split items into components and  fixed css

* removed previous elements

* revert annotateTemplate to main

---------

Co-authored-by: Arindam Kulshi <[email protected]>
  • Loading branch information
arinkulshi-skylight and arinkulshi authored Sep 4, 2024
1 parent 09f2b47 commit 394a22e
Show file tree
Hide file tree
Showing 7 changed files with 345 additions and 22 deletions.
64 changes: 64 additions & 0 deletions OCR/frontend/src/componets/ExtractDataHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React from "react";
import { Button, Icon, Header } from "@trussworks/react-uswds";

interface ExtractDataHeaderProps {
onBack: () => void;
onSubmit: () => void;
isUploadComplete: boolean;
}

export const ExtractDataHeader: React.FC<ExtractDataHeaderProps> = ({
onBack,
onSubmit,
isUploadComplete,
}) => {
return (
<Header style={{ height: "50px", padding: "8px" }}>
<div
className="display-flex height-full flex-align-center"
style={{ justifyContent: "space-between" }}
>
<div
className="display-flex flex-align-center"
style={{ justifyContent: "flex-start" }}
>
<Button
data-testid="close-button"
unstyled
type="button"
style={{ paddingRight: "8px" }}
onClick={onBack}
>
<Icon.Close size={3} color="black" />
</Button>
<h1>Extract data</h1>
</div>
<div className="display-flex flex-align-center">
<Button
onClick={onBack}
disabled={true}
type="reset"
outline
style={{
height: "40px",
boxShadow: "inset 0 0 0 2px #adadad",
color: "#adadad",
}}
>
Back
</Button>
<Button
onClick={onSubmit}
type="submit"
disabled={!isUploadComplete}
style={{ height: "40px", marginLeft: "8px" }}
>
Submit
</Button>
</div>
</div>
</Header>
);
};

export default ExtractDataHeader;
39 changes: 39 additions & 0 deletions OCR/frontend/src/componets/ExtractStepper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { StepIndicator, StepIndicatorStep } from "@trussworks/react-uswds";
import { ExtractStep } from "../utils/constants.ts";

export const ExtractStepper = ({
currentStep,
}: {
currentStep: ExtractStep;
}) => {
const stepOrder: ExtractStep[] = [
ExtractStep.Upload,
ExtractStep.Extract,
ExtractStep.Review,
ExtractStep.Submit,
];

const determineStatus = (step: ExtractStep, currentStep: ExtractStep) => {
const currentStepIndex = stepOrder.indexOf(currentStep);
const stepIndex = stepOrder.indexOf(step);
if (currentStepIndex > stepIndex) return "complete";
else if (currentStepIndex === stepIndex) return "current";
else return "incomplete";
};

return (
<StepIndicator
data-testid="step-indicator"
headingLevel="h5"
headingProps={{ style: { display: "none" } }}
>
{stepOrder.map((step: ExtractStep) => (
<StepIndicatorStep
key={step}
label={step}
status={determineStatus(step, currentStep)}
/>
))}
</StepIndicator>
);
};
143 changes: 143 additions & 0 deletions OCR/frontend/src/componets/ExtractUploadFile.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import React, { ChangeEvent, useId, useState } from "react";
import { Icon, FileInput } from "@trussworks/react-uswds";
import { useFiles } from "../contexts/FilesContext";

interface ExtractUploadFileProps {
onUploadComplete: (isComplete: boolean) => void;
}

interface IFilesObj {
files: File[];
}

export const ExtractUploadFile: React.FC<ExtractUploadFileProps> = ({
onUploadComplete,
}) => {
const id = useId();
const { addFile } = useFiles();
const [template, setTemplate] = useState<string>("");
const [uploadProgress, setUploadProgress] = useState<number>(0);
const [uploadedFile, setUploadedFile] = useState<File | null>(null);

const simulateFileUpload = (file: File) => {
let progress = 0;
const interval = setInterval(() => {
progress += 10;
setUploadProgress(progress);
if (progress >= 100) {
clearInterval(interval);
onUploadComplete(true);
addFile(file);
}
}, 200);
};

const handleTemplateChange = (event: {
target: { value: React.SetStateAction<string> };
}) => {
setTemplate(event.target.value);
};

const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
if (event.target.files && event.target.files.length > 0) {
const file = event.target.files[0];
setUploadedFile(file);
const filesObj: IFilesObj = { files: [file] };
localStorage.setItem("files", JSON.stringify(filesObj));
setUploadProgress(0);
simulateFileUpload(file);
onUploadComplete(false);
}
};

return (
<div className="display-flex flex-column flex-align-center flex-justify-start height-full width-full padding-2 bg-primary-lighter">
<div style={{ width: "70%", textAlign: "left" }}>
<h1 style={{ margin: 0 }}>Choose template and upload new form</h1>
</div>

<div
className="display-flex flex-column flex-justify-center flex-align-center"
style={{ width: "70%" }}
>
<label
htmlFor="template-select"
className="usa-label"
style={{ alignSelf: "flex-start" }}
>
Choose segmentation template
</label>
<select
id="template-select"
value={template}
onChange={handleTemplateChange}
className="usa-select"
style={{ alignSelf: "flex-start", width: "100%", maxWidth: "300px" }}
>
<option value="">Select Template</option>
<option value="COVID Quest V1">COVID Quest V1</option>
</select>
</div>

<div style={{ width: "70%", textAlign: "left" }}>
<h2 style={{ margin: 10 }}>
Upload new image or PDF to extract data from
</h2>
</div>

<div
data-testid="dashed-container"
className="display-flex flex-column margin-top-205 flex-justify flex-align-center bg-white"
style={{ width: "70%", height: "50%", border: "1px dashed #005ea2" }}
>
{!uploadedFile ? (
<>
<Icon.UploadFile
data-testid="upload-icon"
style={{ marginTop: "16px" }}
size={5}
color="#005ea2"
/>
<div
className="display-flex flex-column flex-align-center margin-bottom-1"
style={{ width: "60%" }}
>
<h3 style={{ fontWeight: "bold" }}>Drag and drop file here</h3>
<p>or</p>
<FileInput
onChange={handleChange}
id={`file-input-${id}`}
className="padding-bottom-1"
style={{ border: "1px dashed #005ea2" }}
name="file-input-single"
chooseText="Browse Files"
dragText=" "
/>
</div>
</>
) : (
<div>
<div className="display-flex flex-align-center margin-bottom-1">
<Icon.FilePresent
size={3}
className="margin-right-1 text-primary"
/>
<span className="margin-left-1 text-ink">
{uploadedFile.name} ({Math.round(uploadedFile.size / 1024)} KB)
- {uploadProgress}%
</span>
</div>

{uploadProgress >= 100 && (
<div className="text-center margin-top-2 text-green">
Upload complete!
</div>
)}
</div>
)}
</div>
</div>
);
};

export default ExtractUploadFile;
47 changes: 27 additions & 20 deletions OCR/frontend/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.tsx'
import './style/index.scss'
import {
createBrowserRouter,
RouterProvider,
} from "react-router-dom";
import { UploadTemplate } from './pages/UploadTemplate.tsx';
import { FilesProvider } from './contexts/FilesContext.tsx';
import AnnotateTemplate from './pages/AnnotateTemplate.tsx';
import './App.scss';
import { AnnotationProvider } from './contexts/AnnotationContext.tsx';
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import "./style/index.scss";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { UploadTemplate } from "./pages/UploadTemplate.tsx";
import { FilesProvider } from "./contexts/FilesContext.tsx";
import AnnotateTemplate from "./pages/AnnotateTemplate.tsx";
import "./App.scss";
import { AnnotationProvider } from "./contexts/AnnotationContext.tsx";
import ExtractUpload from "./pages/ExtractUpload.tsx";
import ExtractProcess from "./pages/ExtractProcess.tsx";

const router = createBrowserRouter([
{
Expand All @@ -24,15 +23,23 @@ const router = createBrowserRouter([
{
path: "/new-template/annotate",
element: <AnnotateTemplate />,
}
},
{
path: "/extract/upload",
element: <ExtractUpload />,
},
{
path: "/extract/process",
element: <ExtractProcess />,
},
]);

createRoot(document.getElementById('root')!).render(
createRoot(document.getElementById("root")!).render(
<StrictMode>
<AnnotationProvider>
<FilesProvider>
<RouterProvider router={router} />
</FilesProvider>
<FilesProvider>
<RouterProvider router={router} />
</FilesProvider>
</AnnotationProvider>
</StrictMode>,
)
</StrictMode>
);
27 changes: 27 additions & 0 deletions OCR/frontend/src/pages/ExtractProcess.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useNavigate } from "react-router-dom";
import ExtractDataHeader from "../componets/ExtractDataHeader";
import { Divider } from "../componets/Divider";
import { ExtractStepper } from "../componets/ExtractStepper";
import { ExtractStep } from "../utils/constants";

const ExtractProcess = () => {
const navigate = useNavigate();
return (
<>
<div className="display-flex flex-column flex-justify-start width-full height-full padding-1 padding-top-2">
<ExtractDataHeader
onBack={() => navigate("extract/upload")}
onSubmit={() => navigate("/")}
isUploadComplete={true}
/>
<Divider margin="0px" />
<div className="display-flex flex-justify-center padding-top-4">
<ExtractStepper currentStep={ExtractStep.Extract} />
</div>
<Divider margin="0px" />
</div>
</>
);
};

export default ExtractProcess;
37 changes: 37 additions & 0 deletions OCR/frontend/src/pages/ExtractUpload.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useNavigate } from "react-router-dom";
import ExtractDataHeader from "../componets/ExtractDataHeader";
import { Divider } from "../componets/Divider";
import { ExtractStep } from "../utils/constants";
import { ExtractUploadFile } from "../componets/ExtractUploadFile";
import { ExtractStepper } from "../componets/ExtractStepper";
import { useState } from "react";

const ExtractUpload = () => {
const navigate = useNavigate();
const [isUploadComplete, setIsUploadComplete] = useState<boolean>(false);

const handleUploadComplete = (isComplete: boolean) => {
setIsUploadComplete(isComplete);
};

return (
<div className="display-flex flex-column flex-justify-start width-full height-full padding-1 padding-top-2">
<ExtractDataHeader
onBack={() => navigate("/")}
onSubmit={() => navigate("/extract/process")}
isUploadComplete={isUploadComplete}
/>
<Divider margin="0px" />
<div className="display-flex flex-justify-center padding-top-4">
<ExtractStepper currentStep={ExtractStep.Upload} />
</div>
<Divider margin="0px" />
<div className="display-flex flex-column flex-justify-center width-full height-full">
<Divider margin="0px" />
<ExtractUploadFile onUploadComplete={handleUploadComplete} />
</div>
</div>
);
};

export default ExtractUpload;
10 changes: 8 additions & 2 deletions OCR/frontend/src/utils/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@

export enum AnnotateStep {
Upload = "Upload New Segment",
Annotate = "Annotate",
Save = "Save Template",
}
}

export enum ExtractStep {
Upload = "Choose and upload",
Extract = "Extract Data",
Review = "Review and edit",
Submit = "Submit Data",
}

0 comments on commit 394a22e

Please sign in to comment.