@@ -2,10 +2,11 @@ import { useState, useEffect } from "react";
22import { Tabs , Tab , Alert } from "react-bootstrap" ;
33import Grid from "./grid" ;
44import { useTranslation } from "react-i18next" ;
5- import { useDispatch } from "react-redux" ;
65import idFromUrl from "../../util/helpers/id-from-url" ;
76import PlaylistDragAndDrop from "../../playlist-drag-and-drop/playlist-drag-and-drop" ;
87import { enhancedApi } from "../../../../shared/redux/enhanced-api.ts" ;
8+ import useFetchDataHook from "../../util/fetch-data-hook.js" ;
9+ import mapToIds from "../../util/helpers/map-to-ids.js" ;
910import "./grid.scss" ;
1011
1112/**
@@ -27,11 +28,18 @@ function GridGenerationAndSelect({
2728 regions = [ ] ,
2829} ) {
2930 const { t } = useTranslation ( "common" ) ;
30- const dispatch = useDispatch ( ) ;
3131 const [ selectedRegion , setSelectedRegion ] = useState (
3232 regions . length > 0 ? regions [ 0 ] [ "@id" ] : "" ,
3333 ) ;
3434 const [ selectedPlaylists , setSelectedPlaylists ] = useState ( [ ] ) ;
35+ const { data : playlistsAndRegions } = useFetchDataHook (
36+ enhancedApi . endpoints . getV2ScreensByIdRegionsAndRegionIdPlaylists . initiate ,
37+ mapToIds ( regions ) , // returns and array with ids to fetch for all ids
38+ {
39+ id : screenId , // screen id is the id
40+ } ,
41+ "regionId" , // The key for the list of ids
42+ ) ;
3543
3644 /**
3745 * @param {object } props The props
@@ -40,93 +48,72 @@ function GridGenerationAndSelect({
4048 * @returns {Array } Mapped data
4149 */
4250 function mapData ( { value : inputPlaylists , id } ) {
43- // Map to add region id to incoming data.
44- const localTarget = inputPlaylists . map ( ( playlist ) => {
45- return {
46- region : idFromUrl ( id ) ,
47- ...playlist ,
48- } ;
49- } ) ;
50- // A copy, to be able to remove items.
51- let selectedPlaylistsCopy = [ ...selectedPlaylists ] ;
52-
53- // The following is used to determine if something has been removed from a list.
54- const regionPlaylists = selectedPlaylists
55- . filter ( ( { region } ) => region === id )
56- . map ( ( { region } ) => region ) ;
57-
58- const selectedWithoutRegion = [ ] ;
59-
60- // Checks if an element has been removed from the list
61- if ( inputPlaylists . length < regionPlaylists . length ) {
62- selectedPlaylists . forEach ( ( playlist ) => {
63- if ( ! regionPlaylists . includes ( playlist . region ) ) {
64- selectedWithoutRegion . push ( playlist ) ;
65- }
66- } ) ;
67- // If a playlist is removed from a list, all the playlists in that region will be removed.
68- selectedPlaylistsCopy = selectedWithoutRegion ;
51+ // Region id form id url
52+ const region = idFromUrl ( id ) ;
53+
54+ // Add the region id to each inputted playlist
55+ const playlistsWithRegion = inputPlaylists . map ( ( playlist ) => ( {
56+ region,
57+ ...playlist ,
58+ } ) ) ;
59+
60+ // Get the playlists that belong the same region from the selected playlists
61+ const existingRegionPlaylists = selectedPlaylists . filter (
62+ ( playlist ) => playlist . region === region ,
63+ ) ;
64+
65+ // Check if any playlists from the existing region playlists are missing from
66+ // The inputted playlists if so, they are removed from the list
67+ const removedPlaylists = existingRegionPlaylists . some (
68+ ( { "@id" : existingId } ) =>
69+ ! inputPlaylists . find (
70+ ( { "@id" : incomingId } ) => incomingId === existingId ,
71+ ) ,
72+ ) ;
73+
74+ // Start with the existing selected playlists
75+ let updatedRegionPlaylists = [ ...selectedPlaylists ] ;
76+
77+ // If any playlists were removed, filter out all playlists for this region
78+ if ( removedPlaylists ) {
79+ updatedRegionPlaylists = selectedPlaylists . filter (
80+ ( playlist ) => playlist . region !== region ,
81+ ) ;
6982 }
7083
71- // Removes duplicates.
72- const localSelectedPlaylists = [
73- ...localTarget ,
74- ...selectedPlaylistsCopy ,
84+ // Merge the updated region playlists with the input playlists,
85+ // and remove any duplicate region and id combinations
86+ const mappedData = [
87+ ...playlistsWithRegion ,
88+ ...updatedRegionPlaylists ,
7589 ] . filter (
7690 ( playlist , index , self ) =>
7791 index ===
7892 self . findIndex (
79- ( secondPlaylist ) =>
80- secondPlaylist [ "@id" ] === playlist [ "@id" ] &&
81- secondPlaylist . region === playlist . region ,
93+ ( { region, "@id" : playlistId } ) =>
94+ playlistId === playlist [ "@id" ] && region === playlist . region ,
8295 ) ,
8396 ) ;
8497
85- return localSelectedPlaylists ;
98+ return mappedData ;
8699 }
87100
101+ // On received data, map to fit the components
102+ // We need region id to figure out which dropdown they should be placed in
103+ // and weight (order) for sorting.
88104 useEffect ( ( ) => {
89- if ( regions . length > 0 ) {
90- const promises = [ ] ;
91- regions . forEach ( ( { "@id" : id } ) => {
92- promises . push (
93- dispatch (
94- enhancedApi . endpoints . getV2ScreensByIdRegionsAndRegionIdPlaylists . initiate (
95- {
96- id : screenId ,
97- regionId : idFromUrl ( id ) ,
98- page : 1 ,
99- itemsPerPage : 50 ,
100- } ,
101- ) ,
102- ) ,
103- ) ;
104- } ) ;
105-
106- Promise . allSettled ( promises ) . then ( ( results ) => {
107- let playlists = [ ] ;
108- results . forEach (
109- ( {
110- value : {
111- originalArgs : { regionId } ,
112- data : { "hydra:member" : promisedPlaylists = null } = { } ,
113- } ,
114- } ) => {
115- playlists = [
116- ...playlists ,
117- ...promisedPlaylists . map ( ( { playlist, weight } ) => ( {
118- ...playlist ,
119- weight,
120- region : regionId ,
121- } ) ) ,
122- ] ;
123- } ,
124- ) ;
125- playlists = playlists . sort ( ( a , b ) => a . weight - b . weight ) ;
126- setSelectedPlaylists ( playlists ) ;
127- } ) ;
105+ if ( playlistsAndRegions && playlistsAndRegions . length > 0 ) {
106+ const playlists = playlistsAndRegions
107+ . map ( ( { originalArgs : { regionId } , playlist, weight } ) => ( {
108+ ...playlist ,
109+ weight,
110+ region : regionId ,
111+ } ) )
112+ . sort ( ( a , b ) => a . weight - b . weight ) ;
113+
114+ setSelectedPlaylists ( playlists ) ;
128115 }
129- } , [ regions ] ) ;
116+ } , [ playlistsAndRegions ] ) ;
130117
131118 useEffect ( ( ) => {
132119 handleInput ( { target : { value : selectedPlaylists , id : "playlists" } } ) ;
@@ -156,6 +143,7 @@ function GridGenerationAndSelect({
156143 ) ;
157144 } ;
158145
146+ // If there are no regions, the components should not spend time rendering.
159147 if ( regions ?. length === 0 ) return null ;
160148
161149 return (
@@ -171,37 +159,35 @@ function GridGenerationAndSelect({
171159 </ div >
172160 </ div >
173161 < div className = "col-md-12" >
174- < >
175- < h3 className = "h5" > { t ( "screen-form.screen-region-playlists" ) } </ h3 >
176- < Tabs
177- defaultActiveKey = { regions [ 0 ] [ "@id" ] }
178- id = "tabs"
179- onSelect = { setSelectedRegion }
180- className = "mb-3"
181- >
182- { regions . map ( ( { title, "@id" : id , type } ) => (
183- < Tab eventKey = { id } key = { id } title = { title } >
184- < PlaylistDragAndDrop
185- id = "playlist_drag_and_drop"
186- handleChange = { handleChange }
187- removeFromList = { removeFromList }
188- name = { id }
189- regionIdForInitializeCallback = { id }
190- screenId = { screenId }
191- regionId = { idFromUrl ( id ) }
192- selectedPlaylists = { selectedPlaylists . filter (
193- ( { region } ) => region === idFromUrl ( id ) ,
194- ) }
195- />
196- { type === "touch-buttons" && (
197- < Alert key = "screen-form-touch-buttons" variant = "info" >
198- { t ( "screen-form.touch-region-helptext" ) }
199- </ Alert >
162+ < h3 className = "h5" > { t ( "screen-form.screen-region-playlists" ) } </ h3 >
163+ < Tabs
164+ defaultActiveKey = { regions [ 0 ] [ "@id" ] }
165+ id = "tabs"
166+ onSelect = { setSelectedRegion }
167+ className = "mb-3"
168+ >
169+ { regions . map ( ( { title, "@id" : id , type } ) => (
170+ < Tab eventKey = { id } key = { id } title = { title } >
171+ < PlaylistDragAndDrop
172+ id = "playlist_drag_and_drop"
173+ handleChange = { handleChange }
174+ removeFromList = { removeFromList }
175+ name = { id }
176+ regionIdForInitializeCallback = { id }
177+ screenId = { screenId }
178+ regionId = { idFromUrl ( id ) }
179+ selectedPlaylists = { selectedPlaylists . filter (
180+ ( { region } ) => region === idFromUrl ( id ) ,
200181 ) }
201- </ Tab >
202- ) ) }
203- </ Tabs >
204- </ >
182+ />
183+ { type === "touch-buttons" && (
184+ < Alert key = "screen-form-touch-buttons" variant = "info" >
185+ { t ( "screen-form.touch-region-helptext" ) }
186+ </ Alert >
187+ ) }
188+ </ Tab >
189+ ) ) }
190+ </ Tabs >
205191 </ div >
206192 </ >
207193 ) ;
0 commit comments