2022-07-21 22:55:05 +00:00
import Item from './item'
import ItemJob from './item-job'
2021-09-24 21:28:21 +00:00
import Reply from './reply'
2021-09-23 17:42:00 +00:00
import Comment from './comment'
2023-10-03 00:07:05 +00:00
import Text , { SearchText } from './text'
import ZoomableImage from './image'
2021-09-24 21:28:21 +00:00
import Comments from './comments'
2021-09-23 17:42:00 +00:00
import styles from '../styles/item.module.css'
2023-07-23 15:08:43 +00:00
import itemStyles from './item.module.css'
2021-09-23 17:42:00 +00:00
import { NOFOLLOW _LIMIT } from '../lib/constants'
2021-09-23 22:18:48 +00:00
import { useMe } from './me'
2023-07-24 18:35:05 +00:00
import Button from 'react-bootstrap/Button'
2022-02-12 14:06:41 +00:00
import { TwitterTweetEmbed } from 'react-twitter-embed'
2022-02-05 21:40:54 +00:00
import YouTube from 'react-youtube'
2023-07-23 15:08:43 +00:00
import useDarkMode from './dark-mode'
2023-11-21 03:37:57 +00:00
import { useEffect , useState } from 'react'
2022-07-30 13:25:46 +00:00
import Poll from './poll'
2022-09-02 16:53:44 +00:00
import { commentsViewed } from '../lib/new-comments'
2022-10-26 22:46:01 +00:00
import Related from './related'
2023-01-26 16:11:55 +00:00
import PastBounties from './past-bounties'
import Check from '../svgs/check-double-line.svg'
2023-02-16 22:23:59 +00:00
import Share from './share'
import Toc from './table-of-contents'
import Link from 'next/link'
2023-05-06 21:51:17 +00:00
import { RootProvider } from './root'
2023-07-13 00:10:01 +00:00
import { IMGPROXY _URL _REGEXP } from '../lib/url'
2023-08-08 21:04:06 +00:00
import { numWithUnits } from '../lib/format'
2023-11-21 03:37:57 +00:00
import { useQuoteReply } from './use-quote-reply'
2021-09-23 17:42:00 +00:00
2021-09-24 21:28:21 +00:00
function BioItem ( { item , handleClick } ) {
2021-09-23 22:18:48 +00:00
const me = useMe ( )
2021-09-23 20:09:07 +00:00
if ( ! item . text ) {
return null
}
return (
< >
< ItemText item = { item } / >
2021-09-23 22:18:48 +00:00
{ me ? . name === item . user . name &&
2023-07-25 20:32:49 +00:00
< div className = 'd-flex' >
2021-11-12 22:39:52 +00:00
< Button
2023-07-25 20:32:49 +00:00
className = 'ms-auto'
2021-11-12 22:39:52 +00:00
onClick = { handleClick }
size = 'md' variant = 'link'
> edit bio
< / B u t t o n >
< / d i v > }
2022-09-01 21:53:39 +00:00
< Reply item = { item } / >
2021-09-23 20:09:07 +00:00
< / >
)
}
2022-02-12 14:06:41 +00:00
function TweetSkeleton ( ) {
return (
< div className = { styles . tweetsSkeleton } >
< div className = { styles . tweetSkeleton } >
< div className = { ` ${ styles . img } clouds ` } / >
< div className = { styles . content1 } >
< div className = { ` ${ styles . line } clouds ` } / >
< div className = { ` ${ styles . line } clouds ` } / >
< div className = { ` ${ styles . line } clouds ` } / >
< / d i v >
< / d i v >
< / d i v >
)
}
2022-01-20 20:22:10 +00:00
function ItemEmbed ( { item } ) {
2023-07-23 15:08:43 +00:00
const [ darkMode ] = useDarkMode ( )
2022-02-12 14:06:41 +00:00
const [ overflowing , setOverflowing ] = useState ( false )
const [ show , setShow ] = useState ( false )
2023-08-31 01:13:43 +00:00
const twitter = item . url ? . match ( /^https?:\/\/(?:twitter|x)\.com\/(?:#!\/)?\w+\/status(?:es)?\/(?<id>\d+)/ )
2022-01-20 20:22:10 +00:00
if ( twitter ? . groups ? . id ) {
2022-02-09 19:15:38 +00:00
return (
2022-03-10 16:09:05 +00:00
< div className = { ` ${ styles . twitterContainer } ${ show ? '' : styles . twitterContained } ` } >
2023-11-21 21:39:53 +00:00
< TwitterTweetEmbed tweetId = { twitter . groups . id } options = { { theme : darkMode ? 'dark' : 'light' , width : '550px' } } key = { darkMode ? '1' : '2' } placeholder = { < TweetSkeleton / > } onLoad = { ( ) => setOverflowing ( true ) } / >
2022-02-12 14:06:41 +00:00
{ overflowing && ! show &&
< Button size = 'lg' variant = 'info' className = { styles . twitterShowFull } onClick = { ( ) => setShow ( true ) } >
show full tweet
< / B u t t o n > }
2022-02-09 19:15:38 +00:00
< / d i v >
)
2022-01-20 20:22:10 +00:00
}
2023-01-14 00:09:05 +00:00
const youtube = item . url ? . match ( /(https?:\/\/)?((www\.)?(youtube(-nocookie)?|youtube.googleapis)\.com.*(v\/|v=|vi=|vi\/|e\/|embed\/|user\/.*\/u\/\d+\/)|youtu\.be\/)(?<id>[_0-9a-z-]+)((?:\?|&)(?:t|start)=(?<start>\d+))?/i )
2022-02-05 21:40:54 +00:00
if ( youtube ? . groups ? . id ) {
return (
2023-11-21 22:20:54 +00:00
< div className = { styles . youtubeContainerContainer } >
2023-01-14 00:09:05 +00:00
< YouTube
2023-08-23 20:29:09 +00:00
videoId = { youtube . groups . id } className = { styles . youtubeContainer } opts = { {
2023-01-14 00:09:05 +00:00
playerVars : {
start : youtube ? . groups ? . start
}
} }
/ >
2022-02-05 21:40:54 +00:00
< / d i v >
)
}
2023-07-13 00:10:01 +00:00
if ( item . url ? . match ( IMGPROXY _URL _REGEXP ) ) {
return < ZoomableImage src = { item . url } / >
}
2022-01-20 20:22:10 +00:00
return null
}
multiple forwards on a post (#403)
* multiple forwards on a post
first phase of the multi-forward support
* update the graphql mutation for discussion posts to accept and validate multiple forwards
* update the discussion form to allow multiple forwards in the UI
* start working on db schema changes
* uncomment db schema, add migration to create the new model, and update create_item, update_item
stored procedures
* Propagate updates from discussion to poll, link, and bounty forms
Update the create, update poll sql functions for multi forward support
* Update gql, typedefs, and resolver to return forwarded users in items responses
* UI changes to show multiple forward recipients, and conditional upvote logic changes
* Update notification text to reflect multiple forwards upon vote action
* Disallow duplicate stacker entries
* reduce duplication in populating adv-post-form initial values
* Update item_act sql function to implement multi-way forwarding
* Update referral functions to scale referral bonuses for forwarded users
* Update notification text to reflect non-100% forwarded sats cases
* Update wallet history sql queries to accommodate multi-forward use cases
* Block zaps for posts you are forwarded zaps at the API layer, in addition
to in the UI
* Delete fwdUserId column from Item table as part of migration
* Fix how we calculate stacked sats after partial forwards in wallet history
* Exclude entries from wallet history that are 0 stacked sats from posts with 100% forwarded to other users
* Fix wallet history query for forwarded stacked sats to be scaled by the fwd pct
* Reduce duplication in adv post form, and do some style tweaks for better layout
* Use MAX_FORWARDS constants
* Address various PR feedback
* first enhancement pass
* enhancement pass too
---------
Co-authored-by: keyan <keyan.kousha+huumn@gmail.com>
Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
2023-08-23 22:44:17 +00:00
function FwdUsers ( { forwards } ) {
2023-02-16 22:23:59 +00:00
return (
< div className = { styles . other } >
multiple forwards on a post (#403)
* multiple forwards on a post
first phase of the multi-forward support
* update the graphql mutation for discussion posts to accept and validate multiple forwards
* update the discussion form to allow multiple forwards in the UI
* start working on db schema changes
* uncomment db schema, add migration to create the new model, and update create_item, update_item
stored procedures
* Propagate updates from discussion to poll, link, and bounty forms
Update the create, update poll sql functions for multi forward support
* Update gql, typedefs, and resolver to return forwarded users in items responses
* UI changes to show multiple forward recipients, and conditional upvote logic changes
* Update notification text to reflect multiple forwards upon vote action
* Disallow duplicate stacker entries
* reduce duplication in populating adv-post-form initial values
* Update item_act sql function to implement multi-way forwarding
* Update referral functions to scale referral bonuses for forwarded users
* Update notification text to reflect non-100% forwarded sats cases
* Update wallet history sql queries to accommodate multi-forward use cases
* Block zaps for posts you are forwarded zaps at the API layer, in addition
to in the UI
* Delete fwdUserId column from Item table as part of migration
* Fix how we calculate stacked sats after partial forwards in wallet history
* Exclude entries from wallet history that are 0 stacked sats from posts with 100% forwarded to other users
* Fix wallet history query for forwarded stacked sats to be scaled by the fwd pct
* Reduce duplication in adv post form, and do some style tweaks for better layout
* Use MAX_FORWARDS constants
* Address various PR feedback
* first enhancement pass
* enhancement pass too
---------
Co-authored-by: keyan <keyan.kousha+huumn@gmail.com>
Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
2023-08-23 22:44:17 +00:00
zaps forwarded to { ' ' }
{ forwards . map ( ( fwd , index , arr ) => (
< span key = { fwd . user . name } >
< Link href = { ` / ${ fwd . user . name } ` } >
@ { fwd . user . name }
< / L i n k >
2023-08-28 14:59:01 +00:00
{ ` ( ${ fwd . pct } %) ` } { index !== arr . length - 1 && ' ' }
multiple forwards on a post (#403)
* multiple forwards on a post
first phase of the multi-forward support
* update the graphql mutation for discussion posts to accept and validate multiple forwards
* update the discussion form to allow multiple forwards in the UI
* start working on db schema changes
* uncomment db schema, add migration to create the new model, and update create_item, update_item
stored procedures
* Propagate updates from discussion to poll, link, and bounty forms
Update the create, update poll sql functions for multi forward support
* Update gql, typedefs, and resolver to return forwarded users in items responses
* UI changes to show multiple forward recipients, and conditional upvote logic changes
* Update notification text to reflect multiple forwards upon vote action
* Disallow duplicate stacker entries
* reduce duplication in populating adv-post-form initial values
* Update item_act sql function to implement multi-way forwarding
* Update referral functions to scale referral bonuses for forwarded users
* Update notification text to reflect non-100% forwarded sats cases
* Update wallet history sql queries to accommodate multi-forward use cases
* Block zaps for posts you are forwarded zaps at the API layer, in addition
to in the UI
* Delete fwdUserId column from Item table as part of migration
* Fix how we calculate stacked sats after partial forwards in wallet history
* Exclude entries from wallet history that are 0 stacked sats from posts with 100% forwarded to other users
* Fix wallet history query for forwarded stacked sats to be scaled by the fwd pct
* Reduce duplication in adv post form, and do some style tweaks for better layout
* Use MAX_FORWARDS constants
* Address various PR feedback
* first enhancement pass
* enhancement pass too
---------
Co-authored-by: keyan <keyan.kousha+huumn@gmail.com>
Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
2023-08-23 22:44:17 +00:00
< / s p a n > ) ) }
2023-02-16 22:23:59 +00:00
< / d i v >
)
}
2022-02-03 22:01:42 +00:00
function TopLevelItem ( { item , noReply , ... props } ) {
2022-09-29 20:42:33 +00:00
const ItemComponent = item . isJob ? ItemJob : Item
2023-11-21 03:37:57 +00:00
const { ref : textRef , quote , quoteReply , cancelQuote } = useQuoteReply ( { text : item . text } )
2022-02-17 17:23:43 +00:00
2021-09-23 20:09:07 +00:00
return (
2023-02-16 22:23:59 +00:00
< ItemComponent
item = { item }
2023-05-11 19:34:42 +00:00
full
2023-11-21 03:37:57 +00:00
onQuoteReply = { quoteReply }
2023-02-16 22:23:59 +00:00
right = {
2023-07-23 15:08:43 +00:00
! noReply &&
< >
< Share item = { item } / >
< Toc text = { item . text } / >
< / >
2023-02-16 22:23:59 +00:00
}
multiple forwards on a post (#403)
* multiple forwards on a post
first phase of the multi-forward support
* update the graphql mutation for discussion posts to accept and validate multiple forwards
* update the discussion form to allow multiple forwards in the UI
* start working on db schema changes
* uncomment db schema, add migration to create the new model, and update create_item, update_item
stored procedures
* Propagate updates from discussion to poll, link, and bounty forms
Update the create, update poll sql functions for multi forward support
* Update gql, typedefs, and resolver to return forwarded users in items responses
* UI changes to show multiple forward recipients, and conditional upvote logic changes
* Update notification text to reflect multiple forwards upon vote action
* Disallow duplicate stacker entries
* reduce duplication in populating adv-post-form initial values
* Update item_act sql function to implement multi-way forwarding
* Update referral functions to scale referral bonuses for forwarded users
* Update notification text to reflect non-100% forwarded sats cases
* Update wallet history sql queries to accommodate multi-forward use cases
* Block zaps for posts you are forwarded zaps at the API layer, in addition
to in the UI
* Delete fwdUserId column from Item table as part of migration
* Fix how we calculate stacked sats after partial forwards in wallet history
* Exclude entries from wallet history that are 0 stacked sats from posts with 100% forwarded to other users
* Fix wallet history query for forwarded stacked sats to be scaled by the fwd pct
* Reduce duplication in adv post form, and do some style tweaks for better layout
* Use MAX_FORWARDS constants
* Address various PR feedback
* first enhancement pass
* enhancement pass too
---------
Co-authored-by: keyan <keyan.kousha+huumn@gmail.com>
Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
2023-08-23 22:44:17 +00:00
belowTitle = { item . forwards && item . forwards . length > 0 && < FwdUsers forwards = { item . forwards } / > }
2023-02-16 22:23:59 +00:00
{ ... props }
>
2023-11-21 03:37:57 +00:00
< div className = { styles . fullItemContainer } ref = { textRef } >
2023-01-27 21:01:32 +00:00
{ item . text && < ItemText item = { item } / > }
{ item . url && < ItemEmbed item = { item } / > }
{ item . poll && < Poll item = { item } / > }
{ item . bounty &&
2023-07-24 18:35:05 +00:00
< div className = 'fw-bold mt-2' >
2023-01-27 21:01:32 +00:00
{ item . bountyPaidTo ? . length
? (
< div className = 'px-3 py-1 d-inline-block bg-grey-medium rounded text-success' >
2023-09-18 23:09:08 +00:00
< Check className = 'fill-success' / > { numWithUnits ( item . bounty , { abbreviate : false , format : true } ) } paid
2023-09-19 00:15:02 +00:00
{ item . bountyPaidTo . length > 1 && < small className = 'fw-light' > { new Set ( item . bountyPaidTo ) . size } times < / s m a l l > }
2023-01-27 21:01:32 +00:00
< / d i v > )
: (
< div className = 'px-3 py-1 d-inline-block bg-grey-darkmode rounded text-light' >
2023-09-18 22:49:13 +00:00
{ numWithUnits ( item . bounty , { abbreviate : false , format : true } ) } bounty
2023-01-27 21:01:32 +00:00
< / d i v > ) }
< / d i v > }
< / d i v >
2022-10-26 22:46:01 +00:00
{ ! noReply &&
< >
2023-11-21 03:37:57 +00:00
< Reply item = { item } replyOpen placeholder = { item . ncomments ? undefined : 'start the conversation ...' } onCancelQuote = { cancelQuote } onQuoteReply = { quoteReply } quote = { quote } / >
2023-01-26 16:11:55 +00:00
{ ! item . position && ! item . isJob && ! item . parentId && ! item . bounty > 0 && < Related title = { item . title } itemId = { item . id } / > }
{ item . bounty > 0 && < PastBounties item = { item } / > }
2022-10-26 22:46:01 +00:00
< / > }
2022-02-17 17:23:43 +00:00
< / I t e m C o m p o n e n t >
2021-09-23 20:09:07 +00:00
)
}
function ItemText ( { item } ) {
2023-10-03 00:07:05 +00:00
return item . searchText
? < SearchText text = { item . searchText } / >
: < Text topLevel nofollow = { item . sats + item . boost < NOFOLLOW _LIMIT } imgproxyUrls = { item . imgproxyUrls } > { item . text } < / T e x t >
2021-09-23 20:09:07 +00:00
}
2023-07-23 15:08:43 +00:00
export default function ItemFull ( { item , bio , rank , ... props } ) {
2022-09-02 16:53:44 +00:00
useEffect ( ( ) => {
commentsViewed ( item )
} , [ item . lastCommentAt ] )
2021-09-23 17:42:00 +00:00
return (
2023-07-23 15:08:43 +00:00
< >
{ rank
? (
< div className = { ` ${ itemStyles . rank } pt-2 align-self-start ` } >
{ rank }
< / d i v > )
: < div / > }
< RootProvider root = { item . root || item } >
{ item . parentId
? < Comment topLevel item = { item } replyOpen includeParent noComments { ... props } / >
: (
2023-07-26 00:45:35 +00:00
< div > { bio
? < BioItem item = { item } { ... props } / >
: < TopLevelItem item = { item } { ... props } / > }
2023-07-23 15:08:43 +00:00
< / d i v > ) }
{ item . comments &&
< div className = { styles . comments } >
< Comments
parentId = { item . id } parentCreatedAt = { item . createdAt }
pinned = { item . position } bio = { bio } commentSats = { item . commentSats } comments = { item . comments }
/ >
< / d i v > }
< / R o o t P r o v i d e r >
< / >
2021-09-23 17:42:00 +00:00
)
}