mirror of
https://github.com/cupcakearmy/fantus.git
synced 2024-11-01 04:54:13 +01:00
153 lines
4.8 KiB
TypeScript
153 lines
4.8 KiB
TypeScript
|
import React, { useState, useRef, useCallback } from 'react'
|
||
|
import { useForm } from 'formhero'
|
||
|
import axios from 'axios'
|
||
|
import getConfig from 'next/config'
|
||
|
|
||
|
const { RECAPTCHA_CLIENT } = getConfig().publicRuntimeConfig
|
||
|
|
||
|
const initial = {
|
||
|
contact: '',
|
||
|
description: '',
|
||
|
}
|
||
|
|
||
|
const ab2str = (buf: any): string => {
|
||
|
return String.fromCharCode.apply(null, buf);
|
||
|
}
|
||
|
|
||
|
const Form: React.FC = () => {
|
||
|
const [loading, setLoading] = useState(false)
|
||
|
const [message, setMessage] = useState({
|
||
|
title: '',
|
||
|
error: false,
|
||
|
})
|
||
|
|
||
|
const { field, form, setForm } = useForm(initial)
|
||
|
const [files, setFiles] = useState([] as File[])
|
||
|
|
||
|
const _onFileChange = useCallback(async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||
|
setMessage({ title: '', error: false })
|
||
|
const uploaded = Array.from(e.target.files || [])
|
||
|
|
||
|
const nonAudio = uploaded.find(file => !/^audio\//.test(file.type))
|
||
|
if (nonAudio) {
|
||
|
setMessage({
|
||
|
title: `Error: ${nonAudio.name} You can only select audio files.`,
|
||
|
error: true,
|
||
|
})
|
||
|
return
|
||
|
}
|
||
|
|
||
|
setFiles([...files, ...uploaded])
|
||
|
}, [files])
|
||
|
|
||
|
const _clear = useCallback(() => {
|
||
|
setFiles([])
|
||
|
}, [])
|
||
|
|
||
|
const _submit = useCallback((e: React.FormEvent) => {
|
||
|
e.preventDefault()
|
||
|
|
||
|
if (loading) return
|
||
|
|
||
|
// @ts-ignore
|
||
|
window.grecaptcha.ready(() => {
|
||
|
// @ts-ignore
|
||
|
window.grecaptcha.execute(RECAPTCHA_CLIENT, { action: 'homepage' }).then(function (token) {
|
||
|
setLoading(true)
|
||
|
setMessage({ title: '', error: false })
|
||
|
|
||
|
|
||
|
const body = new FormData()
|
||
|
|
||
|
body.append('json', JSON.stringify({
|
||
|
...form,
|
||
|
token,
|
||
|
}))
|
||
|
|
||
|
for (const file of files) {
|
||
|
body.append(file.name, file)
|
||
|
}
|
||
|
|
||
|
fetch('/api/form', {
|
||
|
method: 'POST',
|
||
|
body
|
||
|
})
|
||
|
.then(() => {
|
||
|
setForm(initial)
|
||
|
setFiles([])
|
||
|
setMessage({ title: 'Uploaded 🚀', error: false })
|
||
|
})
|
||
|
.catch(() => setMessage({ title: 'Something went wrong 😥', error: true }))
|
||
|
.finally(() => setLoading(false))
|
||
|
})
|
||
|
})
|
||
|
}, [form, files, loading])
|
||
|
|
||
|
return (
|
||
|
<form onSubmit={_submit}>
|
||
|
<div className='body'>
|
||
|
<h3 className='ma0 mb3'>submit track</h3>
|
||
|
<label className='text'>
|
||
|
<small>contact email</small>
|
||
|
<input
|
||
|
type='email'
|
||
|
disabled={loading}
|
||
|
placeholder={'me@example.org'}
|
||
|
{...field('contact')}
|
||
|
/>
|
||
|
</label>
|
||
|
<br />
|
||
|
<label className='text'>
|
||
|
<small>description</small>
|
||
|
<textarea
|
||
|
rows={2}
|
||
|
placeholder='reference trakcs, comments, ...'
|
||
|
disabled={loading}
|
||
|
{...field('description')}
|
||
|
/>
|
||
|
</label>
|
||
|
<br />
|
||
|
<label className='file'>
|
||
|
<input
|
||
|
type='file'
|
||
|
multiple
|
||
|
disabled={loading}
|
||
|
onChange={_onFileChange}
|
||
|
/>
|
||
|
upload tracks [max. 300MiB]
|
||
|
</label>
|
||
|
{files.length > 0 && (
|
||
|
<div>
|
||
|
<input onClick={_clear} type='button' value='clear all' />
|
||
|
<ul>
|
||
|
{files.map((file, i) => <li key={i}>
|
||
|
{file.name}
|
||
|
</li>)}
|
||
|
</ul>
|
||
|
</div>
|
||
|
)}
|
||
|
<br />
|
||
|
<input
|
||
|
type='submit'
|
||
|
value={loading ? 'uploading...' : 'submit'}
|
||
|
disabled={loading}
|
||
|
/>
|
||
|
|
||
|
{!!message.title && (
|
||
|
<div>
|
||
|
<br />
|
||
|
<div className={`pa2 ba br1 ${message.error ? 'b--red' : 'b--light-blue'}`}>{message.title}</div>
|
||
|
</div>
|
||
|
)}
|
||
|
</div>
|
||
|
|
||
|
<div className='grc'>
|
||
|
This site is protected by reCAPTCHA and the Google
|
||
|
<a href="https://policies.google.com/privacy">Privacy Policy</a> and
|
||
|
<a href="https://policies.google.com/terms">Terms of Service</a> apply.
|
||
|
</div>
|
||
|
</form>
|
||
|
)
|
||
|
}
|
||
|
|
||
|
export default Form
|