parent
384fe16671
commit
fb007d65de
14
api/_shared/formidablePromise.js
Normal file
14
api/_shared/formidablePromise.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
import formidable from 'formidable'
|
||||
|
||||
export const formidablePromise = async (request, options) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const form = formidable(options)
|
||||
|
||||
form.parse(request, (err, fields, files) => {
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
return resolve({ fields, files })
|
||||
})
|
||||
})
|
||||
}
|
|
@ -1,29 +1,28 @@
|
|||
const MG = require('mailgun.js')
|
||||
const fd = require('form-data')
|
||||
const mailgun = new MG(fd)
|
||||
import { formidablePromise } from './_shared/formidablePromise'
|
||||
const mailgun = require('mailgun-js')({
|
||||
apiKey: process.env.MAILGUN_API_KEY,
|
||||
domain: process.env.MAILGUN_DOMAIN
|
||||
})
|
||||
|
||||
const mgOptions = {
|
||||
key: process.env.MAILGUN_API_KEY,
|
||||
domain: process.env.MAILGUN_DOMAIN,
|
||||
username: 'discoursio' // FIXME
|
||||
}
|
||||
export default async function handler(req, res) {
|
||||
const { contact, subject, message } = await formidablePromise(req)
|
||||
|
||||
const client = mailgun.client(mgOptions)
|
||||
const text = `${contact}\n\n${message}`
|
||||
|
||||
const messageData = (subject, text) => {
|
||||
return {
|
||||
const data = {
|
||||
from: 'Discours Feedback Robot <robot@discours.io>',
|
||||
to: 'welcome@discours.io',
|
||||
subject,
|
||||
text
|
||||
}
|
||||
}
|
||||
export default async function handler(req, res) {
|
||||
const { contact, subject, message } = req.query
|
||||
try {
|
||||
const data = messageData(`${contact}: ${subject}`, message)
|
||||
client.messages.create(mgOptions.domain, data).then(console.log).catch(console.error)
|
||||
} catch (error) {
|
||||
res.status(400).json(error)
|
||||
}
|
||||
|
||||
mailgun.messages().send(data, (error) => {
|
||||
if (error) {
|
||||
console.log('Error:', error)
|
||||
res.status(400).json(error)
|
||||
} else {
|
||||
console.log('Email sent successfully!')
|
||||
res.status(200)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import formidable from 'formidable'
|
|||
import { Writable } from 'stream'
|
||||
import path from 'path'
|
||||
import crypto from 'crypto'
|
||||
import { formidablePromise } from './_shared/formidablePromise.js'
|
||||
|
||||
const { STORJ_ACCESS_KEY, STORJ_SECRET_KEY, STORJ_END_POINT, STORJ_BUCKET_NAME, CDN_DOMAIN } = process.env
|
||||
|
||||
|
@ -15,19 +16,6 @@ const storjS3Client = new S3Client({
|
|||
}
|
||||
})
|
||||
|
||||
const formidablePromise = async (request, options) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const form = formidable(options)
|
||||
|
||||
form.parse(request, (err, fields, files) => {
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
return resolve({ fields, files })
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const fileConsumer = (acc) => {
|
||||
return new Writable({
|
||||
write: (chunk, _enc, next) => {
|
||||
|
|
|
@ -48,6 +48,7 @@ export const TopicSelect = (props: TopicSelectProps) => {
|
|||
|
||||
const format = (item, type) => {
|
||||
if (type === 'option') {
|
||||
// eslint-disable-next-line solid/components-return-once
|
||||
return item.label
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { createSignal, For } from 'solid-js'
|
||||
import { createSignal, For, Show } from 'solid-js'
|
||||
import type { Author } from '../../../graphql/types.gen'
|
||||
import { useAuthorsStore } from '../../../stores/zine/authors'
|
||||
import { Icon } from '../../_shared/Icon'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { clsx } from 'clsx'
|
||||
import styles from './GrowingTextarea.module.scss'
|
||||
import { createEffect, createSignal } from 'solid-js'
|
||||
import { createSignal } from 'solid-js'
|
||||
|
||||
type Props = {
|
||||
class?: string
|
||||
|
|
|
@ -1,6 +1,41 @@
|
|||
import { PageLayout } from '../components/_shared/PageLayout'
|
||||
import { createSignal } from 'solid-js'
|
||||
|
||||
export const ConnectPage = () => {
|
||||
const [state, setState] = createSignal<'initial' | 'loading' | 'success' | 'error'>('initial')
|
||||
|
||||
const formRef: { current: HTMLFormElement } = { current: null }
|
||||
const handleFormSubmit = async (e) => {
|
||||
e.preventDefault()
|
||||
setState('loading')
|
||||
|
||||
// eslint-disable-next-line unicorn/prefer-spread
|
||||
const postData = Array.from(formRef.current.elements).reduce((acc, element) => {
|
||||
const formField = element as unknown as { name: string; value: string }
|
||||
if (formField.name) {
|
||||
acc[formField.name] = formField.value
|
||||
}
|
||||
|
||||
return acc
|
||||
}, {} as Record<string, string>)
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(postData)
|
||||
}
|
||||
|
||||
try {
|
||||
await fetch('/api/feedback', requestOptions)
|
||||
setState('success')
|
||||
} catch (error) {
|
||||
console.error('[handleFormSubmit]', error)
|
||||
setState('error')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<PageLayout>
|
||||
<article class="wide-container container--static-page">
|
||||
|
@ -15,26 +50,30 @@ export const ConnectPage = () => {
|
|||
скорее! Если укажете свою почту, мы обязательно ответим.
|
||||
</p>
|
||||
|
||||
<form action="/api/feedback">
|
||||
<form onSubmit={handleFormSubmit} ref={(el) => (formRef.current = el)}>
|
||||
<div class="pretty-form__item">
|
||||
<select id="subject">
|
||||
<option value="">Сотрудничество</option>
|
||||
<option value="">Посоветовать тему</option>
|
||||
<option value="">Сообщить об ошибке</option>
|
||||
<option value="">Предложить проект</option>
|
||||
<option value="">Волонтерство</option>
|
||||
<option value="">Другое</option>
|
||||
<select name="subject">
|
||||
<option value="Сотрудничество" selected>
|
||||
Сотрудничество
|
||||
</option>
|
||||
<option value="Посоветовать тему">Посоветовать тему</option>
|
||||
<option value="Сообщить об ошибке">Сообщить об ошибке</option>
|
||||
<option value="Предложить проект">Предложить проект</option>
|
||||
<option value="Волонтерство">Волонтерство</option>
|
||||
<option value="Другое">Другое</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="pretty-form__item">
|
||||
<input type="text" id="contact-email" placeholder="Email для обратной связи" />
|
||||
<input type="email" name="contact" placeholder="Email для обратной связи" />
|
||||
<label for="contact-email">Email для обратной связи</label>
|
||||
</div>
|
||||
<div class="pretty-form__item">
|
||||
<textarea id="message" placeholder="Текст сообщения" />
|
||||
<textarea name="message" placeholder="Текст сообщения" />
|
||||
<label for="message">Текст сообщения</label>
|
||||
</div>
|
||||
<button class="button">Отправить письмо</button>
|
||||
<button class="button" disabled={state() !== 'initial'} type="submit">
|
||||
Отправить письмо
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue
Block a user