2022-07-30 13:25:46 +00:00
|
|
|
import { gql, useMutation } from '@apollo/client'
|
2023-07-24 18:35:05 +00:00
|
|
|
import Button from 'react-bootstrap/Button'
|
2023-08-08 21:31:43 +00:00
|
|
|
import { fixedDecimal, numWithUnits } from '../lib/format'
|
2022-07-30 13:25:46 +00:00
|
|
|
import { timeLeft } from '../lib/time'
|
|
|
|
import { useMe } from './me'
|
|
|
|
import styles from './poll.module.css'
|
|
|
|
import Check from '../svgs/checkbox-circle-fill.svg'
|
2023-07-29 19:38:20 +00:00
|
|
|
import { signIn } from 'next-auth/react'
|
2022-07-30 13:25:46 +00:00
|
|
|
import ActionTooltip from './action-tooltip'
|
2023-01-10 23:13:37 +00:00
|
|
|
import { useShowModal } from './modal'
|
2023-08-31 15:10:24 +00:00
|
|
|
import { POLL_COST } from '../lib/constants'
|
|
|
|
import { InvoiceModal } from './invoice'
|
2022-07-30 13:25:46 +00:00
|
|
|
|
|
|
|
export default function Poll ({ item }) {
|
|
|
|
const me = useMe()
|
2023-01-10 23:13:37 +00:00
|
|
|
const showModal = useShowModal()
|
2022-07-30 13:25:46 +00:00
|
|
|
const [pollVote] = useMutation(
|
|
|
|
gql`
|
2023-08-31 15:10:24 +00:00
|
|
|
mutation pollVote($id: ID!, $hash: String, $hmac: String) {
|
|
|
|
pollVote(id: $id, hash: $hash, hmac: $hmac)
|
2022-07-30 13:25:46 +00:00
|
|
|
}`, {
|
|
|
|
update (cache, { data: { pollVote } }) {
|
|
|
|
cache.modify({
|
|
|
|
id: `Item:${item.id}`,
|
|
|
|
fields: {
|
|
|
|
poll (existingPoll) {
|
|
|
|
const poll = { ...existingPoll }
|
|
|
|
poll.meVoted = true
|
|
|
|
poll.count += 1
|
|
|
|
return poll
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
cache.modify({
|
|
|
|
id: `PollOption:${pollVote}`,
|
|
|
|
fields: {
|
|
|
|
count (existingCount) {
|
|
|
|
return existingCount + 1
|
|
|
|
},
|
|
|
|
meVoted () {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
const PollButton = ({ v }) => {
|
|
|
|
return (
|
|
|
|
<ActionTooltip placement='left' notForm>
|
|
|
|
<Button
|
|
|
|
variant='outline-info' className={styles.pollButton}
|
|
|
|
onClick={me
|
|
|
|
? async () => {
|
2023-07-25 14:14:45 +00:00
|
|
|
try {
|
|
|
|
await pollVote({
|
|
|
|
variables: { id: v.id },
|
|
|
|
optimisticResponse: {
|
|
|
|
pollVote: v.id
|
2022-07-30 13:25:46 +00:00
|
|
|
}
|
2023-07-25 14:14:45 +00:00
|
|
|
})
|
|
|
|
} catch (error) {
|
2023-08-31 15:10:24 +00:00
|
|
|
showModal(onClose => {
|
|
|
|
return (
|
|
|
|
<InvoiceModal
|
|
|
|
amount={item.pollCost || POLL_COST}
|
|
|
|
onPayment={async ({ hash, hmac }) => {
|
|
|
|
await pollVote({ variables: { id: v.id, hash, hmac } })
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
)
|
|
|
|
})
|
2022-07-30 13:25:46 +00:00
|
|
|
}
|
2023-07-25 14:14:45 +00:00
|
|
|
}
|
2022-07-30 13:25:46 +00:00
|
|
|
: signIn}
|
|
|
|
>
|
|
|
|
{v.option}
|
|
|
|
</Button>
|
|
|
|
</ActionTooltip>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
const expiresIn = timeLeft(new Date(+new Date(item.createdAt) + 864e5))
|
|
|
|
const mine = item.user.id === me?.id
|
|
|
|
return (
|
|
|
|
<div className={styles.pollBox}>
|
|
|
|
{item.poll.options.map(v =>
|
|
|
|
expiresIn && !item.poll.meVoted && !mine
|
|
|
|
? <PollButton key={v.id} v={v} />
|
|
|
|
: <PollResult
|
|
|
|
key={v.id} v={v}
|
|
|
|
progress={item.poll.count ? fixedDecimal(v.count * 100 / item.poll.count, 1) : 0}
|
|
|
|
/>)}
|
2023-08-08 21:31:43 +00:00
|
|
|
<div className='text-muted mt-1'>{numWithUnits(item.poll.count, { unitSingular: 'vote', unitPlural: 'votes' })} \ {expiresIn ? `${expiresIn} left` : 'poll ended'}</div>
|
2022-07-30 13:25:46 +00:00
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
function PollResult ({ v, progress }) {
|
|
|
|
return (
|
|
|
|
<div className={styles.pollResult}>
|
2023-09-28 21:52:11 +00:00
|
|
|
<span className={styles.pollOption}>{v.option}{v.meVoted && <Check className='fill-grey ms-1 align-self-center flex-shrink-0' width={16} height={16} />}</span>
|
2023-07-24 18:35:05 +00:00
|
|
|
<span className='ms-auto me-2 align-self-center'>{progress}%</span>
|
2022-07-30 13:25:46 +00:00
|
|
|
<div className={styles.pollProgress} style={{ width: `${progress}%` }} />
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|