'use client'; import { IVtuber } from "@/lib/vtubers"; import { IStream } from "@/lib/streams"; import { useSearchParams } from 'next/navigation'; import React, { useContext, useState, useEffect } from 'react'; import { UppyContext } from 'app/uppy'; import { LoginButton, useAuth } from '@/components/auth'; import { Dashboard } from '@uppy/react'; import styles from '@/assets/styles/fp.module.css' import { projektMelodyEpoch } from "@/lib/constants"; import add from "date-fns/add"; import sub from "date-fns/sub"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faCheckCircle, faEraser, faPaperPlane, faSpinner, faX, faXmark } from "@fortawesome/free-solid-svg-icons"; import { useForm, useFieldArray, ValidationMode } from 'react-hook-form'; import { yupResolver } from '@hookform/resolvers/yup'; import * as Yup from 'yup'; import qs from 'qs'; import { toast } from "react-toastify"; import { ErrorMessage } from "@hookform/error-message" interface IUploadFormProps { vtubers: IVtuber[]; } interface IValidationResults { valid: boolean; issues: string[] | null; } interface IFormSchema extends Yup.InferType { }; const validationSchema = Yup.object().shape({ vtuber: Yup.number() .required('VTuber is required'), streamCuid: Yup.string().optional(), date: Yup.date() .typeError('Invalid date') // https://stackoverflow.com/a/72985532/1004931 .min(sub(projektMelodyEpoch, { days: 1 }), 'Date must be after February 7 2020') .max(add(new Date(), { days: 1 }), 'Date cannot be in the future') .required('Date is required'), notes: Yup.string().optional(), attribution: Yup.boolean().optional(), files: Yup.array() .of( Yup.object().shape({ key: Yup.string().required('key is required'), uploadId: Yup.string().required('uploadId is required') }), ) .min(1, 'At least one file is required'), }); export default function UploadForm({ vtubers }: IUploadFormProps) { const searchParams = useSearchParams(); const cuid = searchParams.get('cuid'); const uppy = useContext(UppyContext); const { authData } = useAuth(); const formOptions = { resolver: yupResolver(validationSchema), mode: 'onChange' as keyof ValidationMode, }; const { register, handleSubmit, setError, clearErrors, formState: { errors, isValid, isSubmitted, isSubmitSuccessful, isSubmitting }, setValue, watch, reset } = useForm(formOptions); // useEffect(() => { // if (!cuid) return; // (async () => { // console.log('query') // const query = qs.stringify({ // filters: { // cuid: { // '$eq': cuid // } // } // }); // const res = await fetch(`${process.env.NEXT_PUBLIC_STRAPI_URL}/api/streams?${query}`); // if (!res.ok) return; // const matchingStream = (await res.json()).data as IStream; // console.log(matchingStream); // setValue('vtuber', matchingStream.attributes.vtuber.data.id); // })(); // }, [cuid]); // setValue('streamCuid', cuid||''); const files = watch('files'); async function createUSC(data: IFormSchema) { try { const res = await fetch(`${process.env.NEXT_PUBLIC_STRAPI_URL}/api/user-submitted-contents/createFromUppy`, { method: 'POST', headers: { 'authorization': `Bearer ${authData?.accessToken}`, 'content-type': 'application/json', 'accept': 'application/json' }, body: JSON.stringify({ data: { files: data.files, attribution: data.attribution, notes: data.notes, vtuber: data.vtuber, date: data.date, streamCuid: cuid } }) }); if (!res.ok) { console.error('failed to fetch /api/user-submitted-contents/createFromUppy'); const body = await res.json(); const error = body.error; toast.error(`${error.type} ${error.message}`, { theme: 'dark' }); setError('root.serverError', { type: error.type, message: error.message }) } } catch (e) { if (e instanceof Error) { toast.error(`${e.message}`, { theme: 'dark' }); setError('root.serverError', { type: "remote", message: e.message, }); } else { toast.error(`Something went wrong. Please try again.`, { theme: 'dark' }); setError('root.serverError', { type: 'remote', message: 'Something went wrong. Please try again.' }) } } } uppy.on('complete', async (result: any) => { let files = result.successful.map((f: any) => ({ key: f.s3Multipart.key, uploadId: f.s3Multipart.uploadId })); setValue('files', files); }); return (

VOD uploads

coming soon!!


Track progress on the Goals Page

) // return ( // <> //
//

Upload VOD

//

Together we can archive all lewdtuber livestreams!

// {(!authData?.accessToken) // ? // <> // // // // : ( //
//
// {(!isSubmitSuccessful) &&
//
//
//

// Step 1 //

//

// Upload the file //

//
//
//
// // // {errors.files &&

{errors.files.message?.toString()}

} //
//
} // {(!isSubmitSuccessful) &&
// {/* {(!cuid) && } */} //
//
//

// Step 2 //

//

// Tell us about the VOD //

//
//
//
// {/* */} //
// //
// //
//

Choose the VTuber this VOD belongs to. (More VTubers will be added when storage/bandwidth funding is secured.)

// {errors.vtuber &&

vtuber error

} //
//
// // setDate(evt.target.value)} // > //

The date when the VOD was originally streamed.

// {errors.date &&

{errors.date.message?.toString()}

} //
//
// // //

If there are any issues with the VOD, put a note here. If there are no VOD issues, leave this field blank.

//
//
// // //
//
//
} //
//
//
//

// Step 3 //

//

// Send the form //

//
//
//
// {errors.root?.serverError && ( //
// // //
// )} // {!isSubmitSuccessful && ( // // )} // {isSubmitting && ( //

// //

// )} // {isSubmitSuccessful && ( // <> // // // // )} //
//
//
//
// ) // } //
// // ) }