From 178d59dc131249bb5bc371525c6af886b7ff149e Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 16 Aug 2024 15:00:29 -0700 Subject: [PATCH] added upload progress and upload errors to entity input --- src/website/package.json | 1 + .../src/api/MakeMultipartRequest.ts | 52 +++++++------ .../src/api/media_files/UploadVideoMedia.ts | 15 +++- .../entities/EntityInput/EntityInput.scss | 31 ++++++++ .../entities/EntityInput/EntityInput.tsx | 74 +++++++++++++++++-- .../svg/DashedCircle/DashedCircle.tsx | 3 +- .../svg/WorkIndicator/WorkIndicator.tsx | 3 + .../useMediaUploader/useMediaUploader.tsx | 17 ++++- src/website/yarn.lock | 40 ++++++++++ 9 files changed, 203 insertions(+), 33 deletions(-) diff --git a/src/website/package.json b/src/website/package.json index c5f197810d..1f390d46c1 100644 --- a/src/website/package.json +++ b/src/website/package.json @@ -35,6 +35,7 @@ "@react-spring/types": "^9.7.3", "@typeform/embed": "^4.8.1", "@types/dom-mediacapture-record": "^1.0.19", + "axios": "^1.7.4", "framer-motion": "6.5.1", "local-storage": "^2.0.0", "moment": "^2.29.4", diff --git a/src/website/packages/components/src/api/MakeMultipartRequest.ts b/src/website/packages/components/src/api/MakeMultipartRequest.ts index cdf891c84e..1af49d7c67 100644 --- a/src/website/packages/components/src/api/MakeMultipartRequest.ts +++ b/src/website/packages/components/src/api/MakeMultipartRequest.ts @@ -1,33 +1,39 @@ import GetApiHost from "./GetApiHost"; +import axios, { AxiosProgressEvent } from "axios"; -const { formatUrl, host = "" } = GetApiHost(); +const { formatUrl } = GetApiHost(); -const MakeMultipartRequest = (endpoint = "", body: any) => { +export type OnUploadProgress = (progressEvent: AxiosProgressEvent) => void; + +const MakeMultipartRequest = ( + endpoint = "", + body: any, + onUploadProgress?: OnUploadProgress +) => { const formData = new FormData(); - Object.keys(body).forEach((key) => formData.append(key, body[key])); + Object.keys(body).forEach(key => formData.append(key, body[key])); - formData.append('source', "file"); + formData.append("source", "file"); - return fetch(formatUrl(endpoint), { - method: 'POST', - credentials: 'include', + return axios + .post(formatUrl(endpoint), formData, { + withCredentials: true, headers: { - 'Accept': 'application/json', + Accept: "application/json", }, - body: formData, - }) - .then(res => res.json()) - .then(res => { - if (res && res.success) { - return res; - } else { - return { success : false }; - } - }) - .catch(e => { - return { success : false }; - }); -} + ...(onUploadProgress ? { onUploadProgress } : {}), + }) + .then(({ data }) => { + if (data && data.success) { + return data; + } else { + return { success: false }; + } + }) + .catch(e => { + return { success: false }; + }); +}; -export default MakeMultipartRequest; \ No newline at end of file +export default MakeMultipartRequest; diff --git a/src/website/packages/components/src/api/media_files/UploadVideoMedia.ts b/src/website/packages/components/src/api/media_files/UploadVideoMedia.ts index d0192f975d..ea68f1667b 100644 --- a/src/website/packages/components/src/api/media_files/UploadVideoMedia.ts +++ b/src/website/packages/components/src/api/media_files/UploadVideoMedia.ts @@ -1,4 +1,6 @@ -import MakeMultipartRequest from "../MakeMultipartRequest"; +import MakeMultipartRequest, { + OnUploadProgress, +} from "../MakeMultipartRequest"; export interface UploadVideoMediaRequest { file: any; @@ -15,6 +17,13 @@ export interface UploadVideoMediaResponse { success: boolean; } -export const UploadVideoMedia = (request: UploadVideoMediaRequest) => { - return MakeMultipartRequest("/v1/media_files/upload/new_video", request); +export const UploadVideoMedia = ( + request: UploadVideoMediaRequest, + onUploadProgress?: OnUploadProgress +) => { + return MakeMultipartRequest( + "/v1/media_files/upload/new_video", + request, + onUploadProgress + ); }; diff --git a/src/website/packages/fakeyou.com/src/components/entities/EntityInput/EntityInput.scss b/src/website/packages/fakeyou.com/src/components/entities/EntityInput/EntityInput.scss index 7c39e7fda4..81894f5e18 100644 --- a/src/website/packages/fakeyou.com/src/components/entities/EntityInput/EntityInput.scss +++ b/src/website/packages/fakeyou.com/src/components/entities/EntityInput/EntityInput.scss @@ -81,6 +81,26 @@ color: rgba(#fff, 0.5); pointer-events: none; } + + .fy-entity-input-progress-indicator { + align-items: center; + display: flex; + flex-direction: column; + position: relative; + + .fy-entity-input-progress-number { + position: absolute; + text-align: center; + font-size: 0.625rem; + line-height: 0.625rem; + height: 0.625rem; + top: 50%; + transform: translateY(-50%); + left: 0; + right: 0; + bottom: 0; + } + } } .fy-entity-input-landscape { @@ -135,6 +155,17 @@ padding: 0.5rem; } +.fy-entity-input-error { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + + button { + margin-top: 1rem; + } +} + .fy-entity-input-preview-controls { // background-color: green; display: grid; diff --git a/src/website/packages/fakeyou.com/src/components/entities/EntityInput/EntityInput.tsx b/src/website/packages/fakeyou.com/src/components/entities/EntityInput/EntityInput.tsx index f9212623f6..14e5ea5cb7 100644 --- a/src/website/packages/fakeyou.com/src/components/entities/EntityInput/EntityInput.tsx +++ b/src/website/packages/fakeyou.com/src/components/entities/EntityInput/EntityInput.tsx @@ -5,7 +5,12 @@ import useMeasure from "react-use-measure"; import { MediaFile } from "@storyteller/components/src/api/media_files/GetMedia"; import Iframe from "react-iframe"; import { Area, Point } from "react-easy-crop"; -import { Label, Spinner, ZoomSliderOnChangeEvent } from "components/common"; +import { + Button, + Label, + Spinner, + ZoomSliderOnChangeEvent, +} from "components/common"; import { AcceptTypes, EntityModeProp, @@ -13,6 +18,7 @@ import { MediaFilters, UploaderResponse, } from "components/entities/EntityTypes"; +import { WorkIndicator } from "components/svg"; import { useMedia, useMediaUploader } from "hooks"; import { BucketConfig } from "@storyteller/components/src/api/BucketConfig"; import { Prompt } from "@storyteller/components/src/api/prompts/GetPrompts"; @@ -52,6 +58,9 @@ export interface SlideProps { cropProps?: CropProps; isNarrow: boolean; media?: MediaFile; + resetUploader: () => void; + uploaderBusy: boolean; + uploadProgress: number; } interface AniProps { @@ -63,8 +72,47 @@ interface AniProps { style: any; } -const MediaBusy = () => { - return ; +const MediaError = ({ resetUploader }: SlideProps) => { + return ( + <> +

There was a problem with your upload

+