-
Notifications
You must be signed in to change notification settings - Fork 2
08 Upload UI
JP Barbosa edited this page Sep 24, 2022
·
15 revisions
code ./frontend/src/components/Upload.tsx
import React, { useEffect } from "react";
import AWS from "aws-sdk";
import * as uuid from "uuid";
import { useAppContext } from "../contexts/AppContext";
import { useUpload } from "../hooks/useUpload";
import { Status } from "./Status";
const { VITE_API_REGION, VITE_API_BUCKET_NAME, VITE_API_IDENTITY_POOL_ID } =
import.meta.env;
const credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: VITE_API_IDENTITY_POOL_ID,
});
export const Upload: React.FC = () => {
const { uploadId, setUploadId, setSelectedItem } = useAppContext();
useEffect(() => {
if (!uploadId) {
resetState();
}
}, [uploadId]);
const { uploading, uploadFile, uploadError, upload, resetState } = useUpload({
region: VITE_API_REGION,
credentials,
bucket: VITE_API_BUCKET_NAME,
});
const handleUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
if (!e.target.files) {
return;
}
const [file] = e.target.files;
const id = uuid.v1();
setSelectedItem(undefined);
setUploadId(undefined);
await upload({
file,
id,
callback: () => {
setUploadId(id);
},
});
};
return (
<div id="upload">
<Status
status={[
{
condition: uploading,
message: "Uploading...",
},
]}
/>
<h2>Upload</h2>
<form>
<input
type="file"
accept="image/*"
onChange={handleUpload}
multiple={false}
/>
</form>
<div className="scrollable">
{uploadFile && (
<div className="file">
<div className="box success">{uploadFile.name}</div>
<img src={URL.createObjectURL(uploadFile)} />
</div>
)}
{uploadError && (
<div className="box error">
<pre>{JSON.stringify(uploadError, null, 4)}</pre>
</div>
)}
<div className="box info">
Only the last uploaded image will be displayed. Files are
automatically removed from S3 after processing.
</div>
</div>
</div>
);
};
code ./frontend/src/hooks/useUpload.ts
import { useState } from "react";
import AWS from "aws-sdk";
type UseUploadParams = {
region: string;
credentials: AWS.Credentials;
bucket: string;
};
type UploadParams = {
id: string;
file: File;
callback?: Function;
};
export const useUpload = ({ region, credentials, bucket }: UseUploadParams) => {
const [uploading, setUploading] = useState(false);
const [uploadFile, setUploadFile] = useState<File>();
const [uploadError, setUploadError] = useState<AWS.AWSError>();
AWS.config.update({
region,
credentials,
});
const s3 = new AWS.S3({
params: {
Bucket: bucket,
},
});
const resetState = () => {
setUploading(false);
setUploadFile(undefined);
setUploadError(undefined);
};
const upload = async ({ file, id, callback }: UploadParams) => {
resetState();
try {
setUploading(true);
await s3
.upload({
Bucket: bucket,
Key: id,
Body: file,
})
.promise();
setUploadFile(file);
if (callback) callback();
} catch (error) {
const awsError = error as AWS.AWSError;
setUploadError(awsError);
} finally {
setUploading(false);
}
};
return {
resetState,
upload,
uploading,
uploadFile,
uploadError,
};
};
code ./frontend/src/App.tsx
...
import { Upload } from "./components/Upload";
function App() {
return (
<div id="app">
<AppContextProvider>
<Header />
<div className="content">
<Upload />
</div>
</AppContextProvider>
</div>
);
}
export default App;
npm start
(cd ./frontend && npm run dev)
A credentials error will be throw, which will be addressed in the next chapter.
git add .
git commit -m "Upload UI"