You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
4.5 KiB
163 lines
4.5 KiB
import React, { FC, useState, useEffect } from 'react'
|
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
import { faSearch } from '@fortawesome/free-solid-svg-icons'
|
|
import { Communicator } from '../../../communicator'
|
|
import classNames from 'classnames'
|
|
import Gif from './gif'
|
|
import { ClassDictionary, GiphyGif } from '../../../types'
|
|
|
|
const giphyIcon = require('./giphy.png')
|
|
import '../../../styles/default.scss'
|
|
|
|
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<Props> = ({ communicator }) => {
|
|
const [posting, setPosting] = useState(false)
|
|
const [searching, setSearching] = useState(false)
|
|
const [search, setSearch] = useState('')
|
|
const searchD = useDebounce(search)
|
|
const [gifs, setGifs] = useState<GiphyGif[]>([])
|
|
const [selected, setSelected] = useState('')
|
|
|
|
const buttonStyle: ClassDictionary = {
|
|
'button': true,
|
|
'is-primary': true,
|
|
'is-loading': posting,
|
|
}
|
|
|
|
const controlStyle: ClassDictionary = {
|
|
'control': true,
|
|
'has-icons-left': true,
|
|
'is-loading': searching,
|
|
}
|
|
|
|
useEffect(() => {
|
|
const init = async () => {
|
|
try {
|
|
const content = await communicator.init()
|
|
if (content && content.parent && content.parent.data && content.parent.data.search) {
|
|
setSearch(content.parent.data.search)
|
|
}
|
|
|
|
await communicator.setHeight(1000)
|
|
} catch (err) {
|
|
console.error(err)
|
|
}
|
|
}
|
|
|
|
init()
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
const doTrending = async () => {
|
|
try {
|
|
const response = await fetch('/api/gifs/home')
|
|
setGifs(await response.json() as APIResponse)
|
|
} catch (err) {
|
|
console.error(err)
|
|
}
|
|
}
|
|
|
|
const doSearch = async () => {
|
|
try {
|
|
setSearching(true)
|
|
const response = await fetch(`/api/gifs/search?q=${search}`)
|
|
setGifs(await response.json() as APIResponse)
|
|
} 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)
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<div className="field">
|
|
<p className={classNames(controlStyle)}>
|
|
<input className="input" type="text" placeholder="Search" value={search} onChange={(e) => handleSearchChange(e.target.value)} />
|
|
<span className="icon is-small is-left">
|
|
<FontAwesomeIcon icon={faSearch} />
|
|
</span>
|
|
</p>
|
|
</div>
|
|
|
|
<div className="gifs is-flex">
|
|
{gifs.map(gif => <Gif key={gif.id} gif={gif} selected={gif.id === selected} onSelect={setSelected} />)}
|
|
</div>
|
|
|
|
<nav className="level">
|
|
<div className="level-left">
|
|
<div className="level-item">
|
|
<img src={giphyIcon} />
|
|
</div>
|
|
</div>
|
|
|
|
<div className="level-right">
|
|
<div className="level-item">
|
|
<button className={classNames(buttonStyle)} onClick={() => post()} disabled={!selected}>Post</button>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default App
|