// app.tsx // Copyright (C) 2020 Dwayne Harris // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see . import React, { FC, useState, useEffect } from 'react' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faSearch, faSpinner } from '@fortawesome/free-solid-svg-icons' import { Communicator, Theme, InstallationSettings } from '../../../communicator' import Gif from './gif' import { GiphyGif } from '../../../types' const giphyIcon = require('./giphy.png') import '../../../styles/default.css' type APIResponse = GiphyGif[] interface Props { communicator: Communicator } const useDebounce = (value: string, delay = 500) => { const [valueD, setValueD] = useState(value) useEffect(() => { const handler = setTimeout(() => { setValueD(value) }, delay) return () => { clearTimeout(handler) } }, [value, delay]) return valueD } const App: FC = ({ communicator }) => { const [posting, setPosting] = useState(false) const [searching, setSearching] = useState(false) const [search, setSearch] = useState('') const [settings, setSettings] = useState({}) const searchD = useDebounce(search) const [gifs, setGifs] = useState([]) const [selected, setSelected] = useState('') const [theme, setTheme] = useState({ primary: '#333', primaryAlternate: '#fff', secondary: '#777', backgroundPrimary: '#fff', backgroundSecondary: '#ccc', text: '#555', red: '#ff1a1a', green: '#00802b', blue: '#005ce6', }) useEffect(() => { const init = async () => { try { const content = await communicator.init() if (content) { if (content.settings) setSettings(content.settings) if (content.theme) setTheme(content.theme) if (content.parent?.data?.search) { setSearch(content.parent.data.search) } } await communicator.setHeight(1000) } catch (err) {} } init() }, []) useEffect(() => { const doTrending = async () => { try { const response = await fetch('/api/gifs/home') setGifs(await response.json() as APIResponse) } catch (err) {} } const doSearch = async () => { try { setSearching(true) const response = await fetch(`/api/gifs/search?q=${search}`) setGifs(await response.json() as APIResponse) const previousSearches: string[] = settings.searches ?? [] const searches = [ search, ...previousSearches.slice(0, 9), ] const newSettings = { ...settings, searches, } await communicator.saveSettings(newSettings) setSettings(newSettings) } catch (err) { console.error(err) } setSearching(false) } if (!search) { doTrending() } else if (search.length > 2) { doSearch() } }, [searchD]) const handleSearchChange = (search: string) => { setSearch(search) } const post = async () => { try { const gif = gifs.find(g => g.id === selected) if (!gif) return setPosting(true) await communicator.post({ attachments: [{ url: gif.images.fixed_height.url, text: gif.title, }], data: { search, }, visible: true, }) setSearch('') setSelected('') } catch (err) { console.error(err) } setPosting(false) } const getPlaceholder = () => { const searches = settings.searches as string[] ?? [] return searches[0] ? `Last Search: ${searches[0]}` : 'Search' } return (
handleSearchChange(e.target.value)} />
{gifs.map(gif => )}
) } export default App