diff --git a/package.json b/package.json index e10181e..95e76aa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tweries-app", - "version": "1.4.2", + "version": "1.5.1", "private": true, "description": "Tweries, a tweet-storm-helper app that breaks up a long paragraph into multiple tweets.", "dependencies": { diff --git a/src/api/fetchTweetstorm.js b/src/api/fetchTweetstorm.js index 927620d..e2263eb 100644 --- a/src/api/fetchTweetstorm.js +++ b/src/api/fetchTweetstorm.js @@ -1,11 +1,17 @@ import { BASE_URL } from '../constants'; -async function fetchTweetstorm({ inReplyToTweetUrl, items, userId }) { +async function fetchTweetstorm({ cover, inReplyToTweetUrl, items, userId }) { + // CHECK: https://programmingwithmosh.com/javascript/react-file-upload-proper-server-side-nodejs-easy/ + + const formData = new FormData(); + + formData.append('cover', cover); + formData.append('inReplyToTweetUrl', inReplyToTweetUrl); + formData.append('items', JSON.stringify(items)); + formData.append('userId', userId); + const response = await fetch(`${BASE_URL}/api/v2/tweetstorm`, { - body: JSON.stringify({ inReplyToTweetUrl, items, userId }), - headers: { - 'Content-Type': 'application/json' - }, + body: formData, method: 'POST' }); const json = await response.json(); diff --git a/src/constants.js b/src/constants.js index 8ef268c..9e73e6a 100644 --- a/src/constants.js +++ b/src/constants.js @@ -12,6 +12,7 @@ export const BASE_URL = export const DANGER = 'danger'; +export const ADD_IMAGE_V1 = 'ADD_IMAGE_V1'; export const FEATURE_V1 = 'FEATURE_V1'; export const HIDE_TAGS_V1 = 'HIDE_TAGS_V1'; export const SHOW_INFO_V1 = 'SHOW_INFO_V1'; diff --git a/src/containers/App/App.js b/src/containers/App/App.js index 7f8a582..ef92ebe 100644 --- a/src/containers/App/App.js +++ b/src/containers/App/App.js @@ -4,7 +4,13 @@ import { faTwitter } from '@fortawesome/free-brands-svg-icons'; import { faInfo } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import PropTypes from 'prop-types'; -import React, { useCallback, useEffect, useReducer, useState } from 'react'; +import React, { + useCallback, + useEffect, + useReducer, + useRef, + useState +} from 'react'; import { version } from '../../../package.json'; import fetchHealth from '../../api/fetchHealth'; import fetchTweetstorm from '../../api/fetchTweetstorm'; @@ -16,6 +22,7 @@ import useLocalStorage from '../../hooks/useLocalStorage'; import makeTweetstorm from '../../store/makeTweetstorm'; import { types } from '../../store/makeReducer'; import { + ADD_IMAGE_V1, DANGER, HIDE_TAGS_V1, MAX_LENGTH, @@ -29,6 +36,7 @@ import TweetstormButton from './TweetstormButton'; const copy = { '...': '...', + 'Add an image': 'Add an image', 'Edits can be made in the boxes below before publishing': 'Edits can be made in the boxes below before publishing', 'Log in': 'Log in', @@ -36,6 +44,7 @@ const copy = { 'Login is necessary in order for your series of Tweets to be sent through your Twitter account', 'Start typing. To insert a break prior to reaching 280 characters, please use Newline(s)': 'Start typing. To insert a break prior to reaching 280 characters, please use Newline(s)', + TODO: 'TODO', Tags: 'Tags', Tweet: 'Tweet', Tweries: 'Tweries', @@ -112,7 +121,7 @@ function App({ initialState, reducer }) { if (notification) { const timer = setTimeout(() => { dispatch({ type: types.DISMISS_TOAST }); - }, 3000); + }, 5000); return () => clearTimeout(timer); } }, [notification]); @@ -121,6 +130,9 @@ function App({ initialState, reducer }) { const [inReplyToTweetUrl, setInReplyToTweetUrl] = useState(''); const [waiting, setWaiting] = useState(false); + const [cover, setCover] = useState(null); + const inputEl = useRef(null); + function disabled() { return ( !isAuthenticated || @@ -172,6 +184,10 @@ function App({ initialState, reducer }) { type } }); + if (feature.active(ADD_IMAGE_V1)) { + setCover(null); + inputEl.current.value = null; // to reset the input + } setHashtags(''); setInReplyToTweetUrl(''); setSource(''); @@ -182,6 +198,7 @@ function App({ initialState, reducer }) { setWaiting(true); try { const response = await fetchTweetstorm({ + cover, inReplyToTweetUrl, items, userId @@ -258,6 +275,24 @@ function App({ initialState, reducer }) { value={source} /> + {feature.active(ADD_IMAGE_V1) && ( + <> + + setCover(files[0])} + ref={inputEl} + rows={1} + type="file" + /> + + )} {!feature.active(HIDE_TAGS_V1) && ( <>