diff --git a/src/settings/RealTimeUpdates.tsx b/src/settings/RealTimeUpdates.tsx
index dc89f1d5..d89f6526 100644
--- a/src/settings/RealTimeUpdates.tsx
+++ b/src/settings/RealTimeUpdates.tsx
@@ -1,20 +1,49 @@
import React from 'react';
-import { Card, CardBody, CardHeader } from 'reactstrap';
+import { Card, CardBody, CardHeader, FormGroup, Input } from 'reactstrap';
+import classNames from 'classnames';
import ToggleSwitch from '../utils/ToggleSwitch';
import { Settings } from './reducers/settings';
interface RealTimeUpdatesProps {
settings: Settings;
- setRealTimeUpdates: (enabled: boolean) => void;
+ toggleRealTimeUpdates: (enabled: boolean) => void;
+ setRealTimeUpdatesInterval: (interval: number) => void;
}
-const RealTimeUpdates = ({ settings: { realTimeUpdates }, setRealTimeUpdates }: RealTimeUpdatesProps) => (
+const intervalValue = (interval?: number) => !interval ? '' : `${interval}`;
+
+const RealTimeUpdates = (
+ { settings: { realTimeUpdates }, toggleRealTimeUpdates, setRealTimeUpdatesInterval }: RealTimeUpdatesProps,
+) => (
Real-time updates
-
- Enable or disable real-time updates, when using Shlink v2.2.0 or newer.
-
+
+
+ Enable or disable real-time updates, when using Shlink v2.2.0 or newer.
+
+
+
+
+ setRealTimeUpdatesInterval(Number(e.target.value))}
+ />
+ {realTimeUpdates.enabled && (
+
+ {realTimeUpdates.interval !== undefined && realTimeUpdates.interval > 0 &&
+ Updates will be reflected in the UI every {realTimeUpdates.interval} minutes.
+ }
+ {!realTimeUpdates.interval && 'Updates will be reflected in the UI as soon as they happen.'}
+
+ )}
+
);
diff --git a/src/settings/reducers/settings.ts b/src/settings/reducers/settings.ts
index a87455c8..8a21d146 100644
--- a/src/settings/reducers/settings.ts
+++ b/src/settings/reducers/settings.ts
@@ -1,10 +1,13 @@
import { Action } from 'redux';
+import { mergeDeepRight } from 'ramda';
import { buildReducer } from '../../utils/helpers/redux';
+import { RecursivePartial } from '../../utils/utils';
export const SET_REAL_TIME_UPDATES = 'shlink/realTimeUpdates/SET_REAL_TIME_UPDATES';
interface RealTimeUpdates {
enabled: boolean;
+ interval?: number;
}
export interface Settings {
@@ -19,11 +22,18 @@ const initialState: Settings = {
type SettingsAction = Action & Settings;
+type PartialSettingsAction = Action & RecursivePartial;
+
export default buildReducer({
- [SET_REAL_TIME_UPDATES]: (state, { realTimeUpdates }) => ({ ...state, realTimeUpdates }),
+ [SET_REAL_TIME_UPDATES]: (state, { realTimeUpdates }) => mergeDeepRight(state, { realTimeUpdates }),
}, initialState);
-export const setRealTimeUpdates = (enabled: boolean): SettingsAction => ({
+export const toggleRealTimeUpdates = (enabled: boolean): PartialSettingsAction => ({
type: SET_REAL_TIME_UPDATES,
realTimeUpdates: { enabled },
});
+
+export const setRealTimeUpdatesInterval = (interval: number): PartialSettingsAction => ({
+ type: SET_REAL_TIME_UPDATES,
+ realTimeUpdates: { interval },
+});
diff --git a/src/settings/services/provideServices.ts b/src/settings/services/provideServices.ts
index 6db2052d..78d86e47 100644
--- a/src/settings/services/provideServices.ts
+++ b/src/settings/services/provideServices.ts
@@ -1,7 +1,7 @@
import Bottle from 'bottlejs';
import RealTimeUpdates from '../RealTimeUpdates';
import Settings from '../Settings';
-import { setRealTimeUpdates } from '../reducers/settings';
+import { setRealTimeUpdatesInterval, toggleRealTimeUpdates } from '../reducers/settings';
import { ConnectDecorator } from '../../container/types';
import { withoutSelectedServer } from '../../servers/helpers/withoutSelectedServer';
@@ -13,10 +13,11 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
// Services
bottle.serviceFactory('RealTimeUpdates', () => RealTimeUpdates);
- bottle.decorator('RealTimeUpdates', connect([ 'settings' ], [ 'setRealTimeUpdates' ]));
+ bottle.decorator('RealTimeUpdates', connect([ 'settings' ], [ 'setRealTimeUpdatesInterval' ]));
// Actions
- bottle.serviceFactory('setRealTimeUpdates', () => setRealTimeUpdates);
+ bottle.serviceFactory('toggleRealTimeUpdates', () => toggleRealTimeUpdates);
+ bottle.serviceFactory('setRealTimeUpdatesInterval', () => setRealTimeUpdatesInterval);
};
export default provideServices;
diff --git a/src/utils/utils.ts b/src/utils/utils.ts
index 25c22222..850fd4b6 100644
--- a/src/utils/utils.ts
+++ b/src/utils/utils.ts
@@ -39,3 +39,7 @@ export type Nullable = {
type Optional = T | null | undefined;
export type OptionalString = Optional;
+
+export type RecursivePartial = {
+ [P in keyof T]?: RecursivePartial;
+};
diff --git a/test/settings/reducers/settings.test.ts b/test/settings/reducers/settings.test.ts
index c290f4f3..9018b311 100644
--- a/test/settings/reducers/settings.test.ts
+++ b/test/settings/reducers/settings.test.ts
@@ -1,4 +1,4 @@
-import reducer, { SET_REAL_TIME_UPDATES, setRealTimeUpdates } from '../../../src/settings/reducers/settings';
+import reducer, { SET_REAL_TIME_UPDATES, toggleRealTimeUpdates, setRealTimeUpdatesInterval } from '../../../src/settings/reducers/settings';
describe('settingsReducer', () => {
const realTimeUpdates = { enabled: true };
@@ -9,11 +9,19 @@ describe('settingsReducer', () => {
});
});
- describe('setRealTimeUpdates', () => {
+ describe('toggleRealTimeUpdates', () => {
it.each([[ true ], [ false ]])('updates settings with provided value and then loads updates again', (enabled) => {
- const result = setRealTimeUpdates(enabled);
+ const result = toggleRealTimeUpdates(enabled);
expect(result).toEqual({ type: SET_REAL_TIME_UPDATES, realTimeUpdates: { enabled } });
});
});
+
+ describe('setRealTimeUpdatesInterval', () => {
+ it.each([[ 0 ], [ 1 ], [ 2 ], [ 10 ]])('updates settings with provided value and then loads updates again', (interval) => {
+ const result = setRealTimeUpdatesInterval(interval);
+
+ expect(result).toEqual({ type: SET_REAL_TIME_UPDATES, realTimeUpdates: { interval } });
+ });
+ });
});