Compare commits

..

6 Commits

Author SHA1 Message Date
ekzyis
050122c665
Use global score for top (#1202)
* Use global score for comments ordered by top

* Use global score for global top feed
2024-05-30 09:21:55 -05:00
ekzyis
6047c37e4e
Use refs for modals (#1200)
This fixes concurrent showModal calls with stale values which lead to modals getting replaced instead of stacked.
2024-05-30 09:20:33 -05:00
ekzyis
2e346b488d
Fix missing pointer for anon info (#1201) 2024-05-29 08:32:57 -05:00
ekzyis
4e14e2b5d3
Remove kr from SN users (#1203) 2024-05-29 08:29:48 -05:00
ekzyis
30718b9e1b
Fix TypeError due to invalid URL (#1206) 2024-05-29 08:26:42 -05:00
Keyan
738333efa3
Update awards.csv 2024-05-28 19:30:30 -05:00
6 changed files with 78 additions and 100 deletions

View File

@ -27,18 +27,11 @@ function commentsOrderByClause (me, models, sort) {
return 'ORDER BY "Item".created_at DESC, "Item".id DESC'
}
if (me) {
if (sort === 'top') {
return `ORDER BY COALESCE(
personal_top_score,
${orderByNumerator(models, 0)}) DESC NULLS LAST,
"Item".msats DESC, ("Item".freebie IS FALSE) DESC, "Item".id DESC`
} else {
return `ORDER BY COALESCE(
if (me && sort === 'hot') {
return `ORDER BY COALESCE(
personal_hot_score,
${orderByNumerator(models, 0)}/POWER(GREATEST(3, EXTRACT(EPOCH FROM (now_utc() - "Item".created_at))/3600), 1.3)) DESC NULLS LAST,
"Item".msats DESC, ("Item".freebie IS FALSE) DESC, "Item".id DESC`
}
} else {
if (sort === 'top') {
return `ORDER BY ${orderByNumerator(models, 0)} DESC NULLS LAST, "Item".msats DESC, ("Item".freebie IS FALSE) DESC, "Item".id DESC`
@ -373,32 +366,10 @@ export default {
}, decodedCursor.time, decodedCursor.offset, limit, ...subArr)
break
case 'top':
if (me && (!by || by === 'zaprank') && (when === 'day' || when === 'week')) {
// personalized zaprank only goes back 7 days
items = await itemQueryWithMeta({
me,
models,
query: `
${SELECT}, GREATEST(g.tf_top_score, l.tf_top_score) AS rank
${relationClause(type)}
${joinZapRankPersonalView(me, models)}
${whereClause(
'"Item"."deletedAt" IS NULL',
subClause(sub, 5, subClauseTable(type), me, showNsfw),
typeClause(type),
whenClause(when, 'Item'),
await filterClause(me, models, type),
muteClause(me))}
ORDER BY rank DESC
OFFSET $3
LIMIT $4`,
orderBy: 'ORDER BY rank DESC'
}, ...whenRange(when, from, to || decodedCursor.time), decodedCursor.offset, limit, ...subArr)
} else {
items = await itemQueryWithMeta({
me,
models,
query: `
items = await itemQueryWithMeta({
me,
models,
query: `
${selectClause(type)}
${relationClause(type)}
${whereClause(
@ -411,9 +382,8 @@ export default {
${orderByClause(by || 'zaprank', me, models, type)}
OFFSET $3
LIMIT $4`,
orderBy: orderByClause(by || 'zaprank', me, models, type)
}, ...whenRange(when, from, to || decodedCursor.time), decodedCursor.offset, limit, ...subArr)
}
orderBy: orderByClause(by || 'zaprank', me, models, type)
}, ...whenRange(when, from, to || decodedCursor.time), decodedCursor.offset, limit, ...subArr)
break
default:
// sub so we know the default ranking

View File

@ -102,5 +102,5 @@ OneOneSeven117,issue,#1187,#1164,easy,,,,10k,OneOneSeven@stacker.news,2024-05-23
tsmith123,pr,#1191,#134,medium,,,required small fix,225k,stickymarch60@walletofsatoshi.com,2024-05-28
benalleng,helpfulness,#1191,#134,medium,,,did most of this before,100k,benalleng@mutiny.plus,2024-05-28
cointastical,issue,#1191,#134,medium,,,,22k,cointastical@stacker.news,2024-05-28
kravhen,pr,#1198,#1180,good-first-issue,,,required linting,18k,???,???
kravhen,pr,#1198,#1180,good-first-issue,,,required linting,18k,nichro@getalby.com,2024-05-28
OneOneSeven117,issue,#1198,#1180,good-first-issue,,,required linting,2k,OneOneSeven@stacker.news,2024-05-28

1 name type pr id issue ids difficulty priority changes requested notes amount receive method date paid
102 tsmith123 pr #1191 #134 medium required small fix 225k stickymarch60@walletofsatoshi.com 2024-05-28
103 benalleng helpfulness #1191 #134 medium did most of this before 100k benalleng@mutiny.plus 2024-05-28
104 cointastical issue #1191 #134 medium 22k cointastical@stacker.news 2024-05-28
105 kravhen pr #1198 #1180 good-first-issue required linting 18k ??? nichro@getalby.com ??? 2024-05-28
106 OneOneSeven117 issue #1198 #1180 good-first-issue required linting 2k OneOneSeven@stacker.news 2024-05-28

View File

@ -162,7 +162,7 @@ function AnonInfo () {
return (
<AnonIcon
className='ms-2 fill-theme-color' height={22} width={22}
className='ms-2 fill-theme-color pointer' height={22} width={22}
onClick={
(e) =>
showModal(onClose =>

View File

@ -1,4 +1,4 @@
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'
import { createContext, useCallback, useContext, useEffect, useMemo, useReducer, useRef } from 'react'
import Modal from 'react-bootstrap/Modal'
import BackArrow from '@/svgs/arrow-left-line.svg'
import { useRouter } from 'next/router'
@ -23,26 +23,27 @@ export function useShowModal () {
}
export default function useModal () {
const [modalContent, setModalContent] = useState(null)
const [modalOptions, setModalOptions] = useState(null)
const [modalStack, setModalStack] = useState([])
const modalStack = useRef([])
const [render, forceUpdate] = useReducer(x => x + 1, 0)
const getCurrentContent = useCallback(() => {
return modalStack.current[modalStack.current.length - 1]
}, [])
const onBack = useCallback(() => {
if (modalStack.length === 0) {
return setModalContent(null)
}
const previousModalContent = modalStack[modalStack.length - 1]
setModalStack(modalStack.slice(0, -1))
modalOptions?.onClose?.()
return setModalContent(previousModalContent)
}, [modalStack, setModalStack, modalOptions?.onClose])
getCurrentContent()?.options?.onClose?.()
modalStack.current.pop()
forceUpdate()
}, [])
// this is called on every navigation due to below useEffect
const onClose = useCallback(() => {
setModalContent(null)
setModalStack(ms => ms.length > 0 ? [] : ms)
modalOptions?.onClose?.()
}, [setModalStack, setModalContent, modalOptions?.onClose])
while (modalStack.current.length) {
getCurrentContent()?.options?.onClose?.()
modalStack.current.pop()
}
forceUpdate()
}, [])
const router = useRouter()
useEffect(() => {
@ -51,45 +52,49 @@ export default function useModal () {
}, [router.events, onClose])
const modal = useMemo(() => {
if (modalContent === null) {
if (modalStack.current.length === 0) {
return null
}
const className = modalOptions?.fullScreen ? 'fullscreen' : ''
const content = getCurrentContent()
const { overflow, keepOpen, fullScreen } = content.options || {}
const className = fullScreen ? 'fullscreen' : ''
return (
<Modal
onHide={modalOptions?.keepOpen ? null : onClose} show={!!modalContent}
onHide={keepOpen ? null : onClose} show={!!content}
className={className}
dialogClassName={className}
contentClassName={className}
>
<div className='d-flex flex-row'>
{modalOptions?.overflow &&
{overflow &&
<div className={'modal-btn modal-overflow ' + className}>
<ActionDropdown>
{modalOptions.overflow}
{overflow}
</ActionDropdown>
</div>}
{modalStack.length > 0 ? <div className='modal-btn modal-back' onClick={onBack}><BackArrow width={18} height={18} className='fill-white' /></div> : null}
{modalStack.current.length > 1 ? <div className='modal-btn modal-back' onClick={onBack}><BackArrow width={18} height={18} className='fill-white' /></div> : null}
<div className={'modal-btn modal-close ' + className} onClick={onClose}>X</div>
</div>
<Modal.Body className={className}>
{modalContent}
{content.node}
</Modal.Body>
</Modal>
)
}, [modalContent, onClose, modalOptions, onBack, modalStack])
}, [render])
const showModal = useCallback(
(getContent, options) => {
if (modalContent) {
if (options?.replaceModal) {
setModalStack(stack => ([]))
} else setModalStack(stack => ([...stack, modalContent]))
const ref = { node: getContent(onClose), options }
if (options?.replaceModal) {
modalStack.current = [ref]
} else {
modalStack.current.push(ref)
}
setModalOptions(options)
setModalContent(getContent(onClose))
forceUpdate()
},
[modalContent, onClose]
[onClose]
)
return [modal, showModal]

View File

@ -244,36 +244,39 @@ export default memo(function Text ({ rel, imgproxyUrls, children, tab, itemId, o
paddingRight: '15px'
}
const { provider, id, meta } = parseEmbedUrl(href)
// Youtube video embed
if (provider === 'youtube') {
return (
<div style={videoWrapperStyles}>
<YouTube
videoId={id} className={styles.videoContainer} opts={{
playerVars: {
start: meta?.start || 0
}
}}
/>
</div>
)
}
// Rumble video embed
if (provider === 'rumble') {
return (
<div style={videoWrapperStyles}>
<div className={styles.videoContainer}>
<iframe
title='Rumble Video'
allowFullScreen=''
src={meta?.href}
try {
const { provider, id, meta } = parseEmbedUrl(href)
// Youtube video embed
if (provider === 'youtube') {
return (
<div style={videoWrapperStyles}>
<YouTube
videoId={id} className={styles.videoContainer} opts={{
playerVars: {
start: meta?.start || 0
}
}}
/>
</div>
</div>
)
)
}
// Rumble video embed
if (provider === 'rumble') {
return (
<div style={videoWrapperStyles}>
<div className={styles.videoContainer}>
<iframe
title='Rumble Video'
allowFullScreen=''
src={meta?.href}
/>
</div>
</div>
)
}
} catch {
// ignore invalid URLs
}
// assume the link is an image which will fallback to link if it's not

View File

@ -36,7 +36,7 @@ export const ITEM_SPAM_INTERVAL = '10m'
export const ANON_ITEM_SPAM_INTERVAL = '0'
export const INV_PENDING_LIMIT = 100
export const BALANCE_LIMIT_MSATS = 100000000 // 100k sat
export const SN_USER_IDS = [616, 6030, 946, 4502, 27]
export const SN_USER_IDS = [616, 6030, 4502, 27]
export const SN_NO_REWARDS_IDS = [27, 4502]
export const ANON_INV_PENDING_LIMIT = 1000
export const ANON_BALANCE_LIMIT_MSATS = 0 // disable