2022-07-21 17:55:05 -05:00
import Item from './item'
import ItemJob from './item-job'
2021-09-24 16:28:21 -05:00
import Reply from './reply'
2021-09-23 12:42:00 -05:00
import Comment from './comment'
2023-10-02 19:07:05 -05:00
import Text , { SearchText } from './text'
import ZoomableImage from './image'
2021-09-24 16:28:21 -05:00
import Comments from './comments'
2021-09-23 12:42:00 -05:00
import styles from '../styles/item.module.css'
2023-07-23 10:08:43 -05:00
import itemStyles from './item.module.css'
2021-09-23 12:42:00 -05:00
import { NOFOLLOW _LIMIT } from '../lib/constants'
2021-09-23 17:18:48 -05:00
import { useMe } from './me'
2023-07-24 13:35:05 -05:00
import Button from 'react-bootstrap/Button'
2022-02-12 08:06:41 -06:00
import { TwitterTweetEmbed } from 'react-twitter-embed'
2022-02-05 15:40:54 -06:00
import YouTube from 'react-youtube'
2023-07-23 10:08:43 -05:00
import useDarkMode from './dark-mode'
2023-11-20 21:37:57 -06:00
import { useEffect , useState } from 'react'
2022-07-30 08:25:46 -05:00
import Poll from './poll'
2022-09-02 11:53:44 -05:00
import { commentsViewed } from '../lib/new-comments'
2022-10-26 17:46:01 -05:00
import Related from './related'
2023-01-26 10:11:55 -06:00
import PastBounties from './past-bounties'
import Check from '../svgs/check-double-line.svg'
2023-02-16 23:23:59 +01:00
import Share from './share'
import Toc from './table-of-contents'
import Link from 'next/link'
2023-05-06 16:51:17 -05:00
import { RootProvider } from './root'
2023-07-13 02:10:01 +02:00
import { IMGPROXY _URL _REGEXP } from '../lib/url'
2023-08-08 17:04:06 -04:00
import { numWithUnits } from '../lib/format'
2023-11-20 21:37:57 -06:00
import { useQuoteReply } from './use-quote-reply'
2021-09-23 12:42:00 -05:00
2021-09-24 16:28:21 -05:00
function BioItem ( { item , handleClick } ) {
2021-09-23 17:18:48 -05:00
const me = useMe ( )
2021-09-23 15:09:07 -05:00
if ( ! item . text ) {
return null
}
return (
< >
< ItemText item = { item } / >
2021-09-23 17:18:48 -05:00
{ me ? . name === item . user . name &&
2023-07-25 15:32:49 -05:00
< div className = 'd-flex' >
2021-11-12 16:39:52 -06:00
< Button
2023-07-25 15:32:49 -05:00
className = 'ms-auto'
2021-11-12 16:39:52 -06:00
onClick = { handleClick }
size = 'md' variant = 'link'
> edit bio
< / B u t t o n >
< / d i v > }
2022-09-01 16:53:39 -05:00
< Reply item = { item } / >
2021-09-23 15:09:07 -05:00
< / >
)
}
2022-02-12 08:06:41 -06: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 14:22:10 -06:00
function ItemEmbed ( { item } ) {
2023-07-23 10:08:43 -05:00
const [ darkMode ] = useDarkMode ( )
2022-02-12 08:06:41 -06:00
const [ overflowing , setOverflowing ] = useState ( false )
const [ show , setShow ] = useState ( false )
2023-08-30 21:13:43 -04:00
const twitter = item . url ? . match ( /^https?:\/\/(?:twitter|x)\.com\/(?:#!\/)?\w+\/status(?:es)?\/(?<id>\d+)/ )
2022-01-20 14:22:10 -06:00
if ( twitter ? . groups ? . id ) {
2022-02-09 13:15:38 -06:00
return (
2022-03-10 10:09:05 -06:00
< div className = { ` ${ styles . twitterContainer } ${ show ? '' : styles . twitterContained } ` } >
2023-11-21 15:39:53 -06: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 08:06:41 -06: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 13:15:38 -06:00
< / d i v >
)
2022-01-20 14:22:10 -06:00
}
2023-01-13 18:09:05 -06: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 15:40:54 -06:00
if ( youtube ? . groups ? . id ) {
return (
2023-11-21 16:20:54 -06:00
< div className = { styles . youtubeContainerContainer } >
2023-01-13 18:09:05 -06:00
< YouTube
2023-08-23 22:29:09 +02:00
videoId = { youtube . groups . id } className = { styles . youtubeContainer } opts = { {
2023-01-13 18:09:05 -06:00
playerVars : {
start : youtube ? . groups ? . start
}
} }
/ >
2022-02-05 15:40:54 -06:00
< / d i v >
)
}
2023-07-13 02:10:01 +02:00
if ( item . url ? . match ( IMGPROXY _URL _REGEXP ) ) {
return < ZoomableImage src = { item . url } / >
}
2022-01-20 14:22:10 -06: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 18:44:17 -04:00
function FwdUsers ( { forwards } ) {
2023-02-16 23:23:59 +01: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 18:44:17 -04: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 09:59:01 -05: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 18:44:17 -04:00
< / s p a n > ) ) }
2023-02-16 23:23:59 +01:00
< / d i v >
)
}
2022-02-03 16:01:42 -06:00
function TopLevelItem ( { item , noReply , ... props } ) {
2022-09-29 15:42:33 -05:00
const ItemComponent = item . isJob ? ItemJob : Item
2023-11-20 21:37:57 -06:00
const { ref : textRef , quote , quoteReply , cancelQuote } = useQuoteReply ( { text : item . text } )
2022-02-17 11:23:43 -06:00
2021-09-23 15:09:07 -05:00
return (
2023-02-16 23:23:59 +01:00
< ItemComponent
item = { item }
2023-05-11 14:34:42 -05:00
full
2023-11-20 21:37:57 -06:00
onQuoteReply = { quoteReply }
2023-02-16 23:23:59 +01:00
right = {
2023-07-23 10:08:43 -05:00
! noReply &&
< >
2023-12-15 12:10:29 -06:00
< Share title = { item ? . title } path = { ` /items/ ${ item ? . id } ` } / >
2023-07-23 10:08:43 -05:00
< Toc text = { item . text } / >
< / >
2023-02-16 23:23:59 +01: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 18:44:17 -04:00
belowTitle = { item . forwards && item . forwards . length > 0 && < FwdUsers forwards = { item . forwards } / > }
2023-02-16 23:23:59 +01:00
{ ... props }
>
2023-11-20 21:37:57 -06:00
< div className = { styles . fullItemContainer } ref = { textRef } >
2023-01-27 15:01:32 -06:00
{ item . text && < ItemText item = { item } / > }
{ item . url && < ItemEmbed item = { item } / > }
{ item . poll && < Poll item = { item } / > }
{ item . bounty &&
2023-07-24 13:35:05 -05:00
< div className = 'fw-bold mt-2' >
2023-01-27 15:01:32 -06:00
{ item . bountyPaidTo ? . length
? (
< div className = 'px-3 py-1 d-inline-block bg-grey-medium rounded text-success' >
2023-09-18 18:09:08 -05:00
< Check className = 'fill-success' / > { numWithUnits ( item . bounty , { abbreviate : false , format : true } ) } paid
2023-09-18 19:15:02 -05:00
{ item . bountyPaidTo . length > 1 && < small className = 'fw-light' > { new Set ( item . bountyPaidTo ) . size } times < / s m a l l > }
2023-01-27 15:01:32 -06:00
< / d i v > )
: (
< div className = 'px-3 py-1 d-inline-block bg-grey-darkmode rounded text-light' >
2023-09-18 18:49:13 -04:00
{ numWithUnits ( item . bounty , { abbreviate : false , format : true } ) } bounty
2023-01-27 15:01:32 -06:00
< / d i v > ) }
< / d i v > }
< / d i v >
2022-10-26 17:46:01 -05:00
{ ! noReply &&
< >
2024-01-04 18:48:10 -06:00
< Reply item = { item } replyOpen placeholder = { item . ncomments > 3 ? 'fractions of a penny for your thoughts?' : 'early comments get more zaps' } onCancelQuote = { cancelQuote } onQuoteReply = { quoteReply } quote = { quote } / >
2024-01-20 15:17:34 -06:00
{ ! item . position && ! item . isJob && ! item . parentId && ! ( item . bounty > 0 ) && < Related title = { item . title } itemId = { item . id } show = { item . ncomments === 0 } / > }
2023-01-26 10:11:55 -06:00
{ item . bounty > 0 && < PastBounties item = { item } / > }
2022-10-26 17:46:01 -05:00
< / > }
2022-02-17 11:23:43 -06:00
< / I t e m C o m p o n e n t >
2021-09-23 15:09:07 -05:00
)
}
function ItemText ( { item } ) {
2023-10-02 19:07:05 -05:00
return item . searchText
? < SearchText text = { item . searchText } / >
2023-12-20 18:54:56 -06:00
: < Text itemId = { item . id } topLevel nofollow = { item . sats + item . boost < NOFOLLOW _LIMIT } imgproxyUrls = { item . imgproxyUrls } > { item . text } < / T e x t >
2021-09-23 15:09:07 -05:00
}
2023-07-23 10:08:43 -05:00
export default function ItemFull ( { item , bio , rank , ... props } ) {
2022-09-02 11:53:44 -05:00
useEffect ( ( ) => {
commentsViewed ( item )
} , [ item . lastCommentAt ] )
2021-09-23 12:42:00 -05:00
return (
2023-07-23 10:08:43 -05: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-25 19:45:35 -05:00
< div > { bio
? < BioItem item = { item } { ... props } / >
: < TopLevelItem item = { item } { ... props } / > }
2023-07-23 10:08:43 -05: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 12:42:00 -05:00
)
}