From c6966c67f7f79bbfe6f249e9bd88f2b62c447414 Mon Sep 17 00:00:00 2001 From: grafixeyehero <32230989+grafixeyehero@users.noreply.github.com> Date: Wed, 5 Jan 2022 19:43:40 +0300 Subject: [PATCH] Convert userParentalControlPage to react --- .../dashboard/users/AccessScheduleList.tsx | 60 +++ .../dashboard/users/BlockedTagList.tsx | 38 ++ .../users/SectionTitleButtonElement.tsx | 15 +- .../users/SelectMaxParentalRating.tsx | 41 ++ src/components/pages/UserParentalControl.tsx | 379 ++++++++++++++++++ .../dashboard/users/userparentalcontrol.html | 57 --- .../dashboard/users/userparentalcontrol.js | 274 ------------- src/scripts/routes.js | 2 +- 8 files changed, 527 insertions(+), 339 deletions(-) create mode 100644 src/components/dashboard/users/AccessScheduleList.tsx create mode 100644 src/components/dashboard/users/BlockedTagList.tsx create mode 100644 src/components/dashboard/users/SelectMaxParentalRating.tsx create mode 100644 src/components/pages/UserParentalControl.tsx delete mode 100644 src/controllers/dashboard/users/userparentalcontrol.js diff --git a/src/components/dashboard/users/AccessScheduleList.tsx b/src/components/dashboard/users/AccessScheduleList.tsx new file mode 100644 index 0000000000..b46c6beeb0 --- /dev/null +++ b/src/components/dashboard/users/AccessScheduleList.tsx @@ -0,0 +1,60 @@ +import React, { FunctionComponent } from 'react'; +import datetime from '../../../scripts/datetime'; +import globalize from '../../../scripts/globalize'; + +const createButtonElement = ({index}) => ({ + __html: `` +}); + +type IProps = { + index: number; + Id: number; + DayOfWeek?: string; + StartHour?: number ; + EndHour?: number; +} + +function getDisplayTime(hours) { + let minutes = 0; + const pct = hours % 1; + + if (pct) { + minutes = Math.floor(60 * pct); + } + + return datetime.getDisplayTime(new Date(2000, 1, 1, hours, minutes, 0, 0)); +} + +const AccessScheduleList: FunctionComponent = ({index, DayOfWeek, StartHour, EndHour}: IProps) => { + return ( +
+
+

+ {globalize.translate(DayOfWeek)} +

+
+ {getDisplayTime(StartHour) + ' - ' + getDisplayTime(EndHour)} +
+
+
+
+ ); +}; + +export default AccessScheduleList; diff --git a/src/components/dashboard/users/BlockedTagList.tsx b/src/components/dashboard/users/BlockedTagList.tsx new file mode 100644 index 0000000000..b8ae5081cf --- /dev/null +++ b/src/components/dashboard/users/BlockedTagList.tsx @@ -0,0 +1,38 @@ +import React, { FunctionComponent } from 'react'; + +const createButtonElement = ({tag}) => ({ + __html: `` +}); + +type IProps = { + tag: any; +} + +const BlockedTagList: FunctionComponent = ({tag}: IProps) => { + return ( +
+
+
+

+ {tag} +

+
+
+
+ +
+ ); +}; + +export default BlockedTagList; diff --git a/src/components/dashboard/users/SectionTitleButtonElement.tsx b/src/components/dashboard/users/SectionTitleButtonElement.tsx index 52c94ba4af..2147e228b9 100644 --- a/src/components/dashboard/users/SectionTitleButtonElement.tsx +++ b/src/components/dashboard/users/SectionTitleButtonElement.tsx @@ -1,23 +1,24 @@ import React, { FunctionComponent } from 'react'; import globalize from '../../../scripts/globalize'; +type IProps = { + title: string; + className?: string; + icon: string, +} + const createButtonElement = ({ className, title, icon }) => ({ __html: `` }); -type IProps = { - title?: string; - className?: string; - icon?: string, -} - const SectionTitleButtonElement: FunctionComponent = ({ className, title, icon }: IProps) => { return (
({ + __html: `` +}); + +type IProps = { + className?: string; + label?: string; + parentalRatings: any +} + +const SelectMaxParentalRating: FunctionComponent = ({ className, label, parentalRatings }: IProps) => { + const renderOption = ratings => { + let content = ''; + for (const rating of ratings) { + content += ``; + } + return content; + }; + + return ( +
+ ); +}; + +export default SelectMaxParentalRating; diff --git a/src/components/pages/UserParentalControl.tsx b/src/components/pages/UserParentalControl.tsx new file mode 100644 index 0000000000..7d408fd6c5 --- /dev/null +++ b/src/components/pages/UserParentalControl.tsx @@ -0,0 +1,379 @@ +import React, { FunctionComponent, useCallback, useEffect, useState, useRef } from 'react'; +import globalize from '../../scripts/globalize'; +import LibraryMenu from '../../scripts/libraryMenu'; +import { appRouter } from '../appRouter'; +import AccessScheduleList from '../dashboard/users/AccessScheduleList'; +import BlockedTagList from '../dashboard/users/BlockedTagList'; +import ButtonElement from '../dashboard/users/ButtonElement'; +import CheckBoxListItem from '../dashboard/users/CheckBoxListItem'; +import SectionTitleButtonElement from '../dashboard/users/SectionTitleButtonElement'; +import SectionTitleLinkElement from '../dashboard/users/SectionTitleLinkElement'; +import SelectMaxParentalRating from '../dashboard/users/SelectMaxParentalRating'; +import SectionTabs from '../dashboard/users/SectionTabs'; +import loading from '../loading/loading'; +import toast from '../toast/toast'; + +type Ratings = { + Name: string; + Value: string; +} + +type ItemsArr = { + name: string; + value: string; + checkedAttribute: string +} + +const UserParentalControl: FunctionComponent = () => { + const [ userName, setUserName ] = useState(''); + const [ parentalRatings, setParentalRatings ] = useState([]); + const [ unratedItems, setUnratedItems ] = useState([]); + const [ accessSchedules, setAccessSchedules ] = useState([]); + const [ blockedTags, setBlockedTags ] = useState([]); + + const element = useRef(null); + + const populateRatings = useCallback((allParentalRatings) => { + let rating; + const ratings: Ratings[] = []; + + for (let i = 0, length = allParentalRatings.length; i < length; i++) { + rating = allParentalRatings[i]; + + if (ratings.length) { + const lastRating = ratings[ratings.length - 1]; + + if (lastRating.Value === rating.Value) { + lastRating.Name += '/' + rating.Name; + continue; + } + } + + ratings.push({ + Name: rating.Name, + Value: rating.Value + }); + } + + setParentalRatings(ratings); + }, []); + + const loadUnratedItems = useCallback((user) => { + const items = [{ + name: globalize.translate('Books'), + value: 'Book' + }, { + name: globalize.translate('Channels'), + value: 'ChannelContent' + }, { + name: globalize.translate('LiveTV'), + value: 'LiveTvChannel' + }, { + name: globalize.translate('Movies'), + value: 'Movie' + }, { + name: globalize.translate('Music'), + value: 'Music' + }, { + name: globalize.translate('Trailers'), + value: 'Trailer' + }, { + name: globalize.translate('Shows'), + value: 'Series' + }]; + + const itemsArr: ItemsArr[] = []; + + for (const item of items) { + const isChecked = user.Policy.BlockUnratedItems.indexOf(item.value) != -1; + const checkedAttribute = isChecked ? ' checked="checked"' : ''; + itemsArr.push({ + value: item.value, + name: item.name, + checkedAttribute: checkedAttribute + }); + } + + setUnratedItems(itemsArr); + + const blockUnratedItems = element?.current?.querySelector('.blockUnratedItems'); + blockUnratedItems.dispatchEvent(new CustomEvent('create')); + }, []); + + const loadBlockedTags = useCallback((tags) => { + setBlockedTags(tags); + + const blockedTagsElem = element?.current?.querySelector('.blockedTags'); + + for (const btnDeleteTag of blockedTagsElem.querySelectorAll('.btnDeleteTag')) { + btnDeleteTag.addEventListener('click', function () { + const tag = btnDeleteTag.getAttribute('data-tag'); + const newTags = tags.filter(function (t) { + return t != tag; + }); + loadBlockedTags(newTags); + }); + } + }, []); + + const renderAccessSchedule = useCallback((schedules) => { + setAccessSchedules(schedules); + + const accessScheduleList = element?.current?.querySelector('.accessScheduleList'); + + for (const btnDelete of accessScheduleList.querySelectorAll('.btnDelete')) { + btnDelete.addEventListener('click', function () { + const index = parseInt(btnDelete.getAttribute('data-index')); + schedules.splice(index, 1); + const newindex = schedules.filter(function (i) { + return i != index; + }); + renderAccessSchedule(newindex); + }); + } + }, []); + + const loadUser = useCallback((user, allParentalRatings) => { + setUserName(user.Name); + LibraryMenu.setTitle(user.Name); + loadUnratedItems(user); + + loadBlockedTags(user.Policy.BlockedTags); + populateRatings(allParentalRatings); + let ratingValue = ''; + + if (user.Policy.MaxParentalRating) { + for (let i = 0, length = allParentalRatings.length; i < length; i++) { + const rating = allParentalRatings[i]; + + if (user.Policy.MaxParentalRating >= rating.Value) { + ratingValue = rating.Value; + } + } + } + + element.current.querySelector('.selectMaxParentalRating').value = ratingValue; + + if (user.Policy.IsAdministrator) { + element?.current?.querySelector('.accessScheduleSection').classList.add('hide'); + } else { + element?.current?.querySelector('.accessScheduleSection').classList.remove('hide'); + } + renderAccessSchedule(user.Policy.AccessSchedules || []); + loading.hide(); + }, [loadBlockedTags, loadUnratedItems, populateRatings, renderAccessSchedule]); + + const loadData = useCallback(() => { + loading.show(); + const userId = appRouter.param('userId'); + const promise1 = window.ApiClient.getUser(userId); + const promise2 = window.ApiClient.getParentalRatings(); + // eslint-disable-next-line compat/compat + Promise.all([promise1, promise2]).then(function (responses) { + loadUser(responses[0], responses[1]); + }); + }, [loadUser]); + + useEffect(() => { + loadData(); + + const onSaveComplete = () => { + loading.hide(); + toast(globalize.translate('SettingsSaved')); + }; + + const saveUser = (user) => { + user.Policy.MaxParentalRating = element?.current?.querySelector('.selectMaxParentalRating').value || null; + user.Policy.BlockUnratedItems = Array.prototype.filter.call(element?.current?.querySelectorAll('.chkUnratedItem'), function (i) { + return i.checked; + }).map(function (i) { + return i.getAttribute('data-id'); + }); + user.Policy.AccessSchedules = getSchedulesFromPage(); + user.Policy.BlockedTags = getBlockedTagsFromPage(); + window.ApiClient.updateUserPolicy(user.Id, user.Policy).then(function () { + onSaveComplete(); + }); + }; + + const showSchedulePopup = (schedule, index) => { + schedule = schedule || {}; + import('../../components/accessSchedule/accessSchedule').then(({default: accessschedule}) => { + accessschedule.show({ + schedule: schedule + }).then(function (updatedSchedule) { + const schedules = getSchedulesFromPage(); + + if (index == -1) { + index = schedules.length; + } + + schedules[index] = updatedSchedule; + renderAccessSchedule(schedules); + }); + }); + }; + + const getSchedulesFromPage = () => { + return Array.prototype.map.call(element?.current?.querySelectorAll('.liSchedule'), function (elem) { + return { + DayOfWeek: elem.getAttribute('data-day'), + StartHour: elem.getAttribute('data-start'), + EndHour: elem.getAttribute('data-end') + }; + }); + }; + + const getBlockedTagsFromPage = () => { + return Array.prototype.map.call(element?.current?.querySelectorAll('.blockedTag'), function (elem) { + return elem.getAttribute('data-tag'); + }); + }; + + const showBlockedTagPopup = () => { + import('../../components/prompt/prompt').then(({default: prompt}) => { + prompt({ + label: globalize.translate('LabelTag') + }).then(function (value) { + const tags = getBlockedTagsFromPage(); + + if (tags.indexOf(value) == -1) { + tags.push(value); + loadBlockedTags(tags); + } + }); + }); + }; + + const onSubmit = (e) => { + loading.show(); + const userId = appRouter.param('userId'); + window.ApiClient.getUser(userId).then(function (result) { + saveUser(result); + }); + e.preventDefault(); + e.stopPropagation(); + return false; + }; + + element?.current?.querySelector('.btnAddSchedule').addEventListener('click', function () { + showSchedulePopup({}, -1); + }); + + element?.current?.querySelector('.btnAddBlockedTag').addEventListener('click', function () { + showBlockedTagPopup(); + }); + + element?.current?.querySelector('.userParentalControlForm').addEventListener('submit', onSubmit); + }, [loadBlockedTags, loadData, renderAccessSchedule]); + + return ( +
+
+
+
+

+ {userName} +

+ +
+
+ +
+
+ +
+ {globalize.translate('MaxParentalRatingHelp')} +
+
+
+
+

+ {globalize.translate('HeaderBlockItemsWithNoRating')} +

+
+ {unratedItems.map(Item => { + return ; + })} +
+
+
+
+
+
+

+ {globalize.translate('LabelBlockContentWithTags')} +

+ +
+
+ {blockedTags.map((tag, index) => { + return ; + })} +
+
+
+
+

+ {globalize.translate('HeaderAccessSchedule')} +

+ +
+

{globalize.translate('HeaderAccessScheduleHelp')}

+
+ {accessSchedules.map((accessSchedule, index) => { + return ; + })} +
+
+
+ +
+
+
+
+ ); +}; + +export default UserParentalControl; diff --git a/src/controllers/dashboard/users/userparentalcontrol.html b/src/controllers/dashboard/users/userparentalcontrol.html index 884bacc3b6..8a93c3f931 100644 --- a/src/controllers/dashboard/users/userparentalcontrol.html +++ b/src/controllers/dashboard/users/userparentalcontrol.html @@ -1,60 +1,3 @@
-
-
-
-
-

- ${Help} -
-
- - -
-
- -
${MaxParentalRatingHelp}
-
- -
-
-
- -
- -
-
-

${LabelBlockContentWithTags}

- -
-
-
- -
-
-

${HeaderAccessSchedule}

- -
- -

${HeaderAccessScheduleHelp}

-
-
- -
- -
-
-
-
diff --git a/src/controllers/dashboard/users/userparentalcontrol.js b/src/controllers/dashboard/users/userparentalcontrol.js deleted file mode 100644 index 86af9a2377..0000000000 --- a/src/controllers/dashboard/users/userparentalcontrol.js +++ /dev/null @@ -1,274 +0,0 @@ -import 'jquery'; -import datetime from '../../../scripts/datetime'; -import loading from '../../../components/loading/loading'; -import libraryMenu from '../../../scripts/libraryMenu'; -import globalize from '../../../scripts/globalize'; -import '../../../components/listview/listview.scss'; -import '../../../elements/emby-button/paper-icon-button-light'; -import toast from '../../../components/toast/toast'; - -/* eslint-disable indent */ - - function populateRatings(allParentalRatings, page) { - let html = ''; - html += ""; - let rating; - const ratings = []; - - for (let i = 0, length = allParentalRatings.length; i < length; i++) { - if (rating = allParentalRatings[i], ratings.length) { - const lastRating = ratings[ratings.length - 1]; - - if (lastRating.Value === rating.Value) { - lastRating.Name += '/' + rating.Name; - continue; - } - } - - ratings.push({ - Name: rating.Name, - Value: rating.Value - }); - } - - for (let i = 0, length = ratings.length; i < length; i++) { - rating = ratings[i]; - html += "'; - } - - $('#selectMaxParentalRating', page).html(html); - } - - function loadUnratedItems(page, user) { - const items = [{ - name: globalize.translate('Books'), - value: 'Book' - }, { - name: globalize.translate('Channels'), - value: 'ChannelContent' - }, { - name: globalize.translate('LiveTV'), - value: 'LiveTvChannel' - }, { - name: globalize.translate('Movies'), - value: 'Movie' - }, { - name: globalize.translate('Music'), - value: 'Music' - }, { - name: globalize.translate('Trailers'), - value: 'Trailer' - }, { - name: globalize.translate('Shows'), - value: 'Series' - }]; - let html = ''; - html += '

' + globalize.translate('HeaderBlockItemsWithNoRating') + '

'; - html += '
'; - - for (let i = 0, length = items.length; i < length; i++) { - const item = items[i]; - const checkedAttribute = user.Policy.BlockUnratedItems.indexOf(item.value) != -1 ? ' checked="checked"' : ''; - html += ''; - } - - html += '
'; - $('.blockUnratedItems', page).html(html).trigger('create'); - } - - function loadUser(page, user, allParentalRatings) { - page.querySelector('.username').innerHTML = user.Name; - libraryMenu.setTitle(user.Name); - loadUnratedItems(page, user); - loadBlockedTags(page, user.Policy.BlockedTags); - populateRatings(allParentalRatings, page); - let ratingValue = ''; - - if (user.Policy.MaxParentalRating) { - for (let i = 0, length = allParentalRatings.length; i < length; i++) { - const rating = allParentalRatings[i]; - - if (user.Policy.MaxParentalRating >= rating.Value) { - ratingValue = rating.Value; - } - } - } - - $('#selectMaxParentalRating', page).val(ratingValue); - - if (user.Policy.IsAdministrator) { - $('.accessScheduleSection', page).hide(); - } else { - $('.accessScheduleSection', page).show(); - } - - renderAccessSchedule(page, user.Policy.AccessSchedules || []); - loading.hide(); - } - - function loadBlockedTags(page, tags) { - let html = tags.map(function (h) { - let li = '
'; - li += '
'; - li += '

'; - li += h; - li += '

'; - li += '
'; - li += ''; - return li += '
'; - }).join(''); - - if (html) { - html = '
' + html + '
'; - } - - const elem = $('.blockedTags', page).html(html).trigger('create'); - $('.btnDeleteTag', elem).on('click', function () { - const tag = this.getAttribute('data-tag'); - const newTags = tags.filter(function (t) { - return t != tag; - }); - loadBlockedTags(page, newTags); - }); - } - - function deleteAccessSchedule(page, schedules, index) { - schedules.splice(index, 1); - renderAccessSchedule(page, schedules); - } - - function renderAccessSchedule(page, schedules) { - let html = ''; - let index = 0; - html += schedules.map(function (a) { - let itemHtml = ''; - itemHtml += '
'; - itemHtml += '
'; - itemHtml += '

'; - itemHtml += globalize.translate('Option' + a.DayOfWeek); - itemHtml += '

'; - itemHtml += '
' + getDisplayTime(a.StartHour) + ' - ' + getDisplayTime(a.EndHour) + '
'; - itemHtml += '
'; - itemHtml += ''; - itemHtml += '
'; - index++; - return itemHtml; - }).join(''); - const accessScheduleList = page.querySelector('.accessScheduleList'); - accessScheduleList.innerHTML = html; - $('.btnDelete', accessScheduleList).on('click', function () { - deleteAccessSchedule(page, schedules, parseInt(this.getAttribute('data-index'))); - }); - } - - function onSaveComplete() { - loading.hide(); - toast(globalize.translate('SettingsSaved')); - } - - function saveUser(user, page) { - user.Policy.MaxParentalRating = $('#selectMaxParentalRating', page).val() || null; - user.Policy.BlockUnratedItems = $('.chkUnratedItem', page).get().filter(function (i) { - return i.checked; - }).map(function (i) { - return i.getAttribute('data-itemtype'); - }); - user.Policy.AccessSchedules = getSchedulesFromPage(page); - user.Policy.BlockedTags = getBlockedTagsFromPage(page); - ApiClient.updateUserPolicy(user.Id, user.Policy).then(function () { - onSaveComplete(); - }); - } - - function getDisplayTime(hours) { - let minutes = 0; - const pct = hours % 1; - - if (pct) { - minutes = parseInt(60 * pct); - } - - return datetime.getDisplayTime(new Date(2000, 1, 1, hours, minutes, 0, 0)); - } - - function showSchedulePopup(page, schedule, index) { - schedule = schedule || {}; - import('../../../components/accessSchedule/accessSchedule').then(({default: accessschedule}) => { - accessschedule.show({ - schedule: schedule - }).then(function (updatedSchedule) { - const schedules = getSchedulesFromPage(page); - - if (index == -1) { - index = schedules.length; - } - - schedules[index] = updatedSchedule; - renderAccessSchedule(page, schedules); - }); - }); - } - - function getSchedulesFromPage(page) { - return $('.liSchedule', page).map(function () { - return { - DayOfWeek: this.getAttribute('data-day'), - StartHour: this.getAttribute('data-start'), - EndHour: this.getAttribute('data-end') - }; - }).get(); - } - - function getBlockedTagsFromPage(page) { - return $('.blockedTag', page).map(function () { - return this.getAttribute('data-tag'); - }).get(); - } - - function showBlockedTagPopup(page) { - import('../../../components/prompt/prompt').then(({default: prompt}) => { - prompt({ - label: globalize.translate('LabelTag') - }).then(function (value) { - const tags = getBlockedTagsFromPage(page); - - if (tags.indexOf(value) == -1) { - tags.push(value); - loadBlockedTags(page, tags); - } - }); - }); - } - - window.UserParentalControlPage = { - onSubmit: function () { - const page = $(this).parents('.page'); - loading.show(); - const userId = getParameterByName('userId'); - ApiClient.getUser(userId).then(function (result) { - saveUser(result, page); - }); - return false; - } - }; - $(document).on('pageinit', '#userParentalControlPage', function () { - const page = this; - $('.btnAddSchedule', page).on('click', function () { - showSchedulePopup(page, {}, -1); - }); - $('.btnAddBlockedTag', page).on('click', function () { - showBlockedTagPopup(page); - }); - $('.userParentalControlForm').off('submit', UserParentalControlPage.onSubmit).on('submit', UserParentalControlPage.onSubmit); - }).on('pageshow', '#userParentalControlPage', function () { - const page = this; - loading.show(); - const userId = getParameterByName('userId'); - const promise1 = ApiClient.getUser(userId); - const promise2 = ApiClient.getParentalRatings(); - Promise.all([promise1, promise2]).then(function (responses) { - loadUser(page, responses[0], responses[1]); - }); - }); - -/* eslint-enable indent */ diff --git a/src/scripts/routes.js b/src/scripts/routes.js index cab1287d20..538c0c03ef 100644 --- a/src/scripts/routes.js +++ b/src/scripts/routes.js @@ -464,7 +464,7 @@ import { appRouter } from '../components/appRouter'; path: 'dashboard/users/userparentalcontrol.html', autoFocus: false, roles: 'admin', - controller: 'dashboard/users/userparentalcontrol' + pageComponent: 'UserParentalControl' }); defineRoute({