From f4382ad73e8b62244189b16ac9bdbb5fbe24072d Mon Sep 17 00:00:00 2001
From: Keyan <34140557+huumn@users.noreply.github.com>
Date: Wed, 2 Oct 2024 19:24:01 -0500
Subject: [PATCH] better boost hints (#1441)
* better boost hints
* refine
---
api/resolvers/item.js | 30 ++++++--
api/typeDefs/item.js | 2 +
components/adv-post-form.js | 102 ++++++++++++++++++++--------
components/adv-post-form.module.css | 7 ++
components/item-act.js | 7 +-
5 files changed, 107 insertions(+), 41 deletions(-)
diff --git a/api/resolvers/item.js b/api/resolvers/item.js
index 76a56c84..06ddec3c 100644
--- a/api/resolvers/item.js
+++ b/api/resolvers/item.js
@@ -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
}
}
},
diff --git a/api/typeDefs/item.js b/api/typeDefs/item.js
index c70b84c8..fe87babd 100644
--- a/api/typeDefs/item.js
+++ b/api/typeDefs/item.js
@@ -16,6 +16,8 @@ export default gql`
type BoostPositions {
home: Boolean!
sub: Boolean!
+ homeMaxBoost: Int!
+ subMaxBoost: Int!
}
type TitleUnshorted {
diff --git a/components/adv-post-form.js b/components/adv-post-form.js
index 5e688e54..5ce43d47 100644
--- a/components/adv-post-form.js
+++ b/components/adv-post-form.js
@@ -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 (
+
+
+ {subName &&
+ }
+
+ )
+}
+
// 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 (
- {boostMessage}}
- onChange={(_, e) => {
- if (e.target.value >= 0) {
- setBoost(Number(e.target.value) + (act ? Number(item?.boost) : 0))
- }
- }}
- {...props}
- />
+ <>
+ {boostMessage}}
+ onChange={(_, e) => {
+ if (e.target.value >= 0) {
+ updateBoost(Number(e.target.value))
+ }
+ }}
+ overrideValue={boost}
+ {...props}
+ groupClassName='mb-1'
+ />
+ {!item?.parentId &&
+ }
+ >
)
}
diff --git a/components/adv-post-form.module.css b/components/adv-post-form.module.css
index 1fee284c..e4bfe363 100644
--- a/components/adv-post-form.module.css
+++ b/components/adv-post-form.module.css
@@ -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;
}
\ No newline at end of file
diff --git a/components/item-act.js b/components/item-act.js
index 1d3b3a95..9e38fcfb 100644
--- a/components/item-act.js
+++ b/components/item-act.js
@@ -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}
boost
+ {children}
)
}
@@ -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'
- ? {children}
+ ? {children}
: (
)
}