2021-09-06 22:36:08 +00:00
import { useQuery } from '@apollo/client'
2021-08-17 18:15:24 +00:00
import Comment , { CommentSkeleton } from './comment'
2022-07-21 22:55:05 +00:00
import Item from './item'
import ItemJob from './item-job'
2021-08-17 18:15:24 +00:00
import { NOTIFICATIONS } from '../fragments/notifications'
2021-08-17 23:59:22 +00:00
import { useRouter } from 'next/router'
2021-09-30 15:46:58 +00:00
import MoreFooter from './more-footer'
2022-01-19 21:02:38 +00:00
import Invite from './invite'
2022-01-20 19:03:48 +00:00
import { ignoreClick } from '../lib/clicks'
2022-03-31 16:49:35 +00:00
import { timeSince } from '../lib/time'
2022-03-17 20:13:19 +00:00
import Link from 'next/link'
2022-03-23 18:54:39 +00:00
import Check from '../svgs/check-double-line.svg'
2022-03-23 21:45:36 +00:00
import HandCoin from '../svgs/hand-coin-fill.svg'
2022-05-17 22:09:15 +00:00
import { COMMENT _DEPTH _LIMIT } from '../lib/constants'
2023-02-01 14:44:35 +00:00
import CowboyHatIcon from '../svgs/cowboy.svg'
import BaldIcon from '../svgs/bald.svg'
2023-05-06 21:51:17 +00:00
import { RootProvider } from './root'
2021-08-17 18:15:24 +00:00
2022-03-23 18:54:39 +00:00
// TODO: oh man, this is a mess ... each notification type should just be a component ...
2021-09-06 22:36:08 +00:00
function Notification ( { n } ) {
2021-08-17 23:59:22 +00:00
const router = useRouter ( )
2021-08-20 00:13:32 +00:00
return (
< div
2021-11-04 18:22:03 +00:00
className = 'clickToContext'
2022-01-20 19:03:48 +00:00
onClick = { e => {
2023-02-01 14:44:35 +00:00
if ( n . _ _typename === 'Earn' || n . _ _typename === 'Referral' || n . _ _typename === 'Streak' ) {
2022-03-17 20:13:19 +00:00
return
}
2022-01-20 19:03:48 +00:00
if ( ignoreClick ( e ) ) {
return
}
2022-03-23 18:54:39 +00:00
if ( n . _ _typename === 'InvoicePaid' ) {
router . push ( ` /invoices/ ${ n . invoice . id } ` )
} else if ( n . _ _typename === 'Invitification' ) {
2022-01-19 21:02:38 +00:00
router . push ( '/invites' )
} else if ( ! n . item . title ) {
2022-05-17 22:09:15 +00:00
if ( n . item . path . split ( '.' ) . length > COMMENT _DEPTH _LIMIT + 1 ) {
router . push ( {
pathname : '/items/[id]' ,
query : { id : n . item . parentId , commentId : n . item . id }
} , ` /items/ ${ n . item . parentId } ` )
} else {
router . push ( {
pathname : '/items/[id]' ,
query : { id : n . item . root . id , commentId : n . item . id }
} , ` /items/ ${ n . item . root . id } ` )
}
2021-08-20 00:13:32 +00:00
} else {
2021-09-06 22:36:08 +00:00
router . push ( {
pathname : '/items/[id]' ,
query : { id : n . item . id }
} , ` /items/ ${ n . item . id } ` )
2021-08-20 00:13:32 +00:00
}
} }
>
2022-01-19 21:02:38 +00:00
{ n . _ _typename === 'Invitification'
? (
< >
< small className = 'font-weight-bold text-secondary ml-2' >
your invite has been redeemed by { n . invite . invitees . length } users
< / s m a l l >
< div className = 'ml-4 mr-2 mt-1' >
< Invite
invite = { n . invite } active = {
! n . invite . revoked &&
! ( n . invite . limit && n . invite . invitees . length >= n . invite . limit )
}
/ >
< / d i v >
< / >
)
2022-03-17 20:13:19 +00:00
: n . _ _typename === 'Earn'
? (
2022-03-23 21:45:36 +00:00
< div className = 'd-flex' >
< HandCoin className = 'align-self-center fill-boost mx-1' width = { 24 } height = { 24 } style = { { flex : '0 0 24px' , transform : 'rotateY(180deg)' } } / >
< div className = 'ml-2' >
< div className = 'font-weight-bold text-boost' >
2022-09-12 18:55:34 +00:00
you stacked { n . earnedSats } sats in rewards < small className = 'text-muted ml-1' > { timeSince ( new Date ( n . sortTime ) ) } < / s m a l l >
2022-03-23 21:45:36 +00:00
< / d i v >
2022-09-12 18:55:34 +00:00
{ n . sources &&
< div style = { { fontSize : '80%' , color : 'var(--theme-grey)' } } >
{ n . sources . posts > 0 && < span > { n . sources . posts } sats for top posts < / s p a n > }
{ n . sources . comments > 0 && < span > { n . sources . posts > 0 && ' \\ ' } { n . sources . comments } sats for top comments < / s p a n > }
{ n . sources . tips > 0 && < span > { ( n . sources . comments > 0 || n . sources . posts > 0 ) && ' \\ ' } { n . sources . tips } sats for tipping top content early < / s p a n > }
< / d i v > }
2022-03-23 21:45:36 +00:00
< div className = 'pb-1' style = { { lineHeight : '140%' } } >
2023-01-12 23:53:09 +00:00
SN distributes the sats it earns back to its best users daily . These sats come from < Link href = '/~jobs' passHref > < a > jobs < / a > < / L i n k > , b o o s t s , p o s t i n g f e e s , a n d d o n a t i o n s . Y o u c a n s e e t h e d a i l y r e w a r d s p o o l a n d m a k e a d o n a t i o n < L i n k h r e f = ' / r e w a r d s ' p a s s H r e f > < a > h e r e < / a > < / L i n k > .
2022-03-23 21:45:36 +00:00
< / d i v >
2022-03-17 20:13:19 +00:00
< / d i v >
2022-03-23 21:45:36 +00:00
< / d i v >
2022-03-17 20:13:19 +00:00
)
2022-12-19 22:27:52 +00:00
: n . _ _typename === 'Referral'
2022-04-19 18:35:21 +00:00
? (
2022-03-23 18:54:39 +00:00
< >
2022-12-19 22:27:52 +00:00
< small className = 'font-weight-bold text-secondary ml-2' >
someone joined via one of your < Link href = '/referrals/month' passHref > < a className = 'text-reset' > referral links < / a > < / L i n k >
< small className = 'text-muted ml-1' > { timeSince ( new Date ( n . sortTime ) ) } < / s m a l l >
< / s m a l l >
< / >
)
: n . _ _typename === 'InvoicePaid'
? (
< div className = 'font-weight-bold text-info ml-2 py-1' >
< Check className = 'fill-info mr-1' / > { n . earnedSats } sats were deposited in your account
< small className = 'text-muted ml-1' > { timeSince ( new Date ( n . sortTime ) ) } < / s m a l l >
< / d i v > )
2023-02-01 14:44:35 +00:00
: n . _ _typename === 'Streak'
? < Streak n = { n } / >
: (
< >
{ n . _ _typename === 'Votification' &&
< small className = 'font-weight-bold text-success ml-2' >
your { n . item . title ? 'post' : 'reply' } { n . item . fwdUser ? 'forwarded' : 'stacked' } { n . earnedSats } sats { n . item . fwdUser && ` to @ ${ n . item . fwdUser . name } ` }
< / s m a l l > }
{ n . _ _typename === 'Mention' &&
< small className = 'font-weight-bold text-info ml-2' >
you were mentioned in
< / s m a l l > }
{ n . _ _typename === 'JobChanged' &&
< small className = { ` font-weight-bold text- ${ n . item . status === 'ACTIVE' ? 'success' : 'boost' } ml-1 ` } >
{ 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' ) }
< / s m a l l > }
< div className = { n . _ _typename === 'Votification' || n . _ _typename === 'Mention' || n . _ _typename === 'JobChanged' ? '' : 'py-2' } >
{ n . item . isJob
? < ItemJob item = { n . item } / >
: n . item . title
? < Item item = { n . item } / >
: (
< div className = 'pb-2' >
2023-05-06 21:51:17 +00:00
< RootProvider root = { n . item . root } >
< Comment item = { n . item } noReply includeParent rootText = { n . _ _typename === 'Reply' ? 'replying on:' : undefined } clickToContext / >
< / R o o t P r o v i d e r >
2023-02-01 14:44:35 +00:00
< / d i v > ) }
< / d i v >
< / > ) }
< / d i v >
)
}
function Streak ( { n } ) {
function blurb ( n ) {
const index = Number ( n . id ) % 6
const FOUND _BLURBS = [
'The harsh frontier is no place for the unprepared. This hat will protect you from the sun, dust, and other elements Mother Nature throws your way.' ,
'A cowboy is nothing without a cowboy hat. Take good care of it, and it will protect you from the sun, dust, and other elements on your journey.' ,
"This is not just a hat, it's a matter of survival. Take care of this essential tool, and it will shield you from the scorching sun and the elements." ,
"A cowboy hat isn't just a fashion statement. It's your last defense against the unforgiving elements of the Wild West. Hang onto it tight." ,
"A good cowboy hat is worth its weight in gold, shielding you from the sun, wind, and dust of the western frontier. Don't lose it." ,
'Your cowboy hat is the key to your survival in the wild west. Treat it with respect and it will protect you from the elements.'
]
const LOST _BLURBS = [
'your cowboy hat was taken by the wind storm that blew in from the west. No worries, a true cowboy always finds another hat.' ,
"you left your trusty cowboy hat in the saloon before leaving town. You'll need a replacement for the long journey west." ,
'you lost your cowboy hat in a wild shoot-out on the outskirts of town. Tough luck, tIme to start searching for another one.' ,
'you ran out of food and had to trade your hat for supplies. Better start looking for another hat.' ,
"your hat was stolen by a mischievous prairie dog. You won't catch the dog, but you can always find another hat." ,
'you lost your hat while crossing the river on your journey west. Maybe you can find a replacement hat in the next town.'
]
if ( n . days ) {
return ` After ${ n . days } days, ` + LOST _BLURBS [ index ]
}
return FOUND _BLURBS [ index ]
}
return (
< div className = 'd-flex font-weight-bold ml-2 py-1' >
< div style = { { fontSize : '2rem' } } > { n . days ? < BaldIcon className = 'fill-grey' height = { 40 } width = { 40 } / > : < CowboyHatIcon className = 'fill-grey' height = { 40 } width = { 40 } / > } < / d i v >
< div className = 'ml-1 p-1' >
you { n . days ? 'lost your' : 'found a' } cowboy hat
< div > < small style = { { lineHeight : '140%' , display : 'inline-block' } } > { blurb ( n ) } < / s m a l l > < / d i v >
< / d i v >
2021-08-20 00:13:32 +00:00
< / d i v >
)
}
2022-04-24 16:13:07 +00:00
export default function Notifications ( { notifications , earn , cursor , lastChecked , variables } ) {
2021-10-26 20:49:37 +00:00
const { data , fetchMore } = useQuery ( NOTIFICATIONS , { variables } )
2021-08-20 00:13:32 +00:00
2021-09-30 15:46:58 +00:00
if ( data ) {
2022-04-24 16:13:07 +00:00
( { notifications : { notifications , earn , cursor } } = data )
2021-09-30 15:46:58 +00:00
}
2021-08-20 00:13:32 +00:00
const [ fresh , old ] =
notifications . reduce ( ( result , n ) => {
result [ new Date ( n . sortTime ) . getTime ( ) > lastChecked ? 0 : 1 ] . push ( n )
return result
} ,
[ [ ] , [ ] ] )
2021-08-17 23:59:22 +00:00
2021-08-17 18:15:24 +00:00
return (
< >
2021-08-17 23:07:52 +00:00
{ /* XXX we shouldn't use the index but we don't have a unique id in this union yet */ }
2021-11-04 18:22:03 +00:00
< div className = 'fresh' >
2022-04-24 16:13:07 +00:00
{ earn && < Notification n = { earn } key = 'earn' / > }
2021-08-20 00:13:32 +00:00
{ fresh . map ( ( n , i ) => (
< Notification n = { n } key = { i } / >
) ) }
< / d i v >
{ old . map ( ( n , i ) => (
< Notification n = { n } key = { i } / >
2021-08-17 18:15:24 +00:00
) ) }
2021-09-30 15:46:58 +00:00
< MoreFooter cursor = { cursor } fetchMore = { fetchMore } Skeleton = { CommentsFlatSkeleton } / >
2021-08-17 18:15:24 +00:00
< / >
)
}
function CommentsFlatSkeleton ( ) {
const comments = new Array ( 21 ) . fill ( null )
return (
< div > { comments . map ( ( _ , i ) => (
< CommentSkeleton key = { i } skeletonChildren = { 0 } / >
) ) }
< / d i v >
)
}