Compare commits
17 Commits
32ea514286
...
76f90e0691
Author | SHA1 | Date | |
---|---|---|---|
|
76f90e0691 | ||
|
2a08abd90c | ||
|
5fa7fd9a83 | ||
|
a0b402b4d6 | ||
|
f0334b6719 | ||
|
5c18ef2317 | ||
|
e7fec21375 | ||
|
b995035f46 | ||
|
2ee730f8b5 | ||
|
a0e705b1c0 | ||
|
c2d207fbbb | ||
|
168fd95bf0 | ||
|
fa237d98c9 | ||
|
2bf11dc848 | ||
|
a785f907cb | ||
|
9d897e9bf7 | ||
|
6e75b9d274 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -32,6 +32,9 @@ envbak
|
|||||||
.env*
|
.env*
|
||||||
!.env.sample
|
!.env.sample
|
||||||
|
|
||||||
|
# local settings
|
||||||
|
.vscode/settings.json
|
||||||
|
|
||||||
# vercel
|
# vercel
|
||||||
.vercel
|
.vercel
|
||||||
|
|
||||||
|
20
awards.csv
20
awards.csv
@ -1,5 +1,5 @@
|
|||||||
name,type,pr id,issue ids,difficulty,priority,changes requested,notes,amount,receive method,date paid
|
name,type,pr id,issue ids,difficulty,priority,changes requested,notes,amount,receive method,date paid
|
||||||
jp-melanson,pr,#898,#680,good-first-issue,,,,20k,jpmelanson@getalby.com,2024-03-16
|
jp30566347,pr,#898,#680,good-first-issue,,,,20k,jpmelanson@getalby.com,2024-03-16
|
||||||
NEEDcreations,issue,#898,#680,good-first-issue,,,,2k,NEEDcreations@stacker.news,2024-03-16
|
NEEDcreations,issue,#898,#680,good-first-issue,,,,2k,NEEDcreations@stacker.news,2024-03-16
|
||||||
SatsAllDay,docs,#925,,,,,typo,100,weareallsatoshi@getalby.com,2024-03-16
|
SatsAllDay,docs,#925,,,,,typo,100,weareallsatoshi@getalby.com,2024-03-16
|
||||||
SatsAllDay,issue,#933,#928,medium,,,,25k,weareallsatoshi@getalby.com,2024-03-18
|
SatsAllDay,issue,#933,#928,medium,,,,25k,weareallsatoshi@getalby.com,2024-03-18
|
||||||
@ -18,7 +18,23 @@ felipebueno,pr,#948,,,,,,100k,felipe@stacker.news,2024-03-26
|
|||||||
benalleng,pr,#972,#923,good-first-issue,,,,20k,BenAllenG@stacker.news,2024-03-26
|
benalleng,pr,#972,#923,good-first-issue,,,,20k,BenAllenG@stacker.news,2024-03-26
|
||||||
SatsAllDay,issue,#972,#923,good-first-issue,,,,2k,weareallsatoshi@getalby.com,2024-03-26
|
SatsAllDay,issue,#972,#923,good-first-issue,,,,2k,weareallsatoshi@getalby.com,2024-03-26
|
||||||
felipebueno,pr,#974,#884,good-first-issue,,,,20k,felipe@stacker.news,2024-03-26
|
felipebueno,pr,#974,#884,good-first-issue,,,,20k,felipe@stacker.news,2024-03-26
|
||||||
h0dlr,issue,#974,#884,good-first-issue,,,,2k,???,???
|
h0dlr,issue,#974,#884,good-first-issue,,,,2k,0xe14b9b5981c729a3@ln.tips,2024-04-04
|
||||||
benalleng,pr,#975,,,,,,20k,BenAllenG@stacker.news,2024-03-26
|
benalleng,pr,#975,,,,,,20k,BenAllenG@stacker.news,2024-03-26
|
||||||
SatsAllDay,security,#980,GHSA-qg4g-m4xq-695p,,,,,100k,weareallsatoshi@getalby.com,2024-03-28
|
SatsAllDay,security,#980,GHSA-qg4g-m4xq-695p,,,,,100k,weareallsatoshi@getalby.com,2024-03-28
|
||||||
SatsAllDay,code review,#980,GHSA-qg4g-m4xq-695p,medium,,,,25k,weareallsatoshi@getalby.com,2024-03-28
|
SatsAllDay,code review,#980,GHSA-qg4g-m4xq-695p,medium,,,,25k,weareallsatoshi@getalby.com,2024-03-28
|
||||||
|
Darth-Coin,issue,#1009,#1002,easy,,,,10k,darthcoin@stacker.news,2024-04-04
|
||||||
|
atomantic,issue,#1009,#679,medium,high,,,50k,antic@stacker.news,2024-04-04
|
||||||
|
aniskhalfallah,pr,#1001,#976,good-first-issue,,,,20k,aniskhalfallah@stacker.news,2024-04-04
|
||||||
|
SatsAllDay,pr,#944,#1000,medium,,,,250k,weareallsatoshi@getalby.com,2024-04-04
|
||||||
|
SatsAllDay,issue,#944,#1000,medium,,,,25k,weareallsatoshi@getalby.com,2024-04-04
|
||||||
|
SatsAllDay,pr,#989,#984,medium,,,,250k,weareallsatoshi@getalby.com,2024-04-04
|
||||||
|
SatsAllDay,issue,#989,#984,medium,,,,25k,weareallsatoshi@getalby.com,2024-04-04
|
||||||
|
SouthKoreaLN,pr,#1015,#1010,good-first-issue,,,,20k,south_korea_ln@stacker.news,2024-04-04
|
||||||
|
SatsAllDay,issue,#1015,#1010,good-first-issue,,,,20k,weareallsatoshi@getalby.com,2024-04-04
|
||||||
|
jp30566347,pr,#991,#718,good-first-issue,,,,20k,jpmelanson@getalby.com,2024-04-04
|
||||||
|
benalleng,helpfulness,#1015,#1010,good-first-issue,,,,2k,BenAllenG@stacker.news,2024-04-04
|
||||||
|
felipebueno,pr,#1012,,,,,,20k,felipe@stacker.news,2024-04-24
|
||||||
|
abhiShandy,helpfulness,#1018,#1006,good-first-issue,,,identified problem,2k,???,2024-04-24
|
||||||
|
benalleng,issue,#1018,#1006,good-first-issue,,,,2k,BenAllenG@stacker.news,2024-04-04
|
||||||
|
benalleng,issue,#1011,#993,easy,high,,,20k,BenAllenG@stacker.news,2024-04-04
|
||||||
|
benalleng,pr,#1011,#993,easy,high,,tortured them,200k,BenAllenG@stacker.news,2024-04-04
|
||||||
|
|
@ -228,7 +228,7 @@ const WalletLoggerProvider = ({ children }) => {
|
|||||||
const log = { wallet, level, message, ts: +new Date() }
|
const log = { wallet, level, message, ts: +new Date() }
|
||||||
saveLog(log)
|
saveLog(log)
|
||||||
setLogs((prevLogs) => [...prevLogs, log])
|
setLogs((prevLogs) => [...prevLogs, log])
|
||||||
}, [setLogs, saveLog])
|
}, [saveLog])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WalletLogsContext.Provider value={logs}>
|
<WalletLogsContext.Provider value={logs}>
|
||||||
|
@ -35,19 +35,20 @@ export default function useModal () {
|
|||||||
setModalStack(modalStack.slice(0, -1))
|
setModalStack(modalStack.slice(0, -1))
|
||||||
modalOptions?.onClose?.()
|
modalOptions?.onClose?.()
|
||||||
return setModalContent(previousModalContent)
|
return setModalContent(previousModalContent)
|
||||||
}, [modalStack, setModalStack])
|
}, [modalStack, setModalStack, modalOptions?.onClose])
|
||||||
|
|
||||||
|
// this is called on every navigation due to below useEffect
|
||||||
const onClose = useCallback(() => {
|
const onClose = useCallback(() => {
|
||||||
setModalContent(null)
|
setModalContent(null)
|
||||||
setModalStack([])
|
setModalStack(ms => ms.length > 0 ? [] : ms)
|
||||||
modalOptions?.onClose?.()
|
modalOptions?.onClose?.()
|
||||||
}, [modalOptions?.onClose])
|
}, [setModalStack, setModalContent, modalOptions?.onClose])
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
router.events.on('routeChangeStart', onClose)
|
router.events.on('routeChangeStart', onClose)
|
||||||
return () => router.events.off('routeChangeStart', onClose)
|
return () => router.events.off('routeChangeStart', onClose)
|
||||||
}, [router, onClose])
|
}, [router.events, onClose])
|
||||||
|
|
||||||
const modal = useMemo(() => {
|
const modal = useMemo(() => {
|
||||||
if (modalContent === null) {
|
if (modalContent === null) {
|
||||||
@ -76,7 +77,7 @@ export default function useModal () {
|
|||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
</Modal>
|
</Modal>
|
||||||
)
|
)
|
||||||
}, [modalContent, onClose])
|
}, [modalContent, onClose, modalOptions, onBack, modalStack])
|
||||||
|
|
||||||
const showModal = useCallback(
|
const showModal = useCallback(
|
||||||
(getContent, options) => {
|
(getContent, options) => {
|
||||||
|
@ -236,8 +236,8 @@ export function SignUpButton ({ className = 'py-0' }) {
|
|||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
className={classNames('align-items-center ps-2 pe-3', className)}
|
className={classNames('align-items-center ps-2 pe-3', className)}
|
||||||
style={{ borderWidth: '2px' }}
|
style={{ borderWidth: '2px', width: '112px' }}
|
||||||
id='login'
|
id='signup'
|
||||||
onClick={() => handleLogin('/signup')}
|
onClick={() => handleLogin('/signup')}
|
||||||
>
|
>
|
||||||
<LightningIcon
|
<LightningIcon
|
||||||
@ -259,8 +259,8 @@ export default function LoginButton ({ className }) {
|
|||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
className='align-items-center px-3 py-1 mb-2'
|
className='align-items-center px-3 py-1 mb-2'
|
||||||
id='signup'
|
id='login'
|
||||||
style={{ borderWidth: '2px' }}
|
style={{ borderWidth: '2px', width: '112px' }}
|
||||||
variant='outline-grey-darkmode'
|
variant='outline-grey-darkmode'
|
||||||
onClick={() => handleLogin('/login')}
|
onClick={() => handleLogin('/login')}
|
||||||
>
|
>
|
||||||
@ -353,7 +353,7 @@ export function MeCorner ({ dropNavKey, me, className }) {
|
|||||||
<div className={className}>
|
<div className={className}>
|
||||||
<NavNotifications />
|
<NavNotifications />
|
||||||
<MeDropdown me={me} dropNavKey={dropNavKey} />
|
<MeDropdown me={me} dropNavKey={dropNavKey} />
|
||||||
<NavWalletSummary />
|
<NavWalletSummary className='d-inline-block' />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,9 @@ export default function BottomBar ({ sub }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames('d-block d-md-none', styles.footer, styles.footerPadding)}>
|
<nav className='d-block d-md-none'>
|
||||||
|
<div style={{ marginBottom: '53px' }} className={styles.footerPadding} />
|
||||||
|
<div className={classNames(styles.footer, styles.footerPadding)}>
|
||||||
<Navbar className='container px-0'>
|
<Navbar className='container px-0'>
|
||||||
<Nav className={styles.footerNav}>
|
<Nav className={styles.footerNav}>
|
||||||
<Offcanvas me={me} {...props} />
|
<Offcanvas me={me} {...props} />
|
||||||
@ -58,5 +60,6 @@ export default function BottomBar ({ sub }) {
|
|||||||
</Nav>
|
</Nav>
|
||||||
</Navbar>
|
</Navbar>
|
||||||
</div>
|
</div>
|
||||||
|
</nav>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
position: sticky;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: var(--bs-body-bg);
|
background-color: var(--bs-body-bg);
|
||||||
|
@ -22,9 +22,10 @@ export default function OffCanvas ({ me, dropNavKey }) {
|
|||||||
src={me?.photoId ? `${MEDIA_URL}/${me.photoId}` : '/dorian400.jpg'} width='28' height='28'
|
src={me?.photoId ? `${MEDIA_URL}/${me.photoId}` : '/dorian400.jpg'} width='28' height='28'
|
||||||
style={{ clipPath: 'polygon(0 0, 83% 0, 100% 100%, 17% 100%)' }}
|
style={{ clipPath: 'polygon(0 0, 83% 0, 100% 100%, 17% 100%)' }}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
|
className='pointer'
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
: <span className='text-muted'><AnonIcon onClick={onClick} width='22' height='22' /></span>
|
: <span className='text-muted pointer'><AnonIcon onClick={onClick} width='22' height='22' /></span>
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -7,24 +7,26 @@ import classNames from 'classnames'
|
|||||||
|
|
||||||
export default function StickyBar ({ prefix, sub, path, topNavKey, dropNavKey }) {
|
export default function StickyBar ({ prefix, sub, path, topNavKey, dropNavKey }) {
|
||||||
const ref = useRef()
|
const ref = useRef()
|
||||||
const sticky = useRef()
|
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const observer = new window.IntersectionObserver(([entry]) => {
|
const stick = () => {
|
||||||
sticky?.current?.classList.toggle(styles.hide, entry.isIntersecting)
|
if (window.scrollY > 100) {
|
||||||
})
|
ref.current?.classList.remove(styles.hide)
|
||||||
ref?.current && observer.observe(ref.current)
|
} else {
|
||||||
|
ref.current?.classList.add(styles.hide)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('scroll', stick)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
ref?.current && observer.unobserve(ref.current)
|
window.removeEventListener('scroll', stick)
|
||||||
}
|
}
|
||||||
}, [ref?.current, sticky?.current])
|
}, [ref?.current])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className={classNames(styles.hide, styles.sticky)} ref={ref}>
|
||||||
<div ref={ref} style={{ position: 'relative', top: '50px' }} />
|
|
||||||
<div className={classNames(styles.hide, styles.sticky)} ref={sticky}>
|
|
||||||
<Container className='px-0 d-none d-md-block'>
|
<Container className='px-0 d-none d-md-block'>
|
||||||
<Navbar className='py-0'>
|
<Navbar className='py-0'>
|
||||||
<Nav
|
<Nav
|
||||||
@ -52,6 +54,5 @@ export default function StickyBar ({ prefix, sub, path, topNavKey, dropNavKey })
|
|||||||
</Navbar>
|
</Navbar>
|
||||||
</Container>
|
</Container>
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -531,7 +531,7 @@ export default function Notifications ({ ssrData }) {
|
|||||||
}
|
}
|
||||||
}, router.asPath, { ...router.options, shallow: true })
|
}, router.asPath, { ...router.options, shallow: true })
|
||||||
}
|
}
|
||||||
}, [router, lastChecked])
|
}, [router?.query?.checkedAt, lastChecked])
|
||||||
|
|
||||||
if (!dat) return <CommentsFlatSkeleton />
|
if (!dat) return <CommentsFlatSkeleton />
|
||||||
|
|
||||||
@ -540,7 +540,7 @@ export default function Notifications ({ ssrData }) {
|
|||||||
{notifications.map(n =>
|
{notifications.map(n =>
|
||||||
<Notification
|
<Notification
|
||||||
n={n} key={nid(n)}
|
n={n} key={nid(n)}
|
||||||
fresh={new Date(n.sortTime) > new Date(router?.query?.checkedAt)}
|
fresh={new Date(n.sortTime) > new Date(router?.query?.checkedAt ?? lastChecked)}
|
||||||
/>)}
|
/>)}
|
||||||
<MoreFooter cursor={cursor} count={notifications?.length} fetchMore={fetchMore} Skeleton={CommentsFlatSkeleton} noMoreText='NO MORE' />
|
<MoreFooter cursor={cursor} count={notifications?.length} fetchMore={fetchMore} Skeleton={CommentsFlatSkeleton} noMoreText='NO MORE' />
|
||||||
</>
|
</>
|
||||||
|
@ -36,16 +36,6 @@ export const ToastProvider = ({ children }) => {
|
|||||||
const [toasts, setToasts] = useState([])
|
const [toasts, setToasts] = useState([])
|
||||||
const toastId = useRef(0)
|
const toastId = useRef(0)
|
||||||
|
|
||||||
const dispatchToast = useCallback((toast) => {
|
|
||||||
toast = {
|
|
||||||
...toast,
|
|
||||||
createdAt: +new Date(),
|
|
||||||
id: toastId.current++
|
|
||||||
}
|
|
||||||
setToasts(toasts => ensureFlow(toasts, toast).map(mapHidden(toast)))
|
|
||||||
return () => removeToast(toast)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const removeToast = useCallback(({ id, onCancel, tag }) => {
|
const removeToast = useCallback(({ id, onCancel, tag }) => {
|
||||||
setToasts(toasts => toasts.filter(toast => {
|
setToasts(toasts => toasts.filter(toast => {
|
||||||
if (toast.id === id) {
|
if (toast.id === id) {
|
||||||
@ -65,11 +55,21 @@ export const ToastProvider = ({ children }) => {
|
|||||||
// remove toasts with same tag if they are not cancelable
|
// remove toasts with same tag if they are not cancelable
|
||||||
return false
|
return false
|
||||||
}))
|
}))
|
||||||
}, [])
|
}, [setToasts])
|
||||||
|
|
||||||
|
const dispatchToast = useCallback((toast) => {
|
||||||
|
toast = {
|
||||||
|
...toast,
|
||||||
|
createdAt: +new Date(),
|
||||||
|
id: toastId.current++
|
||||||
|
}
|
||||||
|
setToasts(toasts => ensureFlow(toasts, toast).map(mapHidden(toast)))
|
||||||
|
return () => removeToast(toast)
|
||||||
|
}, [setToasts, removeToast])
|
||||||
|
|
||||||
const endFlow = useCallback((flowId) => {
|
const endFlow = useCallback((flowId) => {
|
||||||
setToasts(toasts => toasts.filter(toast => toast.flowId !== flowId))
|
setToasts(toasts => toasts.filter(toast => toast.flowId !== flowId))
|
||||||
}, [])
|
}, [setToasts])
|
||||||
|
|
||||||
const toaster = useMemo(() => ({
|
const toaster = useMemo(() => ({
|
||||||
success: (body, options) => {
|
success: (body, options) => {
|
||||||
@ -110,13 +110,13 @@ export const ToastProvider = ({ children }) => {
|
|||||||
// Only clear toasts with no cancel function on page navigation
|
// Only clear toasts with no cancel function on page navigation
|
||||||
// since navigation should not interfere with being able to cancel an action.
|
// since navigation should not interfere with being able to cancel an action.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleRouteChangeStart = () => setToasts(toasts => toasts.filter(({ onCancel, onUndo }) => onCancel || onUndo), [])
|
const handleRouteChangeStart = () => setToasts(toasts => toasts.length > 0 ? toasts.filter(({ onCancel, onUndo }) => onCancel || onUndo) : toasts)
|
||||||
router.events.on('routeChangeStart', handleRouteChangeStart)
|
router.events.on('routeChangeStart', handleRouteChangeStart)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
router.events.off('routeChangeStart', handleRouteChangeStart)
|
router.events.off('routeChangeStart', handleRouteChangeStart)
|
||||||
}
|
}
|
||||||
}, [router])
|
}, [router.events, setToasts])
|
||||||
|
|
||||||
// this function merges toasts with the same tag into one toast.
|
// this function merges toasts with the same tag into one toast.
|
||||||
// for example: 3x 'zap pending' -> '(3) zap pending'
|
// for example: 3x 'zap pending' -> '(3) zap pending'
|
||||||
|
@ -131,7 +131,7 @@ export function NWCProvider ({ children }) {
|
|||||||
} finally {
|
} finally {
|
||||||
setInitialized(true)
|
setInitialized(true)
|
||||||
}
|
}
|
||||||
}, [logger])
|
}, [validateParams, logger])
|
||||||
|
|
||||||
const saveConfig = useCallback(async (config) => {
|
const saveConfig = useCallback(async (config) => {
|
||||||
// immediately store config so it's not lost even if config is invalid
|
// immediately store config so it's not lost even if config is invalid
|
||||||
@ -235,8 +235,12 @@ export function NWCProvider ({ children }) {
|
|||||||
},
|
},
|
||||||
onclose (reason) {
|
onclose (reason) {
|
||||||
clearTimeout(timer)
|
clearTimeout(timer)
|
||||||
reject(new Error(reason))
|
if (!['closed by caller', 'relay connection closed by us'].includes(reason)) {
|
||||||
sub?.close()
|
// only log if not closed by us (caller)
|
||||||
|
const msg = 'connection closed: ' + (reason || 'unknown reason')
|
||||||
|
logger.error(msg)
|
||||||
|
reject(new Error(msg))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})().catch(reject)
|
})().catch(reject)
|
||||||
@ -252,7 +256,7 @@ export function NWCProvider ({ children }) {
|
|||||||
// relay?.close()
|
// relay?.close()
|
||||||
if (relay) logger.info(`closed connection to ${relayUrl}`)
|
if (relay) logger.info(`closed connection to ${relayUrl}`)
|
||||||
}
|
}
|
||||||
}, [walletPubkey, secret, logger])
|
}, [walletPubkey, relayUrl, secret, logger])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadConfig().catch(err => logger.error(err.message || err.toString?.()))
|
loadConfig().catch(err => logger.error(err.message || err.toString?.()))
|
||||||
|
@ -20,6 +20,7 @@ import { Col, Row } from 'react-bootstrap'
|
|||||||
import { proportions } from '@/lib/madness'
|
import { proportions } from '@/lib/madness'
|
||||||
import { useData } from '@/components/use-data'
|
import { useData } from '@/components/use-data'
|
||||||
import { GrowthPieChartSkeleton } from '@/components/charts-skeletons'
|
import { GrowthPieChartSkeleton } from '@/components/charts-skeletons'
|
||||||
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
const GrowthPieChart = dynamic(() => import('@/components/charts').then(mod => mod.GrowthPieChart), {
|
const GrowthPieChart = dynamic(() => import('@/components/charts').then(mod => mod.GrowthPieChart), {
|
||||||
loading: () => <GrowthPieChartSkeleton />
|
loading: () => <GrowthPieChartSkeleton />
|
||||||
@ -95,15 +96,20 @@ export default function Rewards ({ ssrData }) {
|
|||||||
REWARDS,
|
REWARDS,
|
||||||
SSR ? {} : { pollInterval: 1000, nextFetchPolicy: 'cache-and-network' })
|
SSR ? {} : { pollInterval: 1000, nextFetchPolicy: 'cache-and-network' })
|
||||||
const { data } = useQuery(REWARDS_FULL)
|
const { data } = useQuery(REWARDS_FULL)
|
||||||
if (!data && !ssrData) return <PageLoading />
|
const dat = useData(data, ssrData)
|
||||||
|
|
||||||
|
let { rewards: [{ total, sources, time, leaderboard }] } = useMemo(() => {
|
||||||
|
return dat || { rewards: [{}] }
|
||||||
|
}, [dat])
|
||||||
|
|
||||||
let { rewards: [{ total, sources, time, leaderboard }] } = useData(data, ssrData)
|
|
||||||
if (rewardsData?.rewards?.length > 0) {
|
if (rewardsData?.rewards?.length > 0) {
|
||||||
total = rewardsData.rewards[0].total
|
total = rewardsData.rewards[0].total
|
||||||
sources = rewardsData.rewards[0].sources
|
sources = rewardsData.rewards[0].sources
|
||||||
time = rewardsData.rewards[0].time
|
time = rewardsData.rewards[0].time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!dat) return <PageLoading />
|
||||||
|
|
||||||
function EstimatedReward ({ rank }) {
|
function EstimatedReward ({ rank }) {
|
||||||
const totalRest = total - 1000000
|
const totalRest = total - 1000000
|
||||||
return (
|
return (
|
||||||
|
43
sndev
43
sndev
@ -305,14 +305,47 @@ sndev__help_stacker_lncli() {
|
|||||||
docker__stacker_lnd --help
|
docker__stacker_lnd --help
|
||||||
}
|
}
|
||||||
|
|
||||||
sndev__pr() {
|
__sndev__pr_track() {
|
||||||
shift
|
json=$(curl -fsSH "Accept: application/vnd.github.v3+json" "https://api.github.com/repos/stackernews/stacker.news/pulls/$1")
|
||||||
|
case $(git config --get remote.origin.url) in
|
||||||
|
"http"*) url=$(echo "$json" | grep -e '"clone_url"' | head -n1 | sed -e 's/^.*"clone_url":[[:space:]]*"//; s/",[[:space:]]*$//') ;;
|
||||||
|
*) url=$(echo "$json" | grep -e '"ssh_url"' | head -n1 | sed -e 's/^.*"ssh_url":[[:space:]]*"//; s/",[[:space:]]*$//') ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
push=$(git remote -v | grep -e "$url .*push" | head -n1) || true
|
||||||
|
if [ -n "$push" ]; then
|
||||||
|
remote=$(printf "%s" $(cut -f 1 <<<"$push"))
|
||||||
|
else
|
||||||
|
remote=$(echo "$json" | grep -e '"login"' | head -n1 | sed -e 's/^.*"login":[[:space:]]*"//; s/",[[:space:]]*$//')
|
||||||
|
git remote remove "$remote" 1>/dev/null 2>&1 || true
|
||||||
|
git remote add "$remote" "$url"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ref=$(echo "$json" | grep -e '"ref"' | head -n1 | sed -e 's/^.*"ref":[[:space:]]*"//; s/",[[:space:]]*$//')
|
||||||
|
git fetch "$remote" "$ref"
|
||||||
|
git checkout -b "pr/$1" "$remote/$ref"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
__sndev__pr_detach() {
|
||||||
refspec="+refs/pull/$1/head:refs/remotes/pr/$1"
|
refspec="+refs/pull/$1/head:refs/remotes/pr/$1"
|
||||||
case $(git config --get remote.origin.url) in
|
case $(git config --get remote.origin.url) in
|
||||||
"http"*) git fetch https://github.com/stackernews/stacker.news.git "$refspec" ;;
|
"http"*) git fetch https://github.com/stackernews/stacker.news.git "$refspec" ;;
|
||||||
*) git fetch git@github.com:stackernews/stacker.news.git "$refspec" ;;
|
*) git fetch git@github.com:stackernews/stacker.news.git "$refspec" ;;
|
||||||
esac
|
esac
|
||||||
git checkout "pr/$1"
|
git checkout "pr/$1"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
sndev__pr() {
|
||||||
|
shift
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
-t|--track)
|
||||||
|
call "__sndev__pr_track" "$2" ;;
|
||||||
|
*)
|
||||||
|
call "__sndev__pr_detach" "$1" ;;
|
||||||
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
sndev__help_pr() {
|
sndev__help_pr() {
|
||||||
@ -320,7 +353,11 @@ sndev__help_pr() {
|
|||||||
fetch and checkout a pr
|
fetch and checkout a pr
|
||||||
|
|
||||||
USAGE
|
USAGE
|
||||||
$ sndev pr <pr number>
|
$ sndev pr [OPTIONS] <pr number>
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
-t, --track track the pr in a new branch, creating a remote if necessary
|
||||||
|
defaults to checking out the pr in a detached state
|
||||||
"
|
"
|
||||||
|
|
||||||
echo "$help"
|
echo "$help"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user