Added new visits settings

This commit is contained in:
Alejandro Celaya 2021-03-06 10:56:49 +01:00
parent ad46927750
commit d3f9650e82
8 changed files with 40 additions and 7 deletions

View file

@ -3,6 +3,7 @@ import { dissoc, mergeDeepRight } from 'ramda';
import { buildReducer } from '../../utils/helpers/redux';
import { RecursivePartial } from '../../utils/utils';
import { Theme } from '../../utils/theme';
import { DateInterval } from '../../utils/dates/types';
export const SET_SETTINGS = 'shlink/realTimeUpdates/SET_SETTINGS';
@ -24,10 +25,15 @@ export interface UiSettings {
theme: Theme;
}
export interface VisitsSettings {
defaultInterval: DateInterval;
}
export interface Settings {
realTimeUpdates: RealTimeUpdatesSettings;
shortUrlCreation?: ShortUrlCreationSettings;
ui?: UiSettings;
visits?: VisitsSettings;
}
const initialState: Settings = {
@ -40,6 +46,9 @@ const initialState: Settings = {
ui: {
theme: 'light',
},
visits: {
defaultInterval: 'last30Days',
},
};
type SettingsAction = Action & Settings;

View file

@ -2,6 +2,7 @@ import { RouteComponentProps } from 'react-router';
import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';
import { ShlinkVisitsParams } from '../api/types';
import { Topics } from '../mercure/helpers/Topics';
import { Settings } from '../settings/reducers/settings';
import VisitsStats from './VisitsStats';
import { OrphanVisitsHeader } from './OrphanVisitsHeader';
import { VisitsInfo } from './types';
@ -10,6 +11,7 @@ export interface OrphanVisitsProps extends RouteComponentProps {
getOrphanVisits: (params: ShlinkVisitsParams) => void;
orphanVisits: VisitsInfo;
cancelGetOrphanVisits: () => void;
settings: Settings;
}
export const OrphanVisits = boundToMercureHub(({
@ -18,12 +20,14 @@ export const OrphanVisits = boundToMercureHub(({
getOrphanVisits,
orphanVisits,
cancelGetOrphanVisits,
settings,
}: OrphanVisitsProps) => (
<VisitsStats
getVisits={getOrphanVisits}
cancelGetVisits={cancelGetOrphanVisits}
visitsInfo={orphanVisits}
baseUrl={url}
settings={settings}
>
<OrphanVisitsHeader orphanVisits={orphanVisits} goBack={goBack} />
</VisitsStats>

View file

@ -5,6 +5,7 @@ import { ShlinkVisitsParams } from '../api/types';
import { parseQuery } from '../utils/helpers/query';
import { Topics } from '../mercure/helpers/Topics';
import { ShortUrlDetail } from '../short-urls/reducers/shortUrlDetail';
import { Settings } from '../settings/reducers/settings';
import { ShortUrlVisits as ShortUrlVisitsState } from './reducers/shortUrlVisits';
import ShortUrlVisitsHeader from './ShortUrlVisitsHeader';
import VisitsStats from './VisitsStats';
@ -15,6 +16,7 @@ export interface ShortUrlVisitsProps extends RouteComponentProps<{ shortCode: st
getShortUrlDetail: Function;
shortUrlDetail: ShortUrlDetail;
cancelGetShortUrlVisits: () => void;
settings: Settings;
}
const ShortUrlVisits = boundToMercureHub(({
@ -26,6 +28,7 @@ const ShortUrlVisits = boundToMercureHub(({
getShortUrlVisits,
getShortUrlDetail,
cancelGetShortUrlVisits,
settings,
}: ShortUrlVisitsProps) => {
const { shortCode } = params;
const { domain } = parseQuery<{ domain?: string }>(search);
@ -42,6 +45,7 @@ const ShortUrlVisits = boundToMercureHub(({
visitsInfo={shortUrlVisits}
baseUrl={url}
domain={domain}
settings={settings}
>
<ShortUrlVisitsHeader shortUrlDetail={shortUrlDetail} shortUrlVisits={shortUrlVisits} goBack={goBack} />
</VisitsStats>

View file

@ -3,6 +3,7 @@ import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';
import ColorGenerator from '../utils/services/ColorGenerator';
import { ShlinkVisitsParams } from '../api/types';
import { Topics } from '../mercure/helpers/Topics';
import { Settings } from '../settings/reducers/settings';
import { TagVisits as TagVisitsState } from './reducers/tagVisits';
import TagVisitsHeader from './TagVisitsHeader';
import VisitsStats from './VisitsStats';
@ -11,6 +12,7 @@ export interface TagVisitsProps extends RouteComponentProps<{ tag: string }> {
getTagVisits: (tag: string, query: any) => void;
tagVisits: TagVisitsState;
cancelGetTagVisits: () => void;
settings: Settings;
}
const TagVisits = (colorGenerator: ColorGenerator) => boundToMercureHub(({
@ -19,12 +21,19 @@ const TagVisits = (colorGenerator: ColorGenerator) => boundToMercureHub(({
getTagVisits,
tagVisits,
cancelGetTagVisits,
settings,
}: TagVisitsProps) => {
const { tag } = params;
const loadVisits = (params: ShlinkVisitsParams) => getTagVisits(tag, params);
return (
<VisitsStats getVisits={loadVisits} cancelGetVisits={cancelGetTagVisits} visitsInfo={tagVisits} baseUrl={url}>
<VisitsStats
getVisits={loadVisits}
cancelGetVisits={cancelGetTagVisits}
visitsInfo={tagVisits}
baseUrl={url}
settings={settings}
>
<TagVisitsHeader tagVisits={tagVisits} goBack={goBack} colorGenerator={colorGenerator} />
</VisitsStats>
);

View file

@ -13,6 +13,7 @@ import { ShlinkVisitsParams } from '../api/types';
import { DateInterval, DateRange, intervalToDateRange } from '../utils/dates/types';
import { Result } from '../utils/Result';
import { ShlinkApiError } from '../api/ShlinkApiError';
import { Settings } from '../settings/reducers/settings';
import SortableBarGraph from './helpers/SortableBarGraph';
import GraphCard from './helpers/GraphCard';
import LineChartCard from './helpers/LineChartCard';
@ -25,6 +26,7 @@ import './VisitsStats.scss';
export interface VisitsStatsProps {
getVisits: (params: Partial<ShlinkVisitsParams>) => void;
visitsInfo: VisitsInfo;
settings: Settings;
cancelGetVisits: () => void;
baseUrl: string;
domain?: string;
@ -59,7 +61,6 @@ const highlightedVisitsToStats = (
return acc;
}, {});
let selectedBar: string | undefined;
const initialInterval: DateInterval = 'last30Days';
const VisitsNavLink: FC<VisitsNavLinkProps & { to: string }> = ({ subPath, title, icon, to }) => (
<NavLink
@ -74,7 +75,10 @@ const VisitsNavLink: FC<VisitsNavLinkProps & { to: string }> = ({ subPath, title
</NavLink>
);
const VisitsStats: FC<VisitsStatsProps> = ({ children, visitsInfo, getVisits, cancelGetVisits, baseUrl, domain }) => {
const VisitsStats: FC<VisitsStatsProps> = (
{ children, visitsInfo, getVisits, cancelGetVisits, baseUrl, domain, settings },
) => {
const initialInterval: DateInterval = settings.visits?.defaultInterval ?? 'last30Days';
const [ dateRange, setDateRange ] = useState<DateRange>(intervalToDateRange(initialInterval));
const [ highlightedVisits, setHighlightedVisits ] = useState<NormalizedVisit[]>([]);
const [ highlightedLabel, setHighlightedLabel ] = useState<string | undefined>();

View file

@ -18,19 +18,19 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
bottle.serviceFactory('ShortUrlVisits', () => ShortUrlVisits);
bottle.decorator('ShortUrlVisits', connect(
[ 'shortUrlVisits', 'shortUrlDetail', 'mercureInfo' ],
[ 'shortUrlVisits', 'shortUrlDetail', 'mercureInfo', 'settings' ],
[ 'getShortUrlVisits', 'getShortUrlDetail', 'cancelGetShortUrlVisits', 'createNewVisits', 'loadMercureInfo' ],
));
bottle.serviceFactory('TagVisits', TagVisits, 'ColorGenerator');
bottle.decorator('TagVisits', connect(
[ 'tagVisits', 'mercureInfo' ],
[ 'tagVisits', 'mercureInfo', 'settings' ],
[ 'getTagVisits', 'cancelGetTagVisits', 'createNewVisits', 'loadMercureInfo' ],
));
bottle.serviceFactory('OrphanVisits', () => OrphanVisits);
bottle.decorator('OrphanVisits', connect(
[ 'orphanVisits', 'mercureInfo' ],
[ 'orphanVisits', 'mercureInfo', 'settings' ],
[ 'getOrphanVisits', 'cancelGetOrphanVisits', 'createNewVisits', 'loadMercureInfo' ],
));

View file

@ -10,7 +10,8 @@ describe('settingsReducer', () => {
const realTimeUpdates = { enabled: true };
const shortUrlCreation = { validateUrls: false };
const ui = { theme: 'light' };
const settings = { realTimeUpdates, shortUrlCreation, ui };
const visits = { defaultInterval: 'last30Days' };
const settings = { realTimeUpdates, shortUrlCreation, ui, visits };
describe('reducer', () => {
it('returns realTimeUpdates when action is SET_SETTINGS', () => {

View file

@ -9,6 +9,7 @@ import { Visit, VisitsInfo } from '../../src/visits/types';
import LineChartCard from '../../src/visits/helpers/LineChartCard';
import VisitsTable from '../../src/visits/VisitsTable';
import { Result } from '../../src/utils/Result';
import { Settings } from '../../src/settings/reducers/settings';
describe('<VisitStats />', () => {
const visits = [ Mock.all<Visit>(), Mock.all<Visit>(), Mock.all<Visit>() ];
@ -23,6 +24,7 @@ describe('<VisitStats />', () => {
visitsInfo={Mock.of<VisitsInfo>(visitsInfo)}
cancelGetVisits={() => {}}
baseUrl={''}
settings={Mock.all<Settings>()}
/>,
);