2019-07-08 22:54:58 +02:00
// @flow
2021-03-03 19:50:16 +01:00
import * as ICONS from 'constants/icons' ;
2021-06-16 04:27:58 +02:00
import { BLOCK _LEVEL } from 'constants/comment' ;
2019-07-08 22:54:58 +02:00
import React from 'react' ;
2021-03-03 19:50:16 +01:00
import classnames from 'classnames' ;
2021-08-20 09:18:54 +02:00
import moment from 'moment' ;
import humanizeDuration from 'humanize-duration' ;
2021-09-10 17:36:08 +02:00
import BlockList from 'component/blockList' ;
2021-06-16 04:27:58 +02:00
import ClaimPreview from 'component/claimPreview' ;
2019-07-08 22:54:58 +02:00
import Page from 'component/page' ;
2021-03-03 19:50:16 +01:00
import Spinner from 'component/spinner' ;
import Button from 'component/button' ;
import usePersistedState from 'effects/use-persisted-state' ;
import ChannelBlockButton from 'component/channelBlockButton' ;
import ChannelMuteButton from 'component/channelMuteButton' ;
2019-07-08 22:54:58 +02:00
2021-06-16 04:27:58 +02:00
const VIEW = {
BLOCKED : 'blocked' ,
ADMIN : 'admin' ,
MODERATOR : 'moderator' ,
MUTED : 'muted' ,
} ;
2019-07-08 22:54:58 +02:00
type Props = {
2021-03-03 19:50:16 +01:00
mutedUris : ? Array < string > ,
2021-06-16 04:27:58 +02:00
personalBlockList : ? Array < string > ,
adminBlockList : ? Array < string > ,
moderatorBlockList : ? Array < string > ,
2021-08-20 09:18:54 +02:00
personalTimeoutMap : { [ uri : string ] : { blockedAt : string , bannedFor : number , banRemaining : number } } ,
adminTimeoutMap : { [ uri : string ] : { blockedAt : string , bannedFor : number , banRemaining : number } } ,
moderatorTimeoutMap : { [ uri : string ] : { blockedAt : string , bannedFor : number , banRemaining : number } } ,
2021-06-16 04:27:58 +02:00
moderatorBlockListDelegatorsMap : { [ string ] : Array < string > } ,
2021-03-03 19:50:16 +01:00
fetchingModerationBlockList : boolean ,
2021-06-07 19:37:33 +02:00
fetchModBlockedList : ( ) => void ,
2021-06-16 04:27:58 +02:00
fetchModAmIList : ( ) => void ,
delegatorsById : { [ string ] : { global : boolean , delegators : { name : string , claimId : string } } } ,
myChannelClaims : ? Array < ChannelClaim > ,
2019-07-08 22:54:58 +02:00
} ;
function ListBlocked ( props : Props ) {
2021-06-16 04:27:58 +02:00
const {
mutedUris ,
personalBlockList ,
adminBlockList ,
moderatorBlockList ,
2021-08-20 09:18:54 +02:00
personalTimeoutMap ,
adminTimeoutMap ,
moderatorTimeoutMap ,
2021-09-10 17:36:08 +02:00
moderatorBlockListDelegatorsMap : delegatorsMap ,
2021-06-16 04:27:58 +02:00
fetchingModerationBlockList ,
fetchModBlockedList ,
fetchModAmIList ,
delegatorsById ,
myChannelClaims ,
} = props ;
const [ viewMode , setViewMode ] = usePersistedState ( 'blocked-muted:display' , VIEW . BLOCKED ) ;
2021-03-03 19:50:16 +01:00
2021-09-10 17:36:08 +02:00
const [ localDelegatorsMap , setLocalDelegatorsMap ] = React . useState ( undefined ) ;
2021-03-03 19:50:16 +01:00
2021-09-10 17:36:08 +02:00
const stringifiedDelegatorsMap = JSON . stringify ( delegatorsMap ) ;
const stringifiedLocalDelegatorsMap = JSON . stringify ( localDelegatorsMap ) ;
2021-06-16 04:27:58 +02:00
const isAdmin =
myChannelClaims && myChannelClaims . some ( ( c ) => delegatorsById [ c . claim _id ] && delegatorsById [ c . claim _id ] . global ) ;
2021-09-10 17:36:08 +02:00
2021-06-16 04:27:58 +02:00
const isModerator =
myChannelClaims &&
myChannelClaims . some (
( c ) => delegatorsById [ c . claim _id ] && Object . keys ( delegatorsById [ c . claim _id ] . delegators ) . length > 0
) ;
2021-09-10 17:36:08 +02:00
// **************************************************************************
2021-06-16 04:27:58 +02:00
2021-09-10 17:36:08 +02:00
function getList ( view ) {
2021-06-16 04:27:58 +02:00
switch ( view ) {
case VIEW . BLOCKED :
2021-09-10 17:36:08 +02:00
return personalBlockList ;
2021-06-16 04:27:58 +02:00
case VIEW . ADMIN :
2021-09-10 17:36:08 +02:00
return adminBlockList ;
2021-06-16 04:27:58 +02:00
case VIEW . MODERATOR :
2021-09-10 17:36:08 +02:00
return moderatorBlockList ;
2021-06-16 04:27:58 +02:00
case VIEW . MUTED :
2021-09-10 17:36:08 +02:00
return mutedUris ;
2021-06-16 04:27:58 +02:00
}
}
2021-09-10 17:36:08 +02:00
function getActionButtons ( uri ) {
2021-08-20 09:18:54 +02:00
const getDurationStr = ( durationNs ) => {
const NANO _TO _MS = 1000000 ;
return humanizeDuration ( durationNs / NANO _TO _MS , { round : true } ) ;
} ;
const getBanInfoElem = ( timeoutInfo ) => {
return (
< div >
< div className = "help" >
< blockquote >
{ moment ( timeoutInfo . blockedAt ) . format ( 'MMMM Do, YYYY @ HH:mm' ) }
< br / >
{ getDurationStr ( timeoutInfo . bannedFor ) } { ' ' }
{ _ _ ( '(Remaining: %duration%) --[timeout ban duration]--' , {
duration : getDurationStr ( timeoutInfo . banRemaining ) ,
} ) }
< / blockquote >
< / div >
< / div >
) ;
} ;
2021-09-10 17:36:08 +02:00
switch ( viewMode ) {
2021-06-16 04:27:58 +02:00
case VIEW . BLOCKED :
return (
< >
< ChannelBlockButton uri = { uri } / >
< ChannelMuteButton uri = { uri } / >
2021-08-20 09:18:54 +02:00
{ personalTimeoutMap [ uri ] && getBanInfoElem ( personalTimeoutMap [ uri ] ) }
2021-06-16 04:27:58 +02:00
< / >
) ;
case VIEW . ADMIN :
2021-08-20 09:18:54 +02:00
return (
< >
< ChannelBlockButton uri = { uri } blockLevel = { BLOCK _LEVEL . ADMIN } / >
{ adminTimeoutMap [ uri ] && getBanInfoElem ( adminTimeoutMap [ uri ] ) }
< / >
) ;
2021-06-16 04:27:58 +02:00
case VIEW . MODERATOR :
2021-09-10 17:36:08 +02:00
const delegatorUrisForBlockedUri = localDelegatorsMap && localDelegatorsMap [ uri ] ;
2021-06-16 04:27:58 +02:00
if ( ! delegatorUrisForBlockedUri ) return null ;
return (
< >
{ delegatorUrisForBlockedUri . map ( ( delegatorUri ) => {
return (
< div className = "block-list--delegator" key = { delegatorUri } >
2021-09-10 17:36:08 +02:00
< label > { _ _ ( 'Blocked on behalf of:' ) } < / label >
< ul className = "section" >
< div className = "content__non-clickable" >
< ClaimPreview uri = { delegatorUri } hideMenu hideActions type = "inline" properties = { false } / >
{ moderatorTimeoutMap [ uri ] && getBanInfoElem ( moderatorTimeoutMap [ uri ] ) }
< / div >
< ChannelBlockButton uri = { uri } blockLevel = { BLOCK _LEVEL . MODERATOR } creatorUri = { delegatorUri } / >
2021-06-16 04:27:58 +02:00
< / ul >
< / div >
) ;
} ) }
< / >
) ;
case VIEW . MUTED :
return (
< >
< ChannelMuteButton uri = { uri } / >
< ChannelBlockButton uri = { uri } / >
< / >
) ;
}
}
function getHelpText ( view ) {
switch ( view ) {
case VIEW . BLOCKED :
2021-09-15 04:08:41 +02:00
return _ _ (
"Blocked channels will be invisible to you in the app. They will not be able to comment on your content, nor reply to your comments left on other channels' content."
) ;
2021-06-16 04:27:58 +02:00
case VIEW . ADMIN :
2021-09-15 04:08:41 +02:00
return _ _ ( 'This is the global block list.' ) ;
2021-06-16 04:27:58 +02:00
case VIEW . MODERATOR :
2021-09-15 04:08:41 +02:00
return _ _ ( 'List of channels that you have blocked as a moderator, along with the list of delegators.' ) ;
2021-06-16 04:27:58 +02:00
case VIEW . MUTED :
2021-09-15 04:08:41 +02:00
return _ _ (
'Muted channels will be invisible to you in the app. They will not know they are muted and can still interact with you and your content.'
) ;
2021-06-16 04:27:58 +02:00
}
}
function getEmptyListTitle ( view ) {
switch ( view ) {
case VIEW . BLOCKED :
2021-09-15 04:08:41 +02:00
return _ _ ( 'You do not have any blocked channels' ) ;
2021-06-16 04:27:58 +02:00
case VIEW . MUTED :
2021-09-15 04:08:41 +02:00
return _ _ ( 'You do not have any muted channels' ) ;
2021-06-16 04:27:58 +02:00
case VIEW . ADMIN :
2021-09-15 04:08:41 +02:00
return _ _ ( 'You do not have any globally-blocked channels' ) ;
2021-06-16 04:27:58 +02:00
case VIEW . MODERATOR :
2021-09-15 04:08:41 +02:00
return _ _ ( 'You do not have any blocked channels as a moderator' ) ;
2021-06-16 04:27:58 +02:00
}
}
function getEmptyListSubtitle ( view ) {
switch ( view ) {
case VIEW . BLOCKED :
case VIEW . MUTED :
return getHelpText ( view ) ;
case VIEW . ADMIN :
case VIEW . MODERATOR :
return null ;
}
}
function isSourceListLarger ( source , local ) {
// Comparing the length of stringified is not perfect, but what are the
// chances of having different lists with the exact same length?
return source && ( ! local || local . length < source . length ) ;
}
2021-03-03 19:50:16 +01:00
2021-09-10 17:36:08 +02:00
function getViewElem ( view , label , icon ) {
return (
< Button
icon = { icon }
button = "alt"
label = { _ _ ( label ) }
className = { classnames ( ` button-toggle ` , {
'button-toggle--active' : viewMode === view ,
} ) }
onClick = { ( ) => setViewMode ( view ) }
/ >
) ;
}
2021-03-03 19:50:16 +01:00
2021-09-10 17:36:08 +02:00
function getRefreshElem ( ) {
return (
2021-09-24 09:01:51 +02:00
myChannelClaims && (
< Button
icon = { ICONS . REFRESH }
button = "alt"
label = { _ _ ( 'Refresh' ) }
onClick = { ( ) => {
fetchModBlockedList ( ) ;
fetchModAmIList ( ) ;
} }
/ >
)
2021-09-10 17:36:08 +02:00
) ;
}
2019-07-08 22:54:58 +02:00
2021-09-10 17:36:08 +02:00
// **************************************************************************
2021-06-16 04:27:58 +02:00
React . useEffect ( ( ) => {
2021-09-10 17:36:08 +02:00
if ( stringifiedDelegatorsMap && isSourceListLarger ( stringifiedDelegatorsMap , stringifiedLocalDelegatorsMap ) ) {
setLocalDelegatorsMap ( JSON . parse ( stringifiedDelegatorsMap ) ) ;
2021-06-16 04:27:58 +02:00
}
2021-09-10 17:36:08 +02:00
} , [ stringifiedDelegatorsMap , stringifiedLocalDelegatorsMap ] ) ;
2021-06-16 04:27:58 +02:00
2021-09-10 17:36:08 +02:00
// **************************************************************************
2021-03-04 07:03:58 +01:00
2019-07-08 22:54:58 +02:00
return (
2021-08-19 07:58:40 +02:00
< Page
noFooter
noSideNavigation
settingsPage
backout = { { title : _ _ ( 'Blocked and muted channels' ) , backLabel : _ _ ( 'Back' ) } }
>
2021-03-04 07:03:58 +01:00
{ fetchingModerationBlockList && (
2019-07-08 22:54:58 +02:00
< div className = "main--empty" >
2021-03-03 19:50:16 +01:00
< Spinner / >
2019-07-08 22:54:58 +02:00
< / div >
) }
2021-03-03 19:50:16 +01:00
2021-03-04 07:03:58 +01:00
{ ! fetchingModerationBlockList && (
2021-03-03 19:50:16 +01:00
< >
< div className = "section__header--actions" >
< div className = "section__actions--inline" >
2021-09-10 17:36:08 +02:00
{ getViewElem ( VIEW . BLOCKED , 'Blocked' , ICONS . BLOCK ) }
{ isAdmin && getViewElem ( VIEW . ADMIN , 'Global' , ICONS . BLOCK ) }
{ isModerator && getViewElem ( VIEW . MODERATOR , 'Moderator' , ICONS . BLOCK ) }
{ getViewElem ( VIEW . MUTED , 'Muted' , ICONS . MUTE ) }
2021-06-07 19:37:33 +02:00
< / div >
2021-09-10 17:36:08 +02:00
< div className = "section__actions--inline" > { getRefreshElem ( ) } < / div >
2021-03-03 19:50:16 +01:00
< / div >
2021-03-04 07:03:58 +01:00
2021-09-10 17:36:08 +02:00
< BlockList
key = { viewMode }
uris = { getList ( viewMode ) }
help = { getHelpText ( viewMode ) }
titleEmptyList = { getEmptyListTitle ( viewMode ) }
subtitle = { getEmptyListSubtitle ( viewMode ) }
getActionButtons = { getActionButtons }
className = { viewMode === VIEW . MODERATOR ? 'block-list--moderator' : undefined }
/ >
2021-03-03 19:50:16 +01:00
< / >
) }
2019-07-08 22:54:58 +02:00
< / Page >
) ;
}
export default ListBlocked ;