import { useState , useEffect } from 'react' ; import Router from 'next/router' ; import * as UpChunk from '@mux/upchunk' ; import useSwr from 'swr' ; import Layout from './layout' ; import Button from './button' ; const fetcher = ( url ) => fetch ( url ) . then ( ( res ) => res . json ( ) ) ; const MAX_VIDEO_DURATION_MIN = 60 ; type Props = { file : File ; resetPage : ( ) => void ; } ; const UploadProgressFullpage = ( { file , resetPage } ) => { const [ isUploading , setIsUploading ] = useState ( false ) ; const [ uploadId , setUploadId ] = useState ( '' ) ; const [ progress , setProgress ] = useState ( 0 ) ; const [ isPreparing , setIsPreparing ] = useState ( false ) ; const [ errorMessage , setErrorMessage ] = useState ( '' ) ; const { data , error } = useSwr ( ( ) => ( isPreparing ? `/api/uploads/${ uploadId }` : null ) , fetcher , { refreshInterval : 5000 } ) ; const upload = data && data . upload ; const createUpload = async ( ) => { try { return fetch ( '/api/uploads' , { method : 'POST' , } ) . then ( ( res ) => res . json ( ) ) . then ( ( { id , url } ) => { setUploadId ( id ) ; return url ; } ) ; } catch ( e ) { console . error ( 'Error in createUpload' , e ) ; setErrorMessage ( 'Error creating upload' ) ; return Promise . reject ( e ) ; } } ; const startUpload = ( _file ) => { if ( isUploading ) { return ; } setIsUploading ( true ) ; try { const upChunk = UpChunk . createUpload ( { endpoint : createUpload , maxFileSize : 2 ** 20 , file : _file , } ) ; upChunk . on ( 'error' , ( err ) => { setErrorMessage ( err . detail ) ; } ) ; upChunk . on ( 'progress' , ( progressEvt ) => { setProgress ( Math . floor ( progressEvt . detail ) ) ; } ) ; upChunk . on ( 'success' , ( ) => { setIsPreparing ( true ) ; } ) ; } catch ( err ) { setErrorMessage ( err . toString ( ) ) ; } } ; useEffect ( ( ) => { if ( upload && upload . asset_id ) { Router . push ( { pathname : `/assets/${ upload . asset_id }` , } ) ; } } , [ upload ] ) ; const startFileValidation = ( _file ) : Promise < void > => { return new Promise ( ( resolve , reject ) => { if ( ! _file . type . includes ( "video" ) ) { console . warn ( `file type (${ _file . type }) does not look like video!` ) ; resolve ( ) ; } const video = document . createElement ( 'video' ) ; video . preload = 'metadata' ; video . onloadedmetadata = function ( ) { URL . revokeObjectURL ( video . src ) ; if ( video . duration !== Infinity && video . duration > MAX_VIDEO_DURATION_MIN * 60 ) { const dur = Math . round ( video . duration * 100 ) / 100 ; reject ( `file duration (${ dur . toString ( ) }s) exceeds allowed maximum (${ MAX_VIDEO_DURATION_MIN }min)!` ) ; } resolve ( ) ; } ; video . onerror = function ( ) { console . warn ( "failed to load video file metadata for validation!" ) ; URL . revokeObjectURL ( video . src ) ; resolve ( ) ; } ; video . src = URL . createObjectURL ( file ) ; } ) ; } ; useEffect ( ( ) => { if ( ! file ) { return ; } startFileValidation ( file ) . then ( ( ) => { startUpload ( file ) ; } ) . catch ( ( error => { setErrorMessage ( error ) ; } ) ) ; } , [ file ] ) ; return ( < Layout centered spinningLogo > { ( errorMessage || error ) ? < div > < h1 > Oops there was a problem uploading your file ! < /h1> < p > { ( error && 'Error fetching API' ) || errorMessage } < /p> < Button onClick = { resetPage } > Start over < /Button> < /div> : < div className = "percent" > < h1 > { progress ? `${ progress }` : '0' } < /h1></div > } < style jsx > { `
        .percent {
          flex-grow: 1;
          display: flex;
          align-items: center;
        }

        .percent h1 {
          font-size: 8vw;
        }
      ` } < /style> < /Layout>); } ; export default UploadProgressFullpage ;