2024-06-02 20:58:11 +03:00
import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client' ;
import React , { useCallback , useEffect , useState , useRef } from 'react' ;
2021-10-02 18:10:14 +03:00
2023-05-01 16:50:41 -04:00
import Dashboard from '../../../../utils/dashboard' ;
2024-08-14 13:31:34 -04:00
import globalize from '../../../../lib/globalize' ;
2023-05-01 16:50:41 -04:00
import loading from '../../../../components/loading/loading' ;
import toast from '../../../../components/toast/toast' ;
import SectionTitleContainer from '../../../../elements/SectionTitleContainer' ;
import InputElement from '../../../../elements/InputElement' ;
import ButtonElement from '../../../../elements/ButtonElement' ;
import AccessContainer from '../../../../components/dashboard/users/AccessContainer' ;
import CheckBoxElement from '../../../../elements/CheckBoxElement' ;
import Page from '../../../../components/Page' ;
2021-10-02 18:10:14 +03:00
2024-10-17 01:23:38 -04:00
type UserInput = {
2021-10-02 18:10:14 +03:00
Name? : string ;
Password? : string ;
2023-05-02 15:54:53 -04:00
} ;
2021-10-02 18:10:14 +03:00
2021-10-09 19:35:10 +03:00
type ItemsArr = {
2024-06-02 20:58:11 +03:00
Name? : string | null ;
2021-10-09 19:35:10 +03:00
Id? : string ;
2023-05-02 15:54:53 -04:00
} ;
2021-10-09 19:35:10 +03:00
2024-06-02 20:58:11 +03:00
const UserNew = ( ) = > {
2022-02-15 23:49:46 +03:00
const [ channelsItems , setChannelsItems ] = useState < ItemsArr [ ] > ( [ ] ) ;
const [ mediaFoldersItems , setMediaFoldersItems ] = useState < ItemsArr [ ] > ( [ ] ) ;
2022-02-15 23:47:59 +03:00
const element = useRef < HTMLDivElement > ( null ) ;
2021-10-02 18:10:14 +03:00
2024-06-02 20:58:11 +03:00
const getItemsResult = ( items : BaseItemDto [ ] ) = > {
2021-11-06 21:02:59 +03:00
return items . map ( item = >
( {
Id : item.Id ,
Name : item.Name
} )
) ;
} ;
2021-10-02 18:10:14 +03:00
2024-06-02 20:58:11 +03:00
const loadMediaFolders = useCallback ( ( result : BaseItemDto [ ] ) = > {
2022-02-16 00:37:06 +03:00
const page = element . current ;
if ( ! page ) {
console . error ( 'Unexpected null reference' ) ;
return ;
}
2021-11-06 21:02:59 +03:00
const mediaFolders = getItemsResult ( result ) ;
2021-10-02 18:10:14 +03:00
2021-11-06 21:02:59 +03:00
setMediaFoldersItems ( mediaFolders ) ;
2021-10-09 21:29:30 +03:00
2022-02-16 22:01:13 +03:00
const folderAccess = page . querySelector ( '.folderAccess' ) as HTMLDivElement ;
2021-11-06 21:02:59 +03:00
folderAccess . dispatchEvent ( new CustomEvent ( 'create' ) ) ;
2021-10-09 19:35:10 +03:00
2022-02-16 22:01:13 +03:00
( page . querySelector ( '.chkEnableAllFolders' ) as HTMLInputElement ) . checked = false ;
2021-11-06 21:02:59 +03:00
} , [ ] ) ;
2021-10-02 18:10:14 +03:00
2024-06-02 20:58:11 +03:00
const loadChannels = useCallback ( ( result : BaseItemDto [ ] ) = > {
2022-02-16 00:37:06 +03:00
const page = element . current ;
if ( ! page ) {
console . error ( 'Unexpected null reference' ) ;
return ;
}
2021-11-06 21:02:59 +03:00
const channels = getItemsResult ( result ) ;
2021-10-02 18:10:14 +03:00
2021-11-06 21:02:59 +03:00
setChannelsItems ( channels ) ;
2021-10-02 18:10:14 +03:00
2022-02-16 22:01:13 +03:00
const channelAccess = page . querySelector ( '.channelAccess' ) as HTMLDivElement ;
2021-11-06 21:02:59 +03:00
channelAccess . dispatchEvent ( new CustomEvent ( 'create' ) ) ;
2021-10-09 19:35:10 +03:00
2022-02-16 22:01:13 +03:00
const channelAccessContainer = page . querySelector ( '.channelAccessContainer' ) as HTMLDivElement ;
2021-11-06 21:02:59 +03:00
channels . length ? channelAccessContainer . classList . remove ( 'hide' ) : channelAccessContainer . classList . add ( 'hide' ) ;
2021-10-02 18:10:14 +03:00
2022-02-16 22:01:13 +03:00
( page . querySelector ( '.chkEnableAllChannels' ) as HTMLInputElement ) . checked = false ;
2021-11-06 21:02:59 +03:00
} , [ ] ) ;
2021-10-02 18:10:14 +03:00
2021-11-06 21:02:59 +03:00
const loadUser = useCallback ( ( ) = > {
2022-02-16 00:37:06 +03:00
const page = element . current ;
if ( ! page ) {
console . error ( 'Unexpected null reference' ) ;
return ;
}
2022-02-16 22:01:13 +03:00
( page . querySelector ( '#txtUsername' ) as HTMLInputElement ) . value = '' ;
( page . querySelector ( '#txtPassword' ) as HTMLInputElement ) . value = '' ;
2021-11-06 21:02:59 +03:00
loading . show ( ) ;
const promiseFolders = window . ApiClient . getJSON ( window . ApiClient . getUrl ( 'Library/MediaFolders' , {
IsHidden : false
} ) ) ;
const promiseChannels = window . ApiClient . getJSON ( window . ApiClient . getUrl ( 'Channels' ) ) ;
Promise . all ( [ promiseFolders , promiseChannels ] ) . then ( function ( responses ) {
loadMediaFolders ( responses [ 0 ] . Items ) ;
loadChannels ( responses [ 1 ] . Items ) ;
loading . hide ( ) ;
2023-05-02 11:24:53 -04:00
} ) . catch ( err = > {
console . error ( '[usernew] failed to load data' , err ) ;
2021-11-06 21:02:59 +03:00
} ) ;
} , [ loadChannels , loadMediaFolders ] ) ;
2021-10-02 18:10:14 +03:00
2021-11-06 21:02:59 +03:00
useEffect ( ( ) = > {
2022-02-16 00:37:06 +03:00
const page = element . current ;
if ( ! page ) {
console . error ( 'Unexpected null reference' ) ;
return ;
}
2021-11-06 21:02:59 +03:00
loadUser ( ) ;
2021-10-02 18:10:14 +03:00
const saveUser = ( ) = > {
2024-10-17 01:23:38 -04:00
const userInput : UserInput = { } ;
2022-02-16 22:01:13 +03:00
userInput . Name = ( page . querySelector ( '#txtUsername' ) as HTMLInputElement ) . value ;
userInput . Password = ( page . querySelector ( '#txtPassword' ) as HTMLInputElement ) . value ;
2021-10-02 18:10:14 +03:00
window . ApiClient . createUser ( userInput ) . then ( function ( user ) {
2023-04-26 12:32:15 -04:00
if ( ! user . Id || ! user . Policy ) {
throw new Error ( 'Unexpected null user id or policy' ) ;
2022-02-18 13:08:44 +03:00
}
2022-02-16 22:01:13 +03:00
user . Policy . EnableAllFolders = ( page . querySelector ( '.chkEnableAllFolders' ) as HTMLInputElement ) . checked ;
2021-10-02 18:10:14 +03:00
user . Policy . EnabledFolders = [ ] ;
if ( ! user . Policy . EnableAllFolders ) {
2022-02-16 00:37:06 +03:00
user . Policy . EnabledFolders = Array . prototype . filter . call ( page . querySelectorAll ( '.chkFolder' ) , function ( i ) {
2021-10-02 18:10:14 +03:00
return i . checked ;
} ) . map ( function ( i ) {
return i . getAttribute ( 'data-id' ) ;
} ) ;
}
2022-02-16 22:01:13 +03:00
user . Policy . EnableAllChannels = ( page . querySelector ( '.chkEnableAllChannels' ) as HTMLInputElement ) . checked ;
2021-10-02 18:10:14 +03:00
user . Policy . EnabledChannels = [ ] ;
if ( ! user . Policy . EnableAllChannels ) {
2022-02-16 00:37:06 +03:00
user . Policy . EnabledChannels = Array . prototype . filter . call ( page . querySelectorAll ( '.chkChannel' ) , function ( i ) {
2021-10-02 18:10:14 +03:00
return i . checked ;
} ) . map ( function ( i ) {
return i . getAttribute ( 'data-id' ) ;
} ) ;
}
window . ApiClient . updateUserPolicy ( user . Id , user . Policy ) . then ( function ( ) {
2023-09-25 00:00:36 -04:00
Dashboard . navigate ( '/dashboard/users/profile?userId=' + user . Id )
2023-05-02 11:24:53 -04:00
. catch ( err = > {
console . error ( '[usernew] failed to navigate to edit user page' , err ) ;
} ) ;
} ) . catch ( err = > {
console . error ( '[usernew] failed to update user policy' , err ) ;
2021-10-02 18:10:14 +03:00
} ) ;
2024-12-17 07:21:49 +00:00
} , function ( error ) {
try {
console . error ( '[usernew] failed to create new user' , error ) ;
error . text ( ) . then ( ( errorMessage : string ) = > {
toast ( errorMessage ) ;
loading . hide ( ) ;
} ) ;
} catch {
toast ( globalize . translate ( 'ErrorDefault' ) ) ;
loading . hide ( ) ;
}
2021-10-02 18:10:14 +03:00
} ) ;
} ;
2022-02-18 14:27:39 +03:00
const onSubmit = ( e : Event ) = > {
2021-10-02 18:10:14 +03:00
loading . show ( ) ;
saveUser ( ) ;
e . preventDefault ( ) ;
e . stopPropagation ( ) ;
return false ;
} ;
2022-02-16 22:01:13 +03:00
( page . querySelector ( '.chkEnableAllChannels' ) as HTMLInputElement ) . addEventListener ( 'change' , function ( this : HTMLInputElement ) {
const channelAccessListContainer = page . querySelector ( '.channelAccessListContainer' ) as HTMLDivElement ;
2021-10-09 23:00:04 +03:00
this . checked ? channelAccessListContainer . classList . add ( 'hide' ) : channelAccessListContainer . classList . remove ( 'hide' ) ;
2021-10-02 18:10:14 +03:00
} ) ;
2022-02-16 22:01:13 +03:00
( page . querySelector ( '.chkEnableAllFolders' ) as HTMLInputElement ) . addEventListener ( 'change' , function ( this : HTMLInputElement ) {
const folderAccessListContainer = page . querySelector ( '.folderAccessListContainer' ) as HTMLDivElement ;
2021-10-09 23:00:04 +03:00
this . checked ? folderAccessListContainer . classList . add ( 'hide' ) : folderAccessListContainer . classList . remove ( 'hide' ) ;
2021-10-02 18:10:14 +03:00
} ) ;
2022-02-16 22:01:13 +03:00
( page . querySelector ( '.newUserProfileForm' ) as HTMLFormElement ) . addEventListener ( 'submit' , onSubmit ) ;
2021-10-02 18:10:14 +03:00
2022-06-29 02:17:10 +03:00
( page . querySelector ( '#btnCancel' ) as HTMLButtonElement ) . addEventListener ( 'click' , function ( ) {
2021-10-02 18:10:14 +03:00
window . history . back ( ) ;
} ) ;
2021-11-06 21:02:59 +03:00
} , [ loadUser ] ) ;
2021-10-02 18:10:14 +03:00
return (
2022-06-29 02:56:49 +03:00
< Page
id = 'newUserPage'
className = 'mainAnimatedPage type-interior'
>
< div ref = { element } className = 'content-primary' >
2022-06-29 02:17:10 +03:00
< div className = 'verticalSection' >
< SectionTitleContainer
title = { globalize . translate ( 'HeaderAddUser' ) }
/ >
< / div >
2021-10-02 18:10:14 +03:00
< form className = 'newUserProfileForm' >
< div className = 'inputContainer' >
< InputElement
type = 'text'
id = 'txtUsername'
label = 'LabelName'
2024-12-18 08:15:43 +00:00
validator = { { pattern : '^([\\w \\-\'._@+]*)([\\w\\-\'._@+])([\\w \\-\'._@+]*)$' , errMessage : 'Username must not be empty and contain only numbers, letters, spaces, or the following symbols -\'._@+' } }
2021-10-02 18:10:14 +03:00
options = { 'required' }
/ >
< / div >
< div className = 'inputContainer' >
< InputElement
type = 'password'
id = 'txtPassword'
label = 'LabelPassword'
/ >
< / div >
2022-05-07 22:10:01 +03:00
< AccessContainer
2022-05-09 20:11:47 +03:00
containerClassName = 'folderAccessContainer'
headerTitle = 'HeaderLibraryAccess'
checkBoxClassName = 'chkEnableAllFolders'
checkBoxTitle = 'OptionEnableAccessToAllLibraries'
listContainerClassName = 'folderAccessListContainer'
accessClassName = 'folderAccess'
listTitle = 'HeaderLibraries'
description = 'LibraryAccessHelp'
2022-05-07 22:10:01 +03:00
>
{ mediaFoldersItems . map ( Item = > (
2022-06-29 02:17:10 +03:00
< CheckBoxElement
2022-05-07 22:10:01 +03:00
key = { Item . Id }
className = 'chkFolder'
2022-06-29 02:17:10 +03:00
itemId = { Item . Id }
itemName = { Item . Name }
2022-05-07 22:10:01 +03:00
/ >
) ) }
< / AccessContainer >
< AccessContainer
2022-05-09 20:11:47 +03:00
containerClassName = 'channelAccessContainer verticalSection-extrabottompadding hide'
headerTitle = 'HeaderChannelAccess'
checkBoxClassName = 'chkEnableAllChannels'
checkBoxTitle = 'OptionEnableAccessToAllChannels'
listContainerClassName = 'channelAccessListContainer'
accessClassName = 'channelAccess'
listTitle = 'Channels'
description = 'ChannelAccessHelp'
2022-05-07 22:10:01 +03:00
>
{ channelsItems . map ( Item = > (
2022-06-29 02:17:10 +03:00
< CheckBoxElement
2022-05-07 22:10:01 +03:00
key = { Item . Id }
className = 'chkChannel'
2022-06-29 02:17:10 +03:00
itemId = { Item . Id }
itemName = { Item . Name }
2022-05-07 22:10:01 +03:00
/ >
) ) }
< / AccessContainer >
2021-10-02 18:10:14 +03:00
< div >
< ButtonElement
type = 'submit'
className = 'raised button-submit block'
title = 'Save'
/ >
< ButtonElement
type = 'button'
2022-06-29 02:17:10 +03:00
id = 'btnCancel'
className = 'raised button-cancel block'
2021-10-02 18:10:14 +03:00
title = 'ButtonCancel'
/ >
< / div >
< / form >
< / div >
2022-06-29 02:56:49 +03:00
< / Page >
2021-10-02 18:10:14 +03:00
) ;
} ;
2022-06-29 23:35:56 +03:00
export default UserNew ;