Compare commits
18 Commits
3310925155
...
18fbd17025
Author | SHA1 | Date | |
---|---|---|---|
|
18fbd17025 | ||
|
2b5a1cbfe9 | ||
|
b6dcee4f26 | ||
|
d30dace266 | ||
|
894d02a196 | ||
|
83458fdc9e | ||
|
101574b605 | ||
|
59d5fd60f2 | ||
|
f90a9905ba | ||
|
8447a4a8b2 | ||
|
4981d572bb | ||
|
4e7b4ee571 | ||
|
8c9d4aa59b | ||
|
ad9a65ce78 | ||
|
b4e143460b | ||
|
731df5fc67 | ||
|
2f191e04f9 | ||
|
09be42844e |
@ -190,7 +190,7 @@ export async function retryPaidAction (actionType, args, context) {
|
|||||||
|
|
||||||
const failedInvoice = await models.invoice.findUnique({ where: { id: invoiceId, actionState: 'FAILED' } })
|
const failedInvoice = await models.invoice.findUnique({ where: { id: invoiceId, actionState: 'FAILED' } })
|
||||||
if (!failedInvoice) {
|
if (!failedInvoice) {
|
||||||
throw new Error(`retryPaidAction - invoice not found or not in failed state ${actionType}`)
|
throw new Error(`retryPaidAction ${actionType} - invoice ${invoiceId} not found or not in failed state`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const { msatsRequested, actionId } = failedInvoice
|
const { msatsRequested, actionId } = failedInvoice
|
||||||
|
@ -105,6 +105,8 @@ const orderByClause = (by, me, models, type) => {
|
|||||||
return 'ORDER BY "Item".msats DESC'
|
return 'ORDER BY "Item".msats DESC'
|
||||||
case 'zaprank':
|
case 'zaprank':
|
||||||
return topOrderByWeightedSats(me, models)
|
return topOrderByWeightedSats(me, models)
|
||||||
|
case 'boost':
|
||||||
|
return 'ORDER BY "Item".boost DESC'
|
||||||
case 'random':
|
case 'random':
|
||||||
return 'ORDER BY RANDOM()'
|
return 'ORDER BY RANDOM()'
|
||||||
default:
|
default:
|
||||||
@ -378,6 +380,7 @@ export default {
|
|||||||
activeOrMine(me),
|
activeOrMine(me),
|
||||||
nsfwClause(showNsfw),
|
nsfwClause(showNsfw),
|
||||||
typeClause(type),
|
typeClause(type),
|
||||||
|
by === 'boost' && '"Item".boost > 0',
|
||||||
whenClause(when || 'forever', table))}
|
whenClause(when || 'forever', table))}
|
||||||
${orderByClause(by, me, models, type)}
|
${orderByClause(by, me, models, type)}
|
||||||
OFFSET $4
|
OFFSET $4
|
||||||
@ -421,6 +424,7 @@ export default {
|
|||||||
typeClause(type),
|
typeClause(type),
|
||||||
whenClause(when, 'Item'),
|
whenClause(when, 'Item'),
|
||||||
await filterClause(me, models, type),
|
await filterClause(me, models, type),
|
||||||
|
by === 'boost' && '"Item".boost > 0',
|
||||||
muteClause(me))}
|
muteClause(me))}
|
||||||
${orderByClause(by || 'zaprank', me, models, type)}
|
${orderByClause(by || 'zaprank', me, models, type)}
|
||||||
OFFSET $3
|
OFFSET $3
|
||||||
@ -479,7 +483,7 @@ export default {
|
|||||||
'"pinId" IS NULL',
|
'"pinId" IS NULL',
|
||||||
subClause(sub, 4)
|
subClause(sub, 4)
|
||||||
)}
|
)}
|
||||||
ORDER BY group_rank, rank
|
ORDER BY group_rank DESC, rank
|
||||||
OFFSET $2
|
OFFSET $2
|
||||||
LIMIT $3`,
|
LIMIT $3`,
|
||||||
orderBy: 'ORDER BY group_rank DESC, rank'
|
orderBy: 'ORDER BY group_rank DESC, rank'
|
||||||
@ -690,7 +694,8 @@ export default {
|
|||||||
boost: { gte: boost },
|
boost: { gte: boost },
|
||||||
status: 'ACTIVE',
|
status: 'ACTIVE',
|
||||||
deletedAt: null,
|
deletedAt: null,
|
||||||
outlawed: false
|
outlawed: false,
|
||||||
|
parentId: null
|
||||||
}
|
}
|
||||||
if (id) {
|
if (id) {
|
||||||
where.id = { not: Number(id) }
|
where.id = { not: Number(id) }
|
||||||
@ -698,7 +703,7 @@ export default {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
home: await models.item.count({ where }) === 0,
|
home: await models.item.count({ where }) === 0,
|
||||||
sub: await models.item.count({ where: { ...where, subName: sub } }) === 0
|
sub: sub ? await models.item.count({ where: { ...where, subName: sub } }) === 0 : false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1139,7 +1144,7 @@ export default {
|
|||||||
return item.weightedVotes - item.weightedDownVotes > 0
|
return item.weightedVotes - item.weightedDownVotes > 0
|
||||||
},
|
},
|
||||||
freebie: async (item) => {
|
freebie: async (item) => {
|
||||||
return item.cost === 0
|
return item.cost === 0 && item.boost === 0
|
||||||
},
|
},
|
||||||
meSats: async (item, args, { me, models }) => {
|
meSats: async (item, args, { me, models }) => {
|
||||||
if (!me) return 0
|
if (!me) return 0
|
||||||
|
@ -90,8 +90,8 @@ export function BoostItemInput ({ item, sub, act = false, ...props }) {
|
|||||||
const [boost, setBoost] = useState(Number(item?.boost) + (act ? BOOST_MULT : 0))
|
const [boost, setBoost] = useState(Number(item?.boost) + (act ? BOOST_MULT : 0))
|
||||||
|
|
||||||
const [getBoostPosition, { data }] = useLazyQuery(gql`
|
const [getBoostPosition, { data }] = useLazyQuery(gql`
|
||||||
query BoostPosition($id: ID, $boost: Int) {
|
query BoostPosition($sub: String, $id: ID, $boost: Int) {
|
||||||
boostPosition(sub: "${item?.subName || sub?.name}", id: $id, boost: $boost) {
|
boostPosition(sub: $sub, id: $id, boost: $boost) {
|
||||||
home
|
home
|
||||||
sub
|
sub
|
||||||
}
|
}
|
||||||
@ -101,10 +101,10 @@ export function BoostItemInput ({ item, sub, act = false, ...props }) {
|
|||||||
const getPositionDebounce = useDebounceCallback((...args) => getBoostPosition(...args), 1000, [getBoostPosition])
|
const getPositionDebounce = useDebounceCallback((...args) => getBoostPosition(...args), 1000, [getBoostPosition])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (boost) {
|
if (boost >= 0 && !item?.parentId) {
|
||||||
getPositionDebounce({ variables: { boost: Number(boost), id: item?.id } })
|
getPositionDebounce({ variables: { sub: item?.subName || sub?.name, boost: Number(boost), id: item?.id } })
|
||||||
}
|
}
|
||||||
}, [boost, item?.id])
|
}, [boost, item?.id, !item?.parentId, item?.subName || sub?.name])
|
||||||
|
|
||||||
const boostMessage = useMemo(() => {
|
const boostMessage = useMemo(() => {
|
||||||
if (!item?.parentId) {
|
if (!item?.parentId) {
|
||||||
|
@ -2,9 +2,9 @@ import { useShowModal } from './modal'
|
|||||||
import { useToast } from './toast'
|
import { useToast } from './toast'
|
||||||
import ItemAct from './item-act'
|
import ItemAct from './item-act'
|
||||||
import AccordianItem from './accordian-item'
|
import AccordianItem from './accordian-item'
|
||||||
import { useMemo } from 'react'
|
import { useMemo, useState } from 'react'
|
||||||
import getColor from '@/lib/rainbow'
|
import getColor from '@/lib/rainbow'
|
||||||
import UpBolt from '@/svgs/bolt.svg'
|
import BoostIcon from '@/svgs/arrow-up-double-line.svg'
|
||||||
import styles from './upvote.module.css'
|
import styles from './upvote.module.css'
|
||||||
import { BoostHelp } from './adv-post-form'
|
import { BoostHelp } from './adv-post-form'
|
||||||
import { BOOST_MULT } from '@/lib/constants'
|
import { BOOST_MULT } from '@/lib/constants'
|
||||||
@ -12,15 +12,17 @@ import classNames from 'classnames'
|
|||||||
|
|
||||||
export default function Boost ({ item, className, ...props }) {
|
export default function Boost ({ item, className, ...props }) {
|
||||||
const { boost } = item
|
const { boost } = item
|
||||||
const style = useMemo(() => (boost
|
const [hover, setHover] = useState(false)
|
||||||
|
|
||||||
|
const [color, nextColor] = useMemo(() => [getColor(boost), getColor(boost + BOOST_MULT)], [boost])
|
||||||
|
|
||||||
|
const style = useMemo(() => (hover || boost
|
||||||
? {
|
? {
|
||||||
fill: getColor(boost),
|
fill: hover ? nextColor : color,
|
||||||
filter: `drop-shadow(0 0 6px ${getColor(boost)}90)`,
|
filter: `drop-shadow(0 0 6px ${hover ? nextColor : color}90)`
|
||||||
transform: 'scaleX(-1)'
|
|
||||||
}
|
}
|
||||||
: {
|
: undefined), [boost, hover])
|
||||||
transform: 'scaleX(-1)'
|
|
||||||
}), [boost])
|
|
||||||
return (
|
return (
|
||||||
<Booster
|
<Booster
|
||||||
item={item} As={({ ...oprops }) =>
|
item={item} As={({ ...oprops }) =>
|
||||||
@ -28,11 +30,14 @@ export default function Boost ({ item, className, ...props }) {
|
|||||||
<div
|
<div
|
||||||
className={styles.upvoteWrapper}
|
className={styles.upvoteWrapper}
|
||||||
>
|
>
|
||||||
<UpBolt
|
<BoostIcon
|
||||||
{...props} {...oprops} style={style}
|
{...props} {...oprops} style={style}
|
||||||
width={26}
|
width={26}
|
||||||
height={26}
|
height={26}
|
||||||
className={classNames(styles.upvote, className, boost && styles.voted)}
|
onPointerEnter={() => setHover(true)}
|
||||||
|
onMouseLeave={() => setHover(false)}
|
||||||
|
onTouchEnd={() => setHover(false)}
|
||||||
|
className={classNames(styles.boost, className, boost && styles.voted)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>}
|
</div>}
|
||||||
|
@ -255,6 +255,11 @@ export function MarkdownInput ({ label, topLevel, groupClassName, onChange, onKe
|
|||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
insertMarkdownItalicFormatting(innerRef.current, helpers.setValue, setSelectionRange)
|
insertMarkdownItalicFormatting(innerRef.current, helpers.setValue, setSelectionRange)
|
||||||
}
|
}
|
||||||
|
if (e.key === 'u') {
|
||||||
|
// some browsers might use CTRL+U to do something else so prevent that behavior too
|
||||||
|
e.preventDefault()
|
||||||
|
imageUploadRef.current?.click()
|
||||||
|
}
|
||||||
if (e.key === 'Tab' && e.altKey) {
|
if (e.key === 'Tab' && e.altKey) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
insertMarkdownTabFormatting(innerRef.current, helpers.setValue, setSelectionRange)
|
insertMarkdownTabFormatting(innerRef.current, helpers.setValue, setSelectionRange)
|
||||||
|
@ -277,7 +277,7 @@ export function useZap () {
|
|||||||
const reason = error?.message || error?.toString?.()
|
const reason = error?.message || error?.toString?.()
|
||||||
toaster.danger(reason)
|
toaster.danger(reason)
|
||||||
}
|
}
|
||||||
}, [me?.id, strike])
|
}, [act, me?.id, strike])
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ActCanceledError extends Error {
|
export class ActCanceledError extends Error {
|
||||||
|
@ -113,7 +113,6 @@ function TopLevelItem ({ item, noReply, ...props }) {
|
|||||||
<Reply
|
<Reply
|
||||||
item={item}
|
item={item}
|
||||||
replyOpen
|
replyOpen
|
||||||
placeholder={item.ncomments > 3 ? 'fractions of a penny for your thoughts?' : 'early comments get more zaps'}
|
|
||||||
onCancelQuote={cancelQuote}
|
onCancelQuote={cancelQuote}
|
||||||
onQuoteReply={quoteReply}
|
onQuoteReply={quoteReply}
|
||||||
quote={quote}
|
quote={quote}
|
||||||
|
@ -106,7 +106,7 @@ export default function Item ({
|
|||||||
<div className={classNames(styles.item, itemClassName)}>
|
<div className={classNames(styles.item, itemClassName)}>
|
||||||
{item.position && (pinnable || !item.subName)
|
{item.position && (pinnable || !item.subName)
|
||||||
? <Pin width={24} height={24} className={styles.pin} />
|
? <Pin width={24} height={24} className={styles.pin} />
|
||||||
: item.mine
|
: item.mine || item.meForward
|
||||||
? <Boost item={item} className={styles.upvote} />
|
? <Boost item={item} className={styles.upvote} />
|
||||||
: item.meDontLikeSats > item.meSats
|
: item.meDontLikeSats > item.meSats
|
||||||
? <DownZap width={24} height={24} className={styles.dontLike} item={item} />
|
? <DownZap width={24} height={24} className={styles.dontLike} item={item} />
|
||||||
|
@ -242,12 +242,12 @@ function RevenueNotification ({ n }) {
|
|||||||
return (
|
return (
|
||||||
<div className='d-flex'>
|
<div className='d-flex'>
|
||||||
<BountyIcon className='align-self-center fill-success mx-1' width={24} height={24} style={{ flex: '0 0 24px' }} />
|
<BountyIcon className='align-self-center fill-success mx-1' width={24} height={24} style={{ flex: '0 0 24px' }} />
|
||||||
<div className=' pb-1'>
|
<div className='ms-2'>
|
||||||
<div className='fw-bold text-success'>
|
<NoteHeader color='success' big>
|
||||||
you stacked {numWithUnits(n.earnedSats, { abbreviate: false })} in territory revenue<small className='text-muted ms-1 fw-normal' suppressHydrationWarning>{timeSince(new Date(n.sortTime))}</small>
|
you stacked {numWithUnits(n.earnedSats, { abbreviate: false })} in territory revenue<small className='text-muted ms-1 fw-normal' suppressHydrationWarning>{timeSince(new Date(n.sortTime))}</small>
|
||||||
</div>
|
</NoteHeader>
|
||||||
<div style={{ lineHeight: '140%' }}>
|
<div style={{ lineHeight: '140%' }}>
|
||||||
As the founder of territory <Link href={`/~${n.subName}`}>~{n.subName}</Link>, you receive 50% of the revenue it generates and the other 50% go to <Link href='/rewards'>rewards</Link>.
|
As the founder of territory <Link href={`/~${n.subName}`}>~{n.subName}</Link>, you receive 70% of the post, comment, boost, and zap fees. The other 30% go to <Link href='/rewards'>rewards</Link>.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,7 +2,7 @@ import { Form, MarkdownInput } from '@/components/form'
|
|||||||
import styles from './reply.module.css'
|
import styles from './reply.module.css'
|
||||||
import { COMMENTS } from '@/fragments/comments'
|
import { COMMENTS } from '@/fragments/comments'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import { forwardRef, useCallback, useEffect, useState, useRef } from 'react'
|
import { forwardRef, useCallback, useEffect, useState, useRef, useMemo } from 'react'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { FeeButtonProvider, postCommentBaseLineItems, postCommentUseRemoteLineItems } from './fee-button'
|
import { FeeButtonProvider, postCommentBaseLineItems, postCommentUseRemoteLineItems } from './fee-button'
|
||||||
import { commentsViewedAfterComment } from '@/lib/new-comments'
|
import { commentsViewedAfterComment } from '@/lib/new-comments'
|
||||||
@ -34,7 +34,6 @@ export default forwardRef(function Reply ({
|
|||||||
item,
|
item,
|
||||||
replyOpen,
|
replyOpen,
|
||||||
children,
|
children,
|
||||||
placeholder,
|
|
||||||
onQuoteReply,
|
onQuoteReply,
|
||||||
onCancelQuote,
|
onCancelQuote,
|
||||||
quote
|
quote
|
||||||
@ -53,6 +52,14 @@ export default forwardRef(function Reply ({
|
|||||||
}
|
}
|
||||||
}, [replyOpen, quote, parentId])
|
}, [replyOpen, quote, parentId])
|
||||||
|
|
||||||
|
const placeholder = useMemo(() => {
|
||||||
|
return [
|
||||||
|
'comment for currency?',
|
||||||
|
'fractions of a penny for your thoughts?',
|
||||||
|
'put your money where your mouth is?'
|
||||||
|
][parentId % 3]
|
||||||
|
}, [parentId])
|
||||||
|
|
||||||
const onSubmit = useItemSubmit(CREATE_COMMENT, {
|
const onSubmit = useItemSubmit(CREATE_COMMENT, {
|
||||||
extraValues: { parentId },
|
extraValues: { parentId },
|
||||||
paidMutationOptions: {
|
paidMutationOptions: {
|
||||||
|
@ -227,14 +227,15 @@ export default function UpVote ({ item, className }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fillColor = meSats && (hover || pending ? nextColor : color)
|
const style = useMemo(() => {
|
||||||
|
const fillColor = pending || hover ? nextColor : color
|
||||||
const style = useMemo(() => (fillColor
|
return meSats || hover || pending
|
||||||
? {
|
? {
|
||||||
fill: fillColor,
|
fill: fillColor,
|
||||||
filter: `drop-shadow(0 0 6px ${fillColor}90)`
|
filter: `drop-shadow(0 0 6px ${fillColor}90)`
|
||||||
}
|
}
|
||||||
: undefined), [fillColor])
|
: undefined
|
||||||
|
}, [hover, pending, nextColor, color, meSats])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={ref} className='upvoteParent'>
|
<div ref={ref} className='upvoteParent'>
|
||||||
|
@ -5,6 +5,13 @@
|
|||||||
-webkit-touch-callout: none;
|
-webkit-touch-callout: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.boost {
|
||||||
|
fill: var(--theme-clickToContextColor);
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
}
|
||||||
|
|
||||||
.upvoteWrapper {
|
.upvoteWrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-right: .2rem;
|
padding-right: .2rem;
|
||||||
|
@ -62,7 +62,7 @@ export const ITEM_FILTER_THRESHOLD = 1.2
|
|||||||
export const DONT_LIKE_THIS_COST = 1
|
export const DONT_LIKE_THIS_COST = 1
|
||||||
export const COMMENT_TYPE_QUERY = ['comments', 'freebies', 'outlawed', 'borderland', 'all', 'bookmarks']
|
export const COMMENT_TYPE_QUERY = ['comments', 'freebies', 'outlawed', 'borderland', 'all', 'bookmarks']
|
||||||
export const USER_SORTS = ['value', 'stacking', 'spending', 'comments', 'posts', 'referrals']
|
export const USER_SORTS = ['value', 'stacking', 'spending', 'comments', 'posts', 'referrals']
|
||||||
export const ITEM_SORTS = ['zaprank', 'comments', 'sats']
|
export const ITEM_SORTS = ['zaprank', 'comments', 'sats', 'boost']
|
||||||
export const SUB_SORTS = ['stacking', 'revenue', 'spending', 'posts', 'comments']
|
export const SUB_SORTS = ['stacking', 'revenue', 'spending', 'posts', 'comments']
|
||||||
export const WHENS = ['day', 'week', 'month', 'year', 'forever', 'custom']
|
export const WHENS = ['day', 'week', 'month', 'year', 'forever', 'custom']
|
||||||
export const ITEM_TYPES_USER = ['all', 'posts', 'comments', 'bounties', 'links', 'discussions', 'polls', 'freebies', 'jobs', 'bookmarks']
|
export const ITEM_TYPES_USER = ['all', 'posts', 'comments', 'bounties', 'links', 'discussions', 'polls', 'freebies', 'jobs', 'bookmarks']
|
||||||
|
@ -22,14 +22,14 @@ export class Relay {
|
|||||||
constructor (relayUrl) {
|
constructor (relayUrl) {
|
||||||
const ws = new WebSocket(relayUrl)
|
const ws = new WebSocket(relayUrl)
|
||||||
|
|
||||||
ws.onmessage = function (msg) {
|
ws.onmessage = (msg) => {
|
||||||
const [type, notice] = JSON.parse(msg.data)
|
const [type, notice] = JSON.parse(msg.data)
|
||||||
if (type === 'NOTICE') {
|
if (type === 'NOTICE') {
|
||||||
console.log('relay notice:', notice)
|
console.log('relay notice:', notice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ws.onerror = function (err) {
|
ws.onerror = (err) => {
|
||||||
console.error('websocket error:', err.message)
|
console.error('websocket error:', err.message)
|
||||||
this.error = err.message
|
this.error = err.message
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
export default function getColor (meSats) {
|
export default function getColor (meSats) {
|
||||||
if (!meSats || meSats <= 10) {
|
if (!meSats || meSats === 0) {
|
||||||
|
return '#a5a5a5'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (meSats <= 10) {
|
||||||
return 'var(--bs-secondary)'
|
return 'var(--bs-secondary)'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ export default function Rewards ({ ssrData }) {
|
|||||||
return (
|
return (
|
||||||
<Layout footerLinks>
|
<Layout footerLinks>
|
||||||
{ad &&
|
{ad &&
|
||||||
<div className='pt-3 align-self-center' style={{ maxWidth: '480px', width: '100%' }}>
|
<div className='pt-3 align-self-center' style={{ maxWidth: '500px', width: '100%' }}>
|
||||||
<div className='fw-bold text-muted pb-2'>
|
<div className='fw-bold text-muted pb-2'>
|
||||||
top boost this month
|
top boost this month
|
||||||
</div>
|
</div>
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
CREATE OR REPLACE FUNCTION expire_boost_jobs()
|
||||||
|
RETURNS INTEGER
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
DECLARE
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO pgboss.job (name, data, retrylimit, retrybackoff, startafter, expirein)
|
||||||
|
SELECT 'expireBoost', jsonb_build_object('id', "Item".id), 21, true, now(), interval '1 days'
|
||||||
|
FROM "Item"
|
||||||
|
WHERE "Item".boost > 0 ON CONFLICT DO NOTHING;
|
||||||
|
return 0;
|
||||||
|
EXCEPTION WHEN OTHERS THEN
|
||||||
|
return 0;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
SELECT expire_boost_jobs();
|
||||||
|
DROP FUNCTION IF EXISTS expire_boost_jobs;
|
@ -1,8 +1,8 @@
|
|||||||
const { ApolloClient, InMemoryCache, HttpLink, gql } = require('@apollo/client')
|
const { ApolloClient, InMemoryCache, HttpLink, gql } = require('@apollo/client')
|
||||||
|
|
||||||
const ITEMS = gql`
|
const ITEMS = gql`
|
||||||
query items ($sort: String, $when: String, $sub: String) {
|
query items ($sort: String, $when: String, $sub: String, $by: String) {
|
||||||
items (sort: $sort, when: $when, sub: $sub) {
|
items (sort: $sort, when: $when, sub: $sub, by: $by) {
|
||||||
cursor
|
cursor
|
||||||
items {
|
items {
|
||||||
id
|
id
|
||||||
@ -15,6 +15,7 @@ const ITEMS = gql`
|
|||||||
location
|
location
|
||||||
remote
|
remote
|
||||||
boost
|
boost
|
||||||
|
subName
|
||||||
user {
|
user {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
@ -152,15 +153,15 @@ async function main () {
|
|||||||
variables: { sort: 'top', when: 'week', sub: 'meta' }
|
variables: { sort: 'top', when: 'week', sub: 'meta' }
|
||||||
})
|
})
|
||||||
|
|
||||||
const jobs = await client.query({
|
const ama = await client.query({
|
||||||
query: ITEMS,
|
query: ITEMS,
|
||||||
variables: { sub: 'jobs' }
|
variables: { sort: 'top', when: 'week', sub: 'ama' }
|
||||||
})
|
})
|
||||||
|
|
||||||
// const thisDay = await client.query({
|
const boosts = await client.query({
|
||||||
// query: SEARCH,
|
query: ITEMS,
|
||||||
// variables: { q: 'This Day in Stacker News @Undisciplined', sort: 'recent', what: 'posts', when: 'week' }
|
variables: { sort: 'top', when: 'forever', by: 'boost' }
|
||||||
// })
|
})
|
||||||
|
|
||||||
const topMeme = await bountyWinner('meme monday')
|
const topMeme = await bountyWinner('meme monday')
|
||||||
const topFact = await bountyWinner('fun fact')
|
const topFact = await bountyWinner('fun fact')
|
||||||
@ -179,6 +180,13 @@ ${top.data.items.items.map((item, i) =>
|
|||||||
`${i + 1}. [${item.title}](https://stacker.news/items/${item.id})
|
`${i + 1}. [${item.title}](https://stacker.news/items/${item.id})
|
||||||
- ${abbrNum(item.sats)} sats${item.boost ? ` \\ ${abbrNum(item.boost)} boost` : ''} \\ ${item.ncomments} comments \\ [@${item.user.name}](https://stacker.news/${item.user.name})\n`).join('')}
|
- ${abbrNum(item.sats)} sats${item.boost ? ` \\ ${abbrNum(item.boost)} boost` : ''} \\ ${item.ncomments} comments \\ [@${item.user.name}](https://stacker.news/${item.user.name})\n`).join('')}
|
||||||
|
|
||||||
|
##### Top AMAs
|
||||||
|
${ama.data.items.items.slice(0, 3).map((item, i) =>
|
||||||
|
`${i + 1}. [${item.title}](https://stacker.news/items/${item.id})
|
||||||
|
- ${abbrNum(item.sats)} sats${item.boost ? ` \\ ${abbrNum(item.boost)} boost` : ''} \\ ${item.ncomments} comments \\ [@${item.user.name}](https://stacker.news/${item.user.name})\n`).join('')}
|
||||||
|
|
||||||
|
[**all AMAs**](https://stacker.news/~meta/top/posts/forever)
|
||||||
|
|
||||||
##### Don't miss
|
##### Don't miss
|
||||||
${top.data.items.items.map((item, i) =>
|
${top.data.items.items.map((item, i) =>
|
||||||
`- [${item.title}](https://stacker.news/items/${item.id})\n`).join('')}
|
`- [${item.title}](https://stacker.news/items/${item.id})\n`).join('')}
|
||||||
@ -230,9 +238,12 @@ ${topCowboys.map((user, i) =>
|
|||||||
|
|
||||||
------
|
------
|
||||||
|
|
||||||
##### Promoted jobs
|
##### Top Boosts
|
||||||
${jobs.data.items.items.filter(i => i.boost > 0).slice(0, 5).map((item, i) =>
|
${boosts.data.items.items.map((item, i) =>
|
||||||
`${i + 1}. [${item.title.trim()} \\ ${item.company} \\ ${item.location}${item.remote ? ' or Remote' : ''}](https://stacker.news/items/${item.id})\n`).join('')}
|
item.subName === 'jobs'
|
||||||
|
? `${i + 1}. [${item.title.trim()} \\ ${item.company} \\ ${item.location}${item.remote ? ' or Remote' : ''}](https://stacker.news/items/${item.id})\n`
|
||||||
|
: `${i + 1}. [${item.title.trim()}](https://stacker.news/items/${item.id})\n`
|
||||||
|
).join('')}
|
||||||
|
|
||||||
[**all jobs**](https://stacker.news/~jobs)
|
[**all jobs**](https://stacker.news/~jobs)
|
||||||
|
|
||||||
|
1
svgs/arrow-up-double-line.svg
Normal file
1
svgs/arrow-up-double-line.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M12 4.83582L5.79291 11.0429L7.20712 12.4571L12 7.66424L16.7929 12.4571L18.2071 11.0429L12 4.83582ZM12 10.4857L5.79291 16.6928L7.20712 18.107L12 13.3141L16.7929 18.107L18.2071 16.6928L12 10.4857Z"></path></svg>
|
After Width: | Height: | Size: 298 B |
@ -16,7 +16,7 @@ export async function expireBoost ({ data: { id }, models }) {
|
|||||||
AND "itemId" = ${Number(id)}::INTEGER
|
AND "itemId" = ${Number(id)}::INTEGER
|
||||||
)
|
)
|
||||||
UPDATE "Item"
|
UPDATE "Item"
|
||||||
SET boost = COALESCE(boost.cur_msats, 0), "oldBoost" = COALESCE(boost.old_msats, 0)
|
SET boost = COALESCE(boost.cur_msats, 0) / 1000, "oldBoost" = COALESCE(boost.old_msats, 0) / 1000
|
||||||
FROM boost
|
FROM boost
|
||||||
WHERE "Item".id = ${Number(id)}::INTEGER`
|
WHERE "Item".id = ${Number(id)}::INTEGER`
|
||||||
],
|
],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user