SN distributes the sats it earns to top stackers like you daily. The top stackers make the top posts and comments or zap the top posts and comments early and generously. View the rewards pool and make a donation here.
click for details
)
}
function ReferralReward ({ n }) {
return (
you stacked {numWithUnits(n.earnedSats, { abbreviate: false })} in referral rewards{dayMonthYear(new Date(n.sortTime))}
{n.sources &&
{n.sources.forever > 0 && {numWithUnits(n.sources.forever, { abbreviate: false })} for stackers joining because of you}
{n.sources.oneDay > 0 && {n.sources.forever > 0 && ' \\ '}{numWithUnits(n.sources.oneDay, { abbreviate: false })} for stackers referred to content by you today}
}
SN gives referral rewards to stackers like you for referring the top stackers daily. You refer stackers when they visit your posts, comments, profile, territory, or if they visit SN through your referral links.
click for details
)
}
function RevenueNotification ({ n }) {
return (
you stacked {numWithUnits(n.earnedSats, { abbreviate: false })} in territory revenue{timeSince(new Date(n.sortTime))}
As the founder of territory ~{n.subName}, you receive 50% of the revenue it generates and the other 50% go to rewards.
)
}
function SubStatus ({ n }) {
const dueDate = nextBillingWithGrace(n.sub)
return (
{n.sub.status === 'ACTIVE'
? 'your territory is active again'
: (n.sub.status === 'GRACE'
? <>your territory payment for ~{n.sub.name} is due or your territory will be archived in >
: <>your territory ~{n.sub.name} has been archived>)}
click to visit territory and pay
)
}
function Invitification ({ n }) {
return (
<>
your invite has been redeemed by
{numWithUnits(n.invite.invitees.length, {
abbreviate: false,
unitSingular: 'stacker',
unitPlural: 'stackers'
})}
{numWithUnits(n.earnedSats, { abbreviate: false, unitSingular: 'sat was', unitPlural: 'sats were' })} withdrawn from your account
{timeSince(new Date(n.sortTime))}
{n.withdrawl.autoWithdraw && autowithdraw}
)
}
function Referral ({ n }) {
return (
someone joined SN because of you
{timeSince(new Date(n.sortTime))}
)
}
function Votification ({ n }) {
let forwardedSats = 0
let ForwardedUsers = null
if (n.item.forwards?.length) {
forwardedSats = Math.floor(n.earnedSats * n.item.forwards.map(fwd => fwd.pct).reduce((sum, cur) => sum + cur) / 100)
ForwardedUsers = () => n.item.forwards.map((fwd, i) =>
@{fwd.user.name}
{i !== n.item.forwards.length - 1 && ' '}
)
}
return (
<>
your {n.item.title ? 'post' : 'reply'} stacked {numWithUnits(n.earnedSats, { abbreviate: false })}
{n.item.forwards?.length > 0 &&
<>
{' '}and forwarded {numWithUnits(forwardedSats, { abbreviate: false })} to{' '}
>}
>
)
}
function ForwardedVotification ({ n }) {
return (
<>
you were forwarded {numWithUnits(n.earnedSats, { abbreviate: false })} from
>
)
}
function Mention ({ n }) {
return (
<>
you were mentioned in
>
)
}
function ItemMention ({ n }) {
return (
<>
your item was mentioned in
>
)
}
function JobChanged ({ n }) {
return (
<>
{n.item.status === 'ACTIVE'
? 'your job is active again'
: (n.item.status === 'NOSATS'
? 'your job promotion ran out of sats'
: 'your job has been stopped')}
>
)
}
function Reply ({ n }) {
return
}
function FollowActivity ({ n }) {
return (
<>
a stacker you subscribe to {n.item.parentId ? 'commented' : 'posted'}
>
)
}
function TerritoryPost ({ n }) {
return (
<>
new post in ~{n.item.sub.name}
>
)
}
function TerritoryTransfer ({ n }) {
return (
~{n.sub.name} was transferred to you
{timeSince(new Date(n.sortTime))}
)
}
function Reminder ({ n }) {
return (
<>
you asked to be reminded of this {n.item.title ? 'post' : 'comment'}
>
)
}
export function NotificationAlert () {
const [showAlert, setShowAlert] = useState(false)
const [hasSubscription, setHasSubscription] = useState(false)
const [error, setError] = useState(null)
const [supported, setSupported] = useState(false)
const sw = useServiceWorker()
useEffect(() => {
const isSupported = sw.support.serviceWorker && sw.support.pushManager && sw.support.notification
if (isSupported) {
const isDefaultPermission = sw.permission.notification === 'default'
setShowAlert(isDefaultPermission && !window.localStorage.getItem('hideNotifyPrompt'))
sw.registration?.pushManager.getSubscription().then(subscription => setHasSubscription(!!subscription))
setSupported(true)
}
}, [sw])
const close = () => {
window.localStorage.setItem('hideNotifyPrompt', 'yep')
setShowAlert(false)
}
return (
error
? (
setError(null)}>
{error.toString()}
)
: showAlert
? (
Enable push notifications?
)
: (
)
)
}
const nid = n => n.__typename + n.id + n.sortTime
export default function Notifications ({ ssrData }) {
const { data, fetchMore } = useQuery(NOTIFICATIONS)
const router = useRouter()
const dat = useData(data, ssrData)
const { notifications, lastChecked, cursor } = useMemo(() => {
if (!dat?.notifications) return {}
// make sure we're using the oldest lastChecked we've seen
const retDat = { ...dat.notifications }
if (ssrData?.notifications?.lastChecked < retDat.lastChecked) {
retDat.lastChecked = ssrData.notifications.lastChecked
}
return retDat
}, [dat])
useEffect(() => {
if (lastChecked && !router?.query?.checkedAt) {
router.replace({
pathname: router.pathname,
query: {
...router.query,
nodata: true, // make sure nodata is set so we don't fetch on back/forward
checkedAt: lastChecked
}
}, router.asPath, { ...router.options, shallow: true })
}
}, [router?.query?.checkedAt, lastChecked])
if (!dat) return
return (
<>
{notifications.map(n =>
new Date(router?.query?.checkedAt ?? lastChecked)}
/>)}
>
)
}
function CommentsFlatSkeleton () {
const comments = new Array(21).fill(null)
return (