2022-09-01 11:00:49 +00:00
|
|
|
/* eslint-disable lines-around-comment */
|
|
|
|
import { getURLWithoutParamsNormalized } from '../base/connection/utils';
|
|
|
|
import PersistenceRegistry from '../base/redux/PersistenceRegistry';
|
|
|
|
import ReducerRegistry from '../base/redux/ReducerRegistry';
|
2018-01-29 22:20:38 +00:00
|
|
|
|
2018-01-17 11:19:10 +00:00
|
|
|
import {
|
2018-05-14 17:37:48 +00:00
|
|
|
_STORE_CURRENT_CONFERENCE,
|
2018-09-25 12:48:03 +00:00
|
|
|
_UPDATE_CONFERENCE_DURATION,
|
|
|
|
DELETE_RECENT_LIST_ENTRY
|
2018-01-17 11:19:10 +00:00
|
|
|
} from './actionTypes';
|
2022-09-01 11:00:49 +00:00
|
|
|
// @ts-ignore
|
2018-08-01 20:37:15 +00:00
|
|
|
import { isRecentListEnabled } from './functions';
|
2018-02-02 18:13:33 +00:00
|
|
|
|
2022-09-01 11:00:49 +00:00
|
|
|
interface IRecent {
|
|
|
|
conference: string;
|
|
|
|
date: number;
|
|
|
|
duration: number;
|
|
|
|
}
|
|
|
|
|
|
|
|
export type IRecentListState = IRecent[];
|
|
|
|
|
2018-02-27 20:21:28 +00:00
|
|
|
/**
|
|
|
|
* The default/initial redux state of the feature {@code recent-list}.
|
|
|
|
*
|
2022-09-01 11:00:49 +00:00
|
|
|
* @type {IRecentListState}
|
2018-02-27 20:21:28 +00:00
|
|
|
*/
|
2022-09-01 11:00:49 +00:00
|
|
|
const DEFAULT_STATE: IRecentListState = [];
|
2018-02-27 20:21:28 +00:00
|
|
|
|
2018-01-17 11:19:10 +00:00
|
|
|
/**
|
2018-02-02 18:13:33 +00:00
|
|
|
* The max size of the list.
|
|
|
|
*
|
|
|
|
* @type {number}
|
|
|
|
*/
|
|
|
|
export const MAX_LIST_SIZE = 30;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The redux subtree of this feature.
|
2018-01-17 11:19:10 +00:00
|
|
|
*/
|
|
|
|
const STORE_NAME = 'features/recent-list';
|
|
|
|
|
|
|
|
/**
|
2018-02-27 20:21:28 +00:00
|
|
|
* Sets up the persistence of the feature {@code recent-list}.
|
2018-01-17 11:19:10 +00:00
|
|
|
*/
|
2018-02-06 09:43:49 +00:00
|
|
|
PersistenceRegistry.register(STORE_NAME);
|
2018-01-17 11:19:10 +00:00
|
|
|
|
|
|
|
/**
|
2018-02-27 20:21:28 +00:00
|
|
|
* Reduces redux actions for the purposes of the feature {@code recent-list}.
|
2018-02-02 18:13:33 +00:00
|
|
|
*/
|
2022-09-05 09:05:07 +00:00
|
|
|
ReducerRegistry.register<IRecentListState>(STORE_NAME, (state = DEFAULT_STATE, action): IRecentListState => {
|
2022-07-12 14:59:46 +00:00
|
|
|
if (isRecentListEnabled()) {
|
|
|
|
switch (action.type) {
|
|
|
|
case DELETE_RECENT_LIST_ENTRY:
|
|
|
|
return _deleteRecentListEntry(state, action.entryId);
|
|
|
|
case _STORE_CURRENT_CONFERENCE:
|
|
|
|
return _storeCurrentConference(state, action);
|
|
|
|
case _UPDATE_CONFERENCE_DURATION:
|
|
|
|
return _updateConferenceDuration(state, action);
|
|
|
|
default:
|
|
|
|
return state;
|
2018-02-02 18:13:33 +00:00
|
|
|
}
|
2022-07-12 14:59:46 +00:00
|
|
|
}
|
2018-08-01 20:37:15 +00:00
|
|
|
|
2022-07-12 14:59:46 +00:00
|
|
|
return state;
|
|
|
|
});
|
2018-02-02 18:13:33 +00:00
|
|
|
|
2018-09-25 12:48:03 +00:00
|
|
|
/**
|
|
|
|
* Deletes a recent list entry based on the url and date of the item.
|
|
|
|
*
|
2022-09-01 11:00:49 +00:00
|
|
|
* @param {IRecentListState} state - The Redux state.
|
2018-09-25 12:48:03 +00:00
|
|
|
* @param {Object} entryId - The ID object of the entry.
|
2022-09-01 11:00:49 +00:00
|
|
|
* @returns {IRecentListState}
|
2018-09-25 12:48:03 +00:00
|
|
|
*/
|
|
|
|
function _deleteRecentListEntry(
|
2022-09-01 11:00:49 +00:00
|
|
|
state: Array<IRecent>, entryId: { date: number; url: string; }): Array<IRecent> {
|
2018-09-25 12:48:03 +00:00
|
|
|
return state.filter(entry =>
|
|
|
|
entry.conference !== entryId.url || entry.date !== entryId.date);
|
|
|
|
}
|
|
|
|
|
2018-01-17 11:19:10 +00:00
|
|
|
/**
|
2018-02-27 20:21:28 +00:00
|
|
|
* Adds a new list entry to the redux store.
|
|
|
|
*
|
2022-09-01 11:00:49 +00:00
|
|
|
* @param {IRecentListState} state - The redux state of the feature {@code recent-list}.
|
2018-02-27 20:21:28 +00:00
|
|
|
* @param {Object} action - The redux action.
|
|
|
|
* @returns {Object}
|
|
|
|
*/
|
2022-09-08 09:52:36 +00:00
|
|
|
function _storeCurrentConference(state: IRecentListState, { locationURL }: { locationURL: { href: string; }; }) {
|
2018-01-17 11:19:10 +00:00
|
|
|
const conference = locationURL.href;
|
|
|
|
|
|
|
|
// If the current conference is already in the list, we remove it to re-add
|
|
|
|
// it to the top.
|
2018-02-27 20:21:28 +00:00
|
|
|
const nextState
|
|
|
|
= state.filter(e => !_urlStringEquals(e.conference, conference));
|
2018-01-17 11:19:10 +00:00
|
|
|
|
2018-02-02 18:13:33 +00:00
|
|
|
// The list is a reverse-sorted (i.e. the newer elements are at the end).
|
2018-02-27 20:21:28 +00:00
|
|
|
nextState.push({
|
2018-01-17 11:19:10 +00:00
|
|
|
conference,
|
2018-02-27 20:21:28 +00:00
|
|
|
date: Date.now(),
|
|
|
|
duration: 0 // We don't have the duration yet!
|
2018-01-17 11:19:10 +00:00
|
|
|
});
|
|
|
|
|
2018-02-02 18:13:33 +00:00
|
|
|
// Ensure the list doesn't exceed a/the maximum size.
|
2018-02-27 20:21:28 +00:00
|
|
|
nextState.splice(0, nextState.length - MAX_LIST_SIZE);
|
2018-01-17 11:19:10 +00:00
|
|
|
|
2018-02-27 20:21:28 +00:00
|
|
|
return nextState;
|
2018-01-17 11:19:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Updates the conference length when left.
|
|
|
|
*
|
2022-09-01 11:00:49 +00:00
|
|
|
* @param {IRecentListState} state - The redux state of the feature {@code recent-list}.
|
2018-01-17 11:19:10 +00:00
|
|
|
* @param {Object} action - The redux action.
|
2018-02-27 20:21:28 +00:00
|
|
|
* @returns {Object} The next redux state of the feature {@code recent-list}.
|
2018-01-17 11:19:10 +00:00
|
|
|
*/
|
2022-09-08 09:52:36 +00:00
|
|
|
function _updateConferenceDuration(state: IRecentListState, { locationURL }: { locationURL: { href: string; }; }) {
|
|
|
|
if (locationURL?.href && state.length) {
|
2018-02-27 20:21:28 +00:00
|
|
|
const mostRecentIndex = state.length - 1;
|
|
|
|
const mostRecent = state[mostRecentIndex];
|
|
|
|
|
|
|
|
if (_urlStringEquals(mostRecent.conference, locationURL.href)) {
|
|
|
|
// The last conference start was stored so we need to update the
|
|
|
|
// length.
|
|
|
|
const nextMostRecent = {
|
|
|
|
...mostRecent,
|
|
|
|
duration: Date.now() - mostRecent.date
|
|
|
|
};
|
2018-01-17 11:19:10 +00:00
|
|
|
|
2018-02-27 20:21:28 +00:00
|
|
|
// Shallow copy to avoid in-place modification.
|
|
|
|
const nextState = state.slice();
|
2018-01-17 11:19:10 +00:00
|
|
|
|
2018-02-27 20:21:28 +00:00
|
|
|
nextState[mostRecentIndex] = nextMostRecent;
|
2018-01-17 11:19:10 +00:00
|
|
|
|
2018-02-27 20:21:28 +00:00
|
|
|
return nextState;
|
2018-01-17 11:19:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return state;
|
|
|
|
}
|
2018-02-27 20:21:28 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Determines whether two specific URL {@code strings} are equal in the sense
|
|
|
|
* that they identify one and the same conference resource (irrespective of
|
|
|
|
* time) for the purposes of the feature {@code recent-list}.
|
|
|
|
*
|
|
|
|
* @param {string} a - The URL {@code string} to test for equality to {@code b}.
|
|
|
|
* @param {string} b - The URL {@code string} to test for equality to {@code a}.
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
|
|
|
function _urlStringEquals(a: string, b: string) {
|
2018-04-04 19:54:42 +00:00
|
|
|
const aHref = getURLWithoutParamsNormalized(new URL(a));
|
|
|
|
const bHref = getURLWithoutParamsNormalized(new URL(b));
|
|
|
|
|
|
|
|
return aHref === bHref;
|
2018-02-27 20:21:28 +00:00
|
|
|
}
|