mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2025-01-09 09:47:28 +03:00
Migrated to TS all visits components except the biggest two
This commit is contained in:
parent
f2e7a2161d
commit
73b854037d
14 changed files with 85 additions and 173 deletions
|
@ -1,4 +1,3 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { Action, Dispatch } from 'redux';
|
||||
import { ShlinkMercureInfo } from '../../utils/services/types';
|
||||
import { GetState } from '../../container/types';
|
||||
|
@ -11,14 +10,6 @@ export const GET_MERCURE_INFO_ERROR = 'shlink/mercure/GET_MERCURE_INFO_ERROR';
|
|||
export const GET_MERCURE_INFO = 'shlink/mercure/GET_MERCURE_INFO';
|
||||
/* eslint-enable padding-line-between-statements */
|
||||
|
||||
/** @deprecated Use MercureInfo interface */
|
||||
export const MercureInfoType = PropTypes.shape({
|
||||
token: PropTypes.string,
|
||||
mercureHubUrl: PropTypes.string,
|
||||
loading: PropTypes.bool,
|
||||
error: PropTypes.bool,
|
||||
});
|
||||
|
||||
export interface MercureInfo {
|
||||
token?: string;
|
||||
mercureHubUrl?: string;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { Dispatch, Action } from 'redux';
|
||||
import { ShortUrlIdentifier, ShortUrlMeta } from '../data';
|
||||
import { GetState } from '../../container/types';
|
||||
|
@ -13,13 +12,6 @@ export const SHORT_URL_META_EDITED = 'shlink/shortUrlMeta/SHORT_URL_META_EDITED'
|
|||
export const RESET_EDIT_SHORT_URL_META = 'shlink/shortUrlMeta/RESET_EDIT_SHORT_URL_META';
|
||||
/* eslint-enable padding-line-between-statements */
|
||||
|
||||
/** @deprecated Use ShortUrlMeta interface instead */
|
||||
export const shortUrlMetaType = PropTypes.shape({
|
||||
validSince: PropTypes.string,
|
||||
validUntil: PropTypes.string,
|
||||
maxVisits: PropTypes.number,
|
||||
});
|
||||
|
||||
export interface ShortUrlMetaEdition {
|
||||
shortCode: string | null;
|
||||
meta: ShortUrlMeta;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { assoc, assocPath, reject } from 'ramda';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Action, Dispatch } from 'redux';
|
||||
import { shortUrlMatches } from '../helpers';
|
||||
import { CREATE_VISIT, CreateVisitAction } from '../../visits/reducers/visitCreation';
|
||||
|
@ -10,7 +9,7 @@ import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuil
|
|||
import { ShlinkShortUrlsResponse } from '../../utils/services/types';
|
||||
import { EditShortUrlTagsAction, SHORT_URL_TAGS_EDITED } from './shortUrlTags';
|
||||
import { SHORT_URL_DELETED } from './shortUrlDeletion';
|
||||
import { SHORT_URL_META_EDITED, ShortUrlMetaEditedAction, shortUrlMetaType } from './shortUrlMeta';
|
||||
import { SHORT_URL_META_EDITED, ShortUrlMetaEditedAction } from './shortUrlMeta';
|
||||
import { SHORT_URL_EDITED, ShortUrlEditedAction } from './shortUrlEdition';
|
||||
import { ShortUrlsListParams } from './shortUrlsListParams';
|
||||
|
||||
|
@ -20,17 +19,6 @@ export const LIST_SHORT_URLS_ERROR = 'shlink/shortUrlsList/LIST_SHORT_URLS_ERROR
|
|||
export const LIST_SHORT_URLS = 'shlink/shortUrlsList/LIST_SHORT_URLS';
|
||||
/* eslint-enable padding-line-between-statements */
|
||||
|
||||
/** @deprecated Use ShortUrl interface instead */
|
||||
export const shortUrlType = PropTypes.shape({
|
||||
shortCode: PropTypes.string,
|
||||
shortUrl: PropTypes.string,
|
||||
longUrl: PropTypes.string,
|
||||
visitsCount: PropTypes.number,
|
||||
meta: shortUrlMetaType,
|
||||
tags: PropTypes.arrayOf(PropTypes.string),
|
||||
domain: PropTypes.string,
|
||||
});
|
||||
|
||||
export interface ShortUrlsList {
|
||||
shortUrls?: ShlinkShortUrlsResponse;
|
||||
loading: boolean;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { rangeOf } from '../utils';
|
||||
import LocalStorage from './LocalStorage';
|
||||
|
||||
|
@ -36,9 +35,3 @@ export default class ColorGenerator {
|
|||
return color;
|
||||
};
|
||||
}
|
||||
|
||||
/** @deprecated Use ColorGenerator class instead */
|
||||
export const colorGeneratorType = PropTypes.shape({
|
||||
getColorForKey: PropTypes.func,
|
||||
setColorForKey: PropTypes.func,
|
||||
});
|
||||
|
|
|
@ -7,7 +7,7 @@ import { ShortUrlVisits as ShortUrlVisitsState } from './reducers/shortUrlVisits
|
|||
import ShortUrlVisitsHeader from './ShortUrlVisitsHeader';
|
||||
import { ShortUrlDetail } from './reducers/shortUrlDetail';
|
||||
|
||||
interface ShortUrlVisitsProps extends RouteComponentProps<{ shortCode: string }>, MercureBoundProps {
|
||||
export interface ShortUrlVisitsProps extends RouteComponentProps<{ shortCode: string }>, MercureBoundProps {
|
||||
getShortUrlVisits: (shortCode: string, query?: ShlinkVisitsParams) => void;
|
||||
shortUrlVisits: ShortUrlVisitsState;
|
||||
getShortUrlDetail: Function;
|
||||
|
|
|
@ -1,24 +1,23 @@
|
|||
import { UncontrolledTooltip } from 'reactstrap';
|
||||
import Moment from 'react-moment';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ExternalLink } from 'react-external-link';
|
||||
import { shortUrlDetailType } from './reducers/shortUrlDetail';
|
||||
import { shortUrlVisitsType } from './reducers/shortUrlVisits';
|
||||
import { ShortUrlDetail } from './reducers/shortUrlDetail';
|
||||
import { ShortUrlVisits } from './reducers/shortUrlVisits';
|
||||
import VisitsHeader from './VisitsHeader';
|
||||
import './ShortUrlVisitsHeader.scss';
|
||||
|
||||
const propTypes = {
|
||||
shortUrlDetail: shortUrlDetailType.isRequired,
|
||||
shortUrlVisits: shortUrlVisitsType.isRequired,
|
||||
goBack: PropTypes.func.isRequired,
|
||||
};
|
||||
interface ShortUrlVisitsHeaderProps {
|
||||
shortUrlDetail: ShortUrlDetail;
|
||||
shortUrlVisits: ShortUrlVisits;
|
||||
goBack: () => void;
|
||||
}
|
||||
|
||||
const ShortUrlVisitsHeader = ({ shortUrlDetail, shortUrlVisits, goBack }) => {
|
||||
const ShortUrlVisitsHeader = ({ shortUrlDetail, shortUrlVisits, goBack }: ShortUrlVisitsHeaderProps) => {
|
||||
const { shortUrl, loading } = shortUrlDetail;
|
||||
const { visits } = shortUrlVisits;
|
||||
const shortLink = shortUrl && shortUrl.shortUrl ? shortUrl.shortUrl : '';
|
||||
const longLink = shortUrl && shortUrl.longUrl ? shortUrl.longUrl : '';
|
||||
const shortLink = shortUrl?.shortUrl ?? '';
|
||||
const longLink = shortUrl?.longUrl ?? '';
|
||||
|
||||
const renderDate = () => !shortUrl ? <small>Loading...</small> : (
|
||||
<span>
|
||||
|
@ -49,6 +48,4 @@ const ShortUrlVisitsHeader = ({ shortUrlDetail, shortUrlVisits, goBack }) => {
|
|||
);
|
||||
};
|
||||
|
||||
ShortUrlVisitsHeader.propTypes = propTypes;
|
||||
|
||||
export default ShortUrlVisitsHeader;
|
|
@ -1,52 +0,0 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { MercureInfoType } from '../mercure/reducers/mercureInfo';
|
||||
import { useMercureTopicBinding } from '../mercure/helpers';
|
||||
import { TagVisitsType } from './reducers/tagVisits';
|
||||
import TagVisitsHeader from './TagVisitsHeader';
|
||||
|
||||
const propTypes = {
|
||||
history: PropTypes.shape({
|
||||
goBack: PropTypes.func,
|
||||
}),
|
||||
match: PropTypes.shape({
|
||||
params: PropTypes.object,
|
||||
}),
|
||||
getTagVisits: PropTypes.func,
|
||||
tagVisits: TagVisitsType,
|
||||
cancelGetTagVisits: PropTypes.func,
|
||||
createNewVisit: PropTypes.func,
|
||||
loadMercureInfo: PropTypes.func,
|
||||
mercureInfo: MercureInfoType,
|
||||
};
|
||||
|
||||
const TagVisits = (VisitsStats, colorGenerator) => {
|
||||
const TagVisitsComp = ({
|
||||
history,
|
||||
match,
|
||||
getTagVisits,
|
||||
tagVisits,
|
||||
cancelGetTagVisits,
|
||||
createNewVisit,
|
||||
loadMercureInfo,
|
||||
mercureInfo,
|
||||
}) => {
|
||||
const { params } = match;
|
||||
const { tag } = params;
|
||||
const loadVisits = (dates) => getTagVisits(tag, dates);
|
||||
|
||||
useMercureTopicBinding(mercureInfo, 'https://shlink.io/new-visit', createNewVisit, loadMercureInfo);
|
||||
|
||||
return (
|
||||
<VisitsStats getVisits={loadVisits} cancelGetVisits={cancelGetTagVisits} visitsInfo={tagVisits}>
|
||||
<TagVisitsHeader tagVisits={tagVisits} goBack={history.goBack} colorGenerator={colorGenerator} />
|
||||
</VisitsStats>
|
||||
);
|
||||
};
|
||||
|
||||
TagVisitsComp.propTypes = propTypes;
|
||||
|
||||
return TagVisitsComp;
|
||||
};
|
||||
|
||||
export default TagVisits;
|
37
src/visits/TagVisits.tsx
Normal file
37
src/visits/TagVisits.tsx
Normal file
|
@ -0,0 +1,37 @@
|
|||
import React, { FC } from 'react';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import { MercureBoundProps, useMercureTopicBinding } from '../mercure/helpers';
|
||||
import ColorGenerator from '../utils/services/ColorGenerator';
|
||||
import { TagVisits as TagVisitsState } from './reducers/tagVisits';
|
||||
import TagVisitsHeader from './TagVisitsHeader';
|
||||
|
||||
export interface TagVisitsProps extends RouteComponentProps<{ tag: string }>, MercureBoundProps {
|
||||
getTagVisits: (tag: string, query: any) => void;
|
||||
tagVisits: TagVisitsState;
|
||||
cancelGetTagVisits: Function;
|
||||
}
|
||||
|
||||
const TagVisits = (VisitsStats: FC<any>, colorGenerator: ColorGenerator) => ({ // TODO Use VisitsStatsProps once available
|
||||
history: { goBack },
|
||||
match,
|
||||
getTagVisits,
|
||||
tagVisits,
|
||||
cancelGetTagVisits,
|
||||
createNewVisit,
|
||||
loadMercureInfo,
|
||||
mercureInfo,
|
||||
}: TagVisitsProps) => {
|
||||
const { params } = match;
|
||||
const { tag } = params;
|
||||
const loadVisits = (dates: any) => getTagVisits(tag, dates);
|
||||
|
||||
useMercureTopicBinding(mercureInfo, 'https://shlink.io/new-visit', createNewVisit, loadMercureInfo);
|
||||
|
||||
return (
|
||||
<VisitsStats getVisits={loadVisits} cancelGetVisits={cancelGetTagVisits} visitsInfo={tagVisits}>
|
||||
<TagVisitsHeader tagVisits={tagVisits} goBack={goBack} colorGenerator={colorGenerator} />
|
||||
</VisitsStats>
|
||||
);
|
||||
};
|
||||
|
||||
export default TagVisits;
|
|
@ -1,18 +1,17 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Tag from '../tags/helpers/Tag';
|
||||
import { colorGeneratorType } from '../utils/services/ColorGenerator';
|
||||
import ColorGenerator from '../utils/services/ColorGenerator';
|
||||
import VisitsHeader from './VisitsHeader';
|
||||
import { TagVisitsType } from './reducers/tagVisits';
|
||||
import { TagVisits } from './reducers/tagVisits';
|
||||
import './ShortUrlVisitsHeader.scss';
|
||||
|
||||
const propTypes = {
|
||||
tagVisits: TagVisitsType.isRequired,
|
||||
goBack: PropTypes.func.isRequired,
|
||||
colorGenerator: colorGeneratorType,
|
||||
};
|
||||
interface TagVisitsHeader {
|
||||
tagVisits: TagVisits;
|
||||
goBack: () => void;
|
||||
colorGenerator: ColorGenerator;
|
||||
}
|
||||
|
||||
const TagVisitsHeader = ({ tagVisits, goBack, colorGenerator }) => {
|
||||
const TagVisitsHeader = ({ tagVisits, goBack, colorGenerator }: TagVisitsHeader) => {
|
||||
const { visits, tag } = tagVisits;
|
||||
|
||||
const visitsStatsTitle = (
|
||||
|
@ -25,6 +24,4 @@ const TagVisitsHeader = ({ tagVisits, goBack, colorGenerator }) => {
|
|||
return <VisitsHeader title={visitsStatsTitle} goBack={goBack} visits={visits} />;
|
||||
};
|
||||
|
||||
TagVisitsHeader.propTypes = propTypes;
|
||||
|
||||
export default TagVisitsHeader;
|
|
@ -1,21 +1,19 @@
|
|||
import { Button, Card } from 'reactstrap';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { FC, ReactNode } from 'react';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faArrowLeft } from '@fortawesome/free-solid-svg-icons';
|
||||
import ShortUrlVisitsCount from '../short-urls/helpers/ShortUrlVisitsCount';
|
||||
import { shortUrlType } from '../short-urls/reducers/shortUrlsList';
|
||||
import { VisitType } from './types';
|
||||
import { ShortUrl } from '../short-urls/data';
|
||||
import { Visit } from './types';
|
||||
|
||||
const propTypes = {
|
||||
visits: PropTypes.arrayOf(VisitType).isRequired,
|
||||
goBack: PropTypes.func.isRequired,
|
||||
title: PropTypes.node.isRequired,
|
||||
children: PropTypes.node,
|
||||
shortUrl: shortUrlType,
|
||||
};
|
||||
interface VisitsHeaderProps {
|
||||
visits: Visit[];
|
||||
goBack: () => void;
|
||||
title: ReactNode;
|
||||
shortUrl?: ShortUrl;
|
||||
}
|
||||
|
||||
const VisitsHeader = ({ visits, goBack, shortUrl, children, title }) => (
|
||||
const VisitsHeader: FC<VisitsHeaderProps> = ({ visits, goBack, shortUrl, children, title }) => (
|
||||
<header>
|
||||
<Card className="bg-light" body>
|
||||
<h2 className="d-flex justify-content-between align-items-center mb-0">
|
||||
|
@ -39,6 +37,4 @@ const VisitsHeader = ({ visits, goBack, shortUrl, children, title }) => (
|
|||
</header>
|
||||
);
|
||||
|
||||
VisitsHeader.propTypes = propTypes;
|
||||
|
||||
export default VisitsHeader;
|
|
@ -1,6 +1,4 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { Action, Dispatch } from 'redux';
|
||||
import { shortUrlType } from '../../short-urls/reducers/shortUrlsList';
|
||||
import { ShortUrl } from '../../short-urls/data';
|
||||
import { buildReducer } from '../../utils/helpers/redux';
|
||||
import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder';
|
||||
|
@ -13,13 +11,6 @@ export const GET_SHORT_URL_DETAIL_ERROR = 'shlink/shortUrlDetail/GET_SHORT_URL_D
|
|||
export const GET_SHORT_URL_DETAIL = 'shlink/shortUrlDetail/GET_SHORT_URL_DETAIL';
|
||||
/* eslint-enable padding-line-between-statements */
|
||||
|
||||
/** @deprecated Use ShortUrlDetail interface instead */
|
||||
export const shortUrlDetailType = PropTypes.shape({
|
||||
shortUrl: shortUrlType,
|
||||
loading: PropTypes.bool,
|
||||
error: PropTypes.bool,
|
||||
});
|
||||
|
||||
export interface ShortUrlDetail {
|
||||
shortUrl?: ShortUrl;
|
||||
loading: boolean;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { Action, Dispatch } from 'redux';
|
||||
import { shortUrlMatches } from '../../short-urls/helpers';
|
||||
import { Visit, VisitsInfo, VisitsLoadProgressChangedAction, VisitType } from '../types';
|
||||
import { Visit, VisitsInfo, VisitsLoadProgressChangedAction } from '../types';
|
||||
import { ShortUrlIdentifier } from '../../short-urls/data';
|
||||
import { buildActionCreator, buildReducer } from '../../utils/helpers/redux';
|
||||
import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder';
|
||||
|
@ -19,17 +18,6 @@ export const GET_SHORT_URL_VISITS_CANCEL = 'shlink/shortUrlVisits/GET_SHORT_URL_
|
|||
export const GET_SHORT_URL_VISITS_PROGRESS_CHANGED = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_PROGRESS_CHANGED';
|
||||
/* eslint-enable padding-line-between-statements */
|
||||
|
||||
/** @deprecated Use ShortUrlVisits interface instead */
|
||||
export const shortUrlVisitsType = PropTypes.shape({
|
||||
visits: PropTypes.arrayOf(VisitType),
|
||||
shortCode: PropTypes.string,
|
||||
domain: PropTypes.string,
|
||||
loading: PropTypes.bool,
|
||||
loadingLarge: PropTypes.bool,
|
||||
error: PropTypes.bool,
|
||||
progress: PropTypes.number,
|
||||
});
|
||||
|
||||
export interface ShortUrlVisits extends VisitsInfo, ShortUrlIdentifier {}
|
||||
|
||||
interface ShortUrlVisitsAction extends Action<string>, ShortUrlIdentifier {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { Action, Dispatch } from 'redux';
|
||||
import { Visit, VisitsInfo, VisitsLoadProgressChangedAction, VisitType } from '../types';
|
||||
import { Visit, VisitsInfo, VisitsLoadProgressChangedAction } from '../types';
|
||||
import { buildActionCreator, buildReducer } from '../../utils/helpers/redux';
|
||||
import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder';
|
||||
import { GetState } from '../../container/types';
|
||||
|
@ -16,16 +15,6 @@ export const GET_TAG_VISITS_CANCEL = 'shlink/tagVisits/GET_TAG_VISITS_CANCEL';
|
|||
export const GET_TAG_VISITS_PROGRESS_CHANGED = 'shlink/tagVisits/GET_TAG_VISITS_PROGRESS_CHANGED';
|
||||
/* eslint-enable padding-line-between-statements */
|
||||
|
||||
/** @deprecated Use TagVisits interface instead */
|
||||
export const TagVisitsType = PropTypes.shape({
|
||||
visits: PropTypes.arrayOf(VisitType),
|
||||
tag: PropTypes.string,
|
||||
loading: PropTypes.bool,
|
||||
loadingLarge: PropTypes.bool,
|
||||
error: PropTypes.bool,
|
||||
progress: PropTypes.number,
|
||||
});
|
||||
|
||||
export interface TagVisits extends VisitsInfo {
|
||||
tag: string;
|
||||
}
|
||||
|
|
|
@ -1,19 +1,24 @@
|
|||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { shallow, ShallowWrapper } from 'enzyme';
|
||||
import { identity } from 'ramda';
|
||||
import createShortUrlVisits from '../../src/visits/ShortUrlVisits';
|
||||
import { Mock } from 'ts-mockery';
|
||||
import { History, Location } from 'history';
|
||||
import { match } from 'react-router'; // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
import createShortUrlVisits, { ShortUrlVisitsProps } from '../../src/visits/ShortUrlVisits';
|
||||
import ShortUrlVisitsHeader from '../../src/visits/ShortUrlVisitsHeader';
|
||||
import { ShortUrlVisits as ShortUrlVisitsState } from '../../src/visits/reducers/shortUrlVisits';
|
||||
import { ShortUrlDetail } from '../../src/visits/reducers/shortUrlDetail';
|
||||
|
||||
describe('<ShortUrlVisits />', () => {
|
||||
let wrapper;
|
||||
let wrapper: ShallowWrapper;
|
||||
const getShortUrlVisitsMock = jest.fn();
|
||||
const match = {
|
||||
const match = Mock.of<match<{ shortCode: string }>>({
|
||||
params: { shortCode: 'abc123' },
|
||||
};
|
||||
const location = { search: '' };
|
||||
const history = {
|
||||
});
|
||||
const location = Mock.of<Location>({ search: '' });
|
||||
const history = Mock.of<History>({
|
||||
goBack: jest.fn(),
|
||||
};
|
||||
});
|
||||
const VisitsStats = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -21,15 +26,15 @@ describe('<ShortUrlVisits />', () => {
|
|||
|
||||
wrapper = shallow(
|
||||
<ShortUrlVisits
|
||||
{...Mock.all<ShortUrlVisitsProps>()}
|
||||
getShortUrlDetail={identity}
|
||||
getShortUrlVisits={getShortUrlVisitsMock}
|
||||
match={match}
|
||||
location={location}
|
||||
history={history}
|
||||
shortUrlVisits={{ loading: true, visits: [] }}
|
||||
shortUrlDetail={{}}
|
||||
shortUrlVisits={Mock.of<ShortUrlVisitsState>({ loading: true, visits: [] })}
|
||||
shortUrlDetail={Mock.all<ShortUrlDetail>()}
|
||||
cancelGetShortUrlVisits={identity}
|
||||
matchMedia={() => ({ matches: false })}
|
||||
/>,
|
||||
);
|
||||
});
|
Loading…
Reference in a new issue