parent
5f1d3dbde4
commit
f4382ad73e
|
@ -685,11 +685,7 @@ export default {
|
|||
|
||||
return await models.item.count({ where }) + 1
|
||||
},
|
||||
boostPosition: async (parent, { id, sub, boost }, { models, me }) => {
|
||||
if (boost <= 0) {
|
||||
throw new GqlInputError('boost must be greater than 0')
|
||||
}
|
||||
|
||||
boostPosition: async (parent, { id, sub, boost = 0 }, { models, me }) => {
|
||||
const where = {
|
||||
boost: { gte: boost },
|
||||
status: 'ACTIVE',
|
||||
|
@ -701,9 +697,29 @@ export default {
|
|||
where.id = { not: Number(id) }
|
||||
}
|
||||
|
||||
const homeAgg = await models.item.aggregate({
|
||||
_count: { id: true },
|
||||
_max: { boost: true },
|
||||
where
|
||||
})
|
||||
|
||||
let subAgg
|
||||
if (sub) {
|
||||
subAgg = await models.item.aggregate({
|
||||
_count: { id: true },
|
||||
_max: { boost: true },
|
||||
where: {
|
||||
...where,
|
||||
subName: sub
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
home: await models.item.count({ where }) === 0,
|
||||
sub: sub ? await models.item.count({ where: { ...where, subName: sub } }) === 0 : false
|
||||
home: homeAgg._count.id === 0 && boost >= BOOST_MULT,
|
||||
sub: subAgg?._count.id === 0 && boost >= BOOST_MULT,
|
||||
homeMaxBoost: homeAgg._max.boost || 0,
|
||||
subMaxBoost: subAgg?._max.boost || 0
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -16,6 +16,8 @@ export default gql`
|
|||
type BoostPositions {
|
||||
home: Boolean!
|
||||
sub: Boolean!
|
||||
homeMaxBoost: Int!
|
||||
subMaxBoost: Int!
|
||||
}
|
||||
|
||||
type TitleUnshorted {
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
import { useState, useEffect, useMemo } from 'react'
|
||||
import { useState, useEffect, useMemo, useCallback } from 'react'
|
||||
import AccordianItem from './accordian-item'
|
||||
import { Input, InputUserSuggest, VariableInput, Checkbox } from './form'
|
||||
import InputGroup from 'react-bootstrap/InputGroup'
|
||||
import { BOOST_MIN, BOOST_MULT, MAX_FORWARDS } from '@/lib/constants'
|
||||
import { BOOST_MIN, BOOST_MULT, MAX_FORWARDS, SSR } from '@/lib/constants'
|
||||
import { DEFAULT_CROSSPOSTING_RELAYS } from '@/lib/nostr'
|
||||
import Info from './info'
|
||||
import { numWithUnits } from '@/lib/format'
|
||||
import { abbrNum, numWithUnits } from '@/lib/format'
|
||||
import styles from './adv-post-form.module.css'
|
||||
import { useMe } from './me'
|
||||
import { useFeeButton } from './fee-button'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useFormikContext } from 'formik'
|
||||
import { gql, useLazyQuery } from '@apollo/client'
|
||||
import { gql, useQuery } from '@apollo/client'
|
||||
import useDebounceCallback from './use-debounce-callback'
|
||||
import { Button } from 'react-bootstrap'
|
||||
import classNames from 'classnames'
|
||||
|
||||
const EMPTY_FORWARD = { nym: '', pct: '' }
|
||||
|
||||
|
@ -85,56 +87,96 @@ export function BoostInput ({ onChange, ...props }) {
|
|||
)
|
||||
}
|
||||
|
||||
const BoostMaxes = ({ subName, homeMax, subMax, boost, updateBoost }) => {
|
||||
return (
|
||||
<div className='d-flex flex-row mb-2'>
|
||||
<Button
|
||||
className={classNames(styles.boostMax, 'me-2', homeMax + BOOST_MULT <= (boost || 0) && 'invisible')}
|
||||
size='sm'
|
||||
onClick={() => updateBoost(homeMax + BOOST_MULT)}
|
||||
>
|
||||
{abbrNum(homeMax + BOOST_MULT)} <small>top of homepage</small>
|
||||
</Button>
|
||||
{subName &&
|
||||
<Button
|
||||
className={classNames(styles.boostMax, subMax + BOOST_MULT <= (boost || 0) && 'invisible')}
|
||||
size='sm'
|
||||
onClick={() => updateBoost(subMax + BOOST_MULT)}
|
||||
>
|
||||
{abbrNum(subMax + BOOST_MULT)} <small>top of ~{subName}</small>
|
||||
</Button>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// act means we are adding to existing boost
|
||||
export function BoostItemInput ({ item, sub, act = false, ...props }) {
|
||||
const [boost, setBoost] = useState(Number(item?.boost) + (act ? BOOST_MULT : 0))
|
||||
// act adds boost to existing boost
|
||||
const existingBoost = act ? Number(item?.boost || 0) : 0
|
||||
const [boost, setBoost] = useState(act ? 0 : Number(item?.boost || 0))
|
||||
|
||||
const [getBoostPosition, { data }] = useLazyQuery(gql`
|
||||
const { data, previousData, refetch } = useQuery(gql`
|
||||
query BoostPosition($sub: String, $id: ID, $boost: Int) {
|
||||
boostPosition(sub: $sub, id: $id, boost: $boost) {
|
||||
home
|
||||
sub
|
||||
homeMaxBoost
|
||||
subMaxBoost
|
||||
}
|
||||
}`,
|
||||
{ fetchPolicy: 'cache-and-network' })
|
||||
{
|
||||
variables: { sub: item?.subName || sub?.name, boost: existingBoost + boost, id: item?.id },
|
||||
fetchPolicy: 'cache-and-network',
|
||||
skip: !!item?.parentId || SSR
|
||||
})
|
||||
|
||||
const getPositionDebounce = useDebounceCallback((...args) => getBoostPosition(...args), 1000, [getBoostPosition])
|
||||
const getPositionDebounce = useDebounceCallback((...args) => refetch(...args), 1000, [refetch])
|
||||
const updateBoost = useCallback((boost) => {
|
||||
const boostToUse = Number(boost || 0)
|
||||
setBoost(boostToUse)
|
||||
getPositionDebounce({ sub: item?.subName || sub?.name, boost: Number(existingBoost + boostToUse), id: item?.id })
|
||||
}, [getPositionDebounce, item?.id, item?.subName, sub?.name, existingBoost])
|
||||
|
||||
useEffect(() => {
|
||||
if (boost >= 0 && !item?.parentId) {
|
||||
getPositionDebounce({ variables: { sub: item?.subName || sub?.name, boost: Number(boost), id: item?.id } })
|
||||
}
|
||||
}, [boost, item?.id, !item?.parentId, item?.subName || sub?.name])
|
||||
const dat = data || previousData
|
||||
|
||||
const boostMessage = useMemo(() => {
|
||||
if (!item?.parentId) {
|
||||
if (data?.boostPosition?.home || data?.boostPosition?.sub) {
|
||||
if (!item?.parentId && boost >= BOOST_MULT) {
|
||||
if (dat?.boostPosition?.home || dat?.boostPosition?.sub || boost > dat?.boostPosition?.homeMaxBoost || boost > dat?.boostPosition?.subMaxBoost) {
|
||||
const boostPinning = []
|
||||
if (data?.boostPosition?.home) {
|
||||
if (dat?.boostPosition?.home || boost > dat?.boostPosition?.homeMaxBoost) {
|
||||
boostPinning.push('homepage')
|
||||
}
|
||||
if (data?.boostPosition?.sub) {
|
||||
if ((item?.subName || sub?.name) && (dat?.boostPosition?.sub || boost > dat?.boostPosition?.subMaxBoost)) {
|
||||
boostPinning.push(`~${item?.subName || sub?.name}`)
|
||||
}
|
||||
return `pins to the top of ${boostPinning.join(' and ')}`
|
||||
}
|
||||
}
|
||||
if (boost >= 0 && boost % BOOST_MULT === 0) {
|
||||
return `${act ? 'brings to' : 'equivalent to'} ${numWithUnits(boost / BOOST_MULT, { unitPlural: 'zapvotes', unitSingular: 'zapvote' })}`
|
||||
}
|
||||
return 'ranks posts higher based on the amount'
|
||||
}, [boost, data?.boostPosition?.home, data?.boostPosition?.sub, item?.subName, sub?.name])
|
||||
}, [boost, dat?.boostPosition?.home, dat?.boostPosition?.sub, item?.subName, sub?.name])
|
||||
|
||||
return (
|
||||
<BoostInput
|
||||
hint={<span className='text-muted'>{boostMessage}</span>}
|
||||
onChange={(_, e) => {
|
||||
if (e.target.value >= 0) {
|
||||
setBoost(Number(e.target.value) + (act ? Number(item?.boost) : 0))
|
||||
}
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
<>
|
||||
<BoostInput
|
||||
hint={<span className='text-muted'>{boostMessage}</span>}
|
||||
onChange={(_, e) => {
|
||||
if (e.target.value >= 0) {
|
||||
updateBoost(Number(e.target.value))
|
||||
}
|
||||
}}
|
||||
overrideValue={boost}
|
||||
{...props}
|
||||
groupClassName='mb-1'
|
||||
/>
|
||||
{!item?.parentId &&
|
||||
<BoostMaxes
|
||||
subName={item?.subName || sub?.name}
|
||||
homeMax={(dat?.boostPosition?.homeMaxBoost || 0) - existingBoost}
|
||||
subMax={(dat?.boostPosition?.subMaxBoost || 0) - existingBoost}
|
||||
boost={existingBoost + boost}
|
||||
updateBoost={updateBoost}
|
||||
/>}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -9,4 +9,11 @@
|
|||
display: flex;
|
||||
flex: 0 1 fit-content;
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
.boostMax small {
|
||||
font-weight: 400;
|
||||
margin-left: 0.25rem;
|
||||
margin-right: 0.25rem;
|
||||
opacity: 0.5;
|
||||
}
|
|
@ -70,19 +70,18 @@ function BoostForm ({ step, onSubmit, children, item, oValue, inputRef, act = 'B
|
|||
name='amount'
|
||||
type='number'
|
||||
innerRef={inputRef}
|
||||
overrideValue={oValue}
|
||||
sub={item.sub}
|
||||
step={step}
|
||||
required
|
||||
autoFocus
|
||||
item={item}
|
||||
/>
|
||||
{children}
|
||||
<div className='d-flex mt-3'>
|
||||
<SubmitButton variant='success' className='ms-auto mt-1 px-4' value={act}>
|
||||
boost
|
||||
</SubmitButton>
|
||||
</div>
|
||||
{children}
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
@ -147,7 +146,7 @@ export default function ItemAct ({ onClose, item, act = 'TIP', step, children, a
|
|||
}, [me, actor, !!wallet, act, item.id, onClose, abortSignal, strike])
|
||||
|
||||
return act === 'BOOST'
|
||||
? <BoostForm step={step} onSubmit={onSubmit} item={item} oValue={oValue} inputRef={inputRef} act={act}>{children}</BoostForm>
|
||||
? <BoostForm step={step} onSubmit={onSubmit} item={item} inputRef={inputRef} act={act}>{children}</BoostForm>
|
||||
: (
|
||||
<Form
|
||||
initial={{
|
||||
|
@ -171,12 +170,12 @@ export default function ItemAct ({ onClose, item, act = 'TIP', step, children, a
|
|||
<div>
|
||||
<Tips setOValue={setOValue} />
|
||||
</div>
|
||||
{children}
|
||||
<div className='d-flex mt-3'>
|
||||
<SubmitButton variant={act === 'DONT_LIKE_THIS' ? 'danger' : 'success'} className='ms-auto mt-1 px-4' value={act}>
|
||||
{act === 'DONT_LIKE_THIS' ? 'downzap' : 'zap'}
|
||||
</SubmitButton>
|
||||
</div>
|
||||
{children}
|
||||
</Form>)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue