[ABANDONDED] Set of "apps" for the Flexor social network.
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

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