2023-02-06 10:01:03 -08:00
import clsx from 'clsx' ;
2022-04-10 01:20:12 -07:00
import { List as ImmutableList } from 'immutable' ;
2023-03-18 03:55:00 -07:00
import React , { useEffect , useMemo , useState } from 'react' ;
2022-04-10 01:20:12 -07:00
import { FormattedMessage , defineMessages , useIntl } from 'react-intl' ;
import { fetchFavourites , fetchReactions } from 'soapbox/actions/interactions' ;
2022-11-15 08:00:49 -08:00
import ScrollableList from 'soapbox/components/scrollable-list' ;
2022-06-09 12:47:21 -07:00
import { Emoji , Modal , Spinner , Tabs } from 'soapbox/components/ui' ;
2022-11-15 08:13:54 -08:00
import AccountContainer from 'soapbox/containers/account-container' ;
2022-05-28 09:02:04 -07:00
import { useAppDispatch , useAppSelector } from 'soapbox/hooks' ;
2022-11-15 12:39:43 -08:00
import { ReactionRecord } from 'soapbox/reducers/user-lists' ;
2022-04-10 01:20:12 -07:00
2022-06-09 12:47:21 -07:00
import type { Item } from 'soapbox/components/ui/tabs/tabs' ;
2022-04-10 01:20:12 -07:00
const messages = defineMessages ( {
close : { id : 'lightbox.close' , defaultMessage : 'Close' } ,
all : { id : 'reactions.all' , defaultMessage : 'All' } ,
} ) ;
2023-03-18 03:55:00 -07:00
interface IAccountWithReaction {
id : string
reaction : string
reactionUrl? : string
}
2022-04-10 01:20:12 -07:00
interface IReactionsModal {
2023-02-15 13:26:27 -08:00
onClose : ( string : string ) = > void
statusId : string
reaction? : string
2022-04-10 01:20:12 -07:00
}
2022-05-28 09:02:04 -07:00
const ReactionsModal : React.FC < IReactionsModal > = ( { onClose , statusId , reaction : initialReaction } ) = > {
const dispatch = useAppDispatch ( ) ;
2022-04-10 01:20:12 -07:00
const intl = useIntl ( ) ;
2022-05-28 09:02:04 -07:00
const [ reaction , setReaction ] = useState ( initialReaction ) ;
2022-06-21 15:29:17 -07:00
const reactions = useAppSelector < ImmutableList < ReturnType < typeof ReactionRecord > > | undefined > ( ( state ) = > {
const favourites = state . user_lists . favourited_by . get ( statusId ) ? . items ;
const reactions = state . user_lists . reactions . get ( statusId ) ? . items ;
return favourites && reactions && ImmutableList ( favourites ? . size ? [ ReactionRecord ( { accounts : favourites , count : favourites.size , name : '👍' } ) ] : [ ] ) . concat ( reactions || [ ] ) ;
2022-04-10 01:20:12 -07:00
} ) ;
const fetchData = ( ) = > {
dispatch ( fetchFavourites ( statusId ) ) ;
dispatch ( fetchReactions ( statusId ) ) ;
} ;
const onClickClose = ( ) = > {
onClose ( 'REACTIONS' ) ;
} ;
const renderFilterBar = ( ) = > {
2022-06-09 12:47:21 -07:00
const items : Array < Item > = [
2022-04-10 01:20:12 -07:00
{
text : intl.formatMessage ( messages . all ) ,
action : ( ) = > setReaction ( '' ) ,
name : 'all' ,
} ,
] ;
2022-06-21 15:29:17 -07:00
reactions ! . forEach ( reaction = > items . push (
2022-04-10 01:20:12 -07:00
{
2022-06-09 12:47:21 -07:00
text : < div className = 'flex items-center gap-1' >
2023-03-17 16:07:18 -07:00
< Emoji className = 'h-4 w-4' emoji = { reaction . name } src = { reaction . url || undefined } / >
2022-06-09 12:47:21 -07:00
{ reaction . count }
< / div > ,
2022-04-10 01:20:12 -07:00
action : ( ) = > setReaction ( reaction . name ) ,
name : reaction.name ,
} ,
) ) ;
2022-06-09 12:47:21 -07:00
return < Tabs items = { items } activeItem = { reaction || 'all' } / > ;
2022-04-10 01:20:12 -07:00
} ;
2023-03-18 03:55:00 -07:00
const accounts = useMemo ( ( ) : ImmutableList < IAccountWithReaction > | undefined = > {
if ( ! reactions ) return ;
if ( reaction ) {
const reactionRecord = reactions . find ( ( { name } ) = > name === reaction ) ;
if ( reactionRecord ) return reactionRecord . accounts . map ( account = > ( { id : account , reaction : reaction , reactionUrl : reactionRecord.url || undefined } ) ) . toList ( ) ;
} else {
return reactions . map ( ( { accounts , name , url } ) = > accounts . map ( account = > ( { id : account , reaction : name , reactionUrl : url } ) ) ) . flatten ( ) as ImmutableList < IAccountWithReaction > ;
}
} , [ reactions , reaction ] ) ;
2022-04-10 01:20:12 -07:00
useEffect ( ( ) = > {
fetchData ( ) ;
} , [ ] ) ;
let body ;
2023-03-18 03:55:00 -07:00
if ( ! accounts || ! reactions ) {
2022-04-10 01:20:12 -07:00
body = < Spinner / > ;
} else {
const emptyMessage = < FormattedMessage id = 'status.reactions.empty' defaultMessage = 'No one has reacted to this post yet. When someone does, they will show up here.' / > ;
body = ( < >
2022-06-09 12:47:21 -07:00
{ reactions . size > 0 && renderFilterBar ( ) }
2022-04-10 01:20:12 -07:00
< ScrollableList
scrollKey = 'reactions'
emptyMessage = { emptyMessage }
2023-02-06 10:01:03 -08:00
className = { clsx ( 'max-w-full' , {
2023-01-07 03:24:18 -08:00
'mt-4' : reactions . size > 0 ,
} ) }
2022-04-22 10:24:09 -07:00
itemClassName = 'pb-3'
2022-04-10 01:20:12 -07:00
>
{ accounts . map ( ( account ) = >
2023-03-17 16:07:18 -07:00
< AccountContainer key = { ` ${ account . id } - ${ account . reaction } ` } id = { account . id } emoji = { account . reaction } emojiUrl = { account . reactionUrl } / > ,
2022-04-10 01:20:12 -07:00
) }
< / ScrollableList >
< / > ) ;
}
return (
< Modal
title = { < FormattedMessage id = 'column.reactions' defaultMessage = 'Reactions' / > }
onClose = { onClickClose }
>
{ body }
< / Modal >
) ;
} ;
export default ReactionsModal ;