2024-01-25 09:57:57 +00:00
import { createInfiniteScroll } from '@solid-primitives/pagination'
import { clsx } from 'clsx'
2024-02-04 11:25:21 +00:00
import { For , Show , createEffect , createSignal , on } from 'solid-js'
2024-01-25 09:57:57 +00:00
2024-07-04 07:51:15 +00:00
import { useAuthors } from '~/context/authors'
import { useInbox } from '~/context/inbox'
import { useLocalize } from '~/context/localize'
2024-06-24 17:50:27 +00:00
import { useUI } from '~/context/ui'
2024-07-04 07:51:15 +00:00
import { Author } from '~/graphql/schema/core.gen'
2024-01-25 09:57:57 +00:00
import { AuthorBadge } from '../../Author/AuthorBadge'
2024-06-24 17:50:27 +00:00
import { InlineLoader } from '../../InlineLoader'
2024-01-25 09:57:57 +00:00
import { Button } from '../Button'
import { DropdownSelect } from '../DropdownSelect'
import styles from './InviteMembers.module.scss'
type InviteAuthor = Author & { selected : boolean }
type Props = {
title? : string
variant ? : 'coauthors' | 'recipients'
}
const PAGE_SIZE = 50
export const InviteMembers = ( props : Props ) = > {
const { t } = useLocalize ( )
2024-06-24 17:50:27 +00:00
const { hideModal } = useUI ( )
2024-01-25 09:57:57 +00:00
const roles = [
{
title : t ( 'Editor' ) ,
2024-06-26 08:22:05 +00:00
description : t ( 'Can write and edit text directly, and accept or reject suggestions from others' )
2024-01-25 09:57:57 +00:00
} ,
{
title : t ( 'Co-author' ) ,
2024-06-26 08:22:05 +00:00
description : t ( 'Can make any changes, accept or reject suggestions, and share access with others' )
2024-01-25 09:57:57 +00:00
} ,
{
title : t ( 'Commentator' ) ,
2024-06-26 08:22:05 +00:00
description : t ( 'Can offer edits and comments, but cannot edit the post or share access with others' )
}
2024-01-25 09:57:57 +00:00
]
2024-06-24 17:50:27 +00:00
const { authorsSorted } = useAuthors ( )
2024-02-04 17:40:15 +00:00
const { loadChats , createChat } = useInbox ( )
2024-01-25 09:57:57 +00:00
const [ authorsToInvite , setAuthorsToInvite ] = createSignal < InviteAuthor [ ] > ( )
const [ searchResultAuthors , setSearchResultAuthors ] = createSignal < Author [ ] > ( )
const [ collectionToInvite , setCollectionToInvite ] = createSignal < number [ ] > ( [ ] )
const fetcher = async ( page : number ) = > {
await new Promise ( ( resolve , reject ) = > {
const checkDataLoaded = ( ) = > {
2024-07-05 19:40:54 +00:00
if ( ( authorsSorted ? . ( ) . length || 0 ) > 0 ) {
2024-01-25 09:57:57 +00:00
resolve ( true )
} else {
setTimeout ( checkDataLoaded , 100 )
}
}
setTimeout ( ( ) = > reject ( new Error ( 'Timeout waiting for sortedAuthors' ) ) , 10000 )
checkDataLoaded ( )
} )
const start = page * PAGE_SIZE
const end = start + PAGE_SIZE
2024-01-25 19:16:38 +00:00
const authors = authorsToInvite ( ) ? . map ( ( author ) = > ( { . . . author , selected : false } ) )
2024-06-24 17:50:27 +00:00
return authors ? . slice ( start , end ) || [ ]
2024-01-25 09:57:57 +00:00
}
2024-02-22 07:29:52 +00:00
const [ pages , setEl , { end } ] = createInfiniteScroll ( fetcher )
2024-01-25 09:57:57 +00:00
createEffect (
on (
2024-06-24 17:50:27 +00:00
authorsSorted ,
2024-01-25 09:57:57 +00:00
( currentAuthors ) = > {
setAuthorsToInvite ( currentAuthors . map ( ( author ) = > ( { . . . author , selected : false } ) ) )
} ,
2024-06-26 08:22:05 +00:00
{ defer : true }
)
2024-01-25 09:57:57 +00:00
)
const handleInputChange = async ( value : string ) = > {
if ( value . length > 1 ) {
2024-02-04 06:38:45 +00:00
const match = authorsToInvite ( ) ? . filter ( ( author ) = >
2024-06-26 08:22:05 +00:00
author . name ? . toLowerCase ( ) . includes ( value . toLowerCase ( ) )
2024-01-25 09:57:57 +00:00
)
setSearchResultAuthors ( match )
} else {
setSearchResultAuthors ( )
}
}
2024-06-24 17:50:27 +00:00
const handleInvite = ( id : number ) = > {
2024-01-25 09:57:57 +00:00
setCollectionToInvite ( ( prev ) = > [ . . . prev , id ] )
}
const handleCloseModal = ( ) = > {
setSearchResultAuthors ( )
2024-06-24 17:50:27 +00:00
setCollectionToInvite ( [ ] )
2024-01-25 09:57:57 +00:00
hideModal ( )
}
const handleCreate = async ( ) = > {
try {
2024-01-27 06:21:48 +00:00
const initChat = await createChat ( collectionToInvite ( ) , 'chat Title' )
2024-01-25 09:57:57 +00:00
console . debug ( '[components.Inbox] create chat result:' , initChat )
hideModal ( )
2024-01-27 06:21:48 +00:00
await loadChats ( )
2024-01-25 09:57:57 +00:00
} catch ( error ) {
console . error ( 'handleCreate chat' , error )
}
}
return (
2024-02-02 04:31:25 +00:00
< >
2024-01-25 09:57:57 +00:00
< h2 > { props . title || t ( 'Invite collaborators' ) } < / h2 >
< div class = { clsx ( styles . InviteMembers ) } >
< div class = { styles . searchHeader } >
< div class = { styles . field } >
< input
class = { styles . input }
type = "text"
placeholder = { t ( 'Write your colleagues name or email' ) }
onChange = { ( e ) = > {
if ( props . variant === 'recipients' ) return
handleInputChange ( e . target . value )
} }
onInput = { ( e ) = > {
if ( props . variant === 'coauthors' ) return
handleInputChange ( e . target . value )
} }
/ >
< Show when = { props . variant === 'coauthors' } >
< DropdownSelect selectItems = { roles } / >
< / Show >
< / div >
< Show when = { props . variant === 'coauthors' } >
< Button class = { styles . searchButton } variant = { 'bordered' } size = { 'M' } value = { t ( 'Search' ) } / >
< / Show >
< / div >
< Show when = { props . variant === 'coauthors' } >
< div class = { styles . teaser } >
< h3 > { t ( 'Coming soon' ) } < / h3 >
< p >
{ t (
2024-06-26 08:22:05 +00:00
'We are working on collaborative editing of articles and in the near future you will have an amazing opportunity - to create together with your colleagues'
2024-01-25 09:57:57 +00:00
) }
< / p >
< / div >
< / Show >
< Show when = { props . variant === 'recipients' } >
< div class = { styles . authors } >
< For each = { searchResultAuthors ( ) ? ? pages ( ) } >
{ ( author ) = > (
< div class = { styles . author } >
< AuthorBadge
author = { author }
nameOnly = { true }
inviteView = { true }
onInvite = { ( id ) = > handleInvite ( id ) }
/ >
< / div >
) }
< / For >
< Show when = { ! end ( ) } >
2024-06-24 17:50:27 +00:00
< div ref = { ( el : HTMLDivElement ) = > setEl ( el , ( ) = > true ) } >
2024-02-22 07:29:52 +00:00
< InlineLoader / >
2024-01-25 09:57:57 +00:00
< / div >
< / Show >
< / div >
< / Show >
< div class = { styles . actions } >
< Button variant = { 'bordered' } size = { 'M' } value = { t ( 'Cancel' ) } onClick = { handleCloseModal } / >
< Button
variant = { 'primary' }
size = { 'M' }
disabled = { collectionToInvite ( ) . length === 0 }
value = { t ( 'Start dialog' ) }
onClick = { handleCreate }
/ >
< / div >
< / div >
2024-02-02 04:31:25 +00:00
< / >
2024-01-25 09:57:57 +00:00
)
}