fix: added packageMeta type

This commit is contained in:
Griffith Tchen Pan 2019-06-22 10:43:59 +01:00 committed by Griffithtp
parent c0b0189cc6
commit 3c54b116c9
16 changed files with 83 additions and 65 deletions

View File

@ -1,4 +1,4 @@
import React, { Component, ReactNode } from 'react'; import React, { Component, ReactNode, ReactElement } from 'react';
import Avatar from '@material-ui/core/Avatar'; import Avatar from '@material-ui/core/Avatar';
import List from '@material-ui/core/List'; import List from '@material-ui/core/List';
@ -8,18 +8,18 @@ import { DetailContextConsumer } from '../../pages/version/Version';
import { Heading, AuthorListItem } from './styles'; import { Heading, AuthorListItem } from './styles';
import { isEmail } from '../../utils/url'; import { isEmail } from '../../utils/url';
class Authors extends Component<any, any> { class Authors extends Component {
render() { public render(): ReactElement<HTMLElement> {
return ( return (
<DetailContextConsumer> <DetailContextConsumer>
{(context: any) => { {context => {
return context && context.packageMeta && this.renderAuthor(context.packageMeta); return context && context.packageMeta && this.renderAuthor(context.packageMeta);
}} }}
</DetailContextConsumer> </DetailContextConsumer>
); );
} }
renderLinkForMail(email: string, avatarComponent: ReactNode, packageName: string, version: string) { public renderLinkForMail(email: string, avatarComponent: ReactNode, packageName: string, version: string): ReactElement<HTMLElement> | ReactNode {
if (!email || isEmail(email) === false) { if (!email || isEmail(email) === false) {
return avatarComponent; return avatarComponent;
} }
@ -31,7 +31,7 @@ class Authors extends Component<any, any> {
); );
} }
renderAuthor = packageMeta => { public renderAuthor = packageMeta => {
const { author, name: packageName, version } = packageMeta.latest; const { author, name: packageName, version } = packageMeta.latest;
if (!author) { if (!author) {

View File

@ -23,10 +23,10 @@ interface Dist {
unpackedSize: number; unpackedSize: number;
} }
interface Props { export interface PackageInterface {
name: string; name: string;
version: string; version: string;
time: string; time?: number | string;
author: Author; author: Author;
description?: string; description?: string;
keywords?: string[]; keywords?: string[];
@ -35,6 +35,7 @@ interface Props {
bugs?: Bugs; bugs?: Bugs;
dist?: Dist; dist?: Dist;
} }
// interface Props {} & PackageInterface;
import { import {
Author, Author,
@ -56,7 +57,7 @@ import {
} from './styles'; } from './styles';
import { isURL } from '../../utils/url'; import { isURL } from '../../utils/url';
const Package: React.FC<Props> = ({ const Package: React.FC<PackageInterface> = ({
author: { name: authorName, avatar: authorAvatar }, author: { name: authorName, avatar: authorAvatar },
bugs, bugs,
description, description,

View File

@ -1,25 +1,21 @@
import React, { Fragment } from 'react'; import React, { Fragment, ReactElement } from 'react';
import PropTypes from 'prop-types';
import Divider from '@material-ui/core/Divider'; import Divider from '@material-ui/core/Divider';
import Package from '../Package'; import Package from '../Package';
import Help from '../Help'; import Help from '../Help';
import { formatLicense } from '../../utils/package'; import { formatLicense } from '../../utils/package';
import { PackageInterface } from '../Package/Package';
// @ts-ignore // @ts-ignore
import classes from './packageList.scss'; import classes from './packageList.scss';
interface Props { interface Props {
packages: any; packages: PackageInterface[];
} }
export default class PackageList extends React.Component<Props, {}> { export default class PackageList extends React.Component<Props, {}> {
static propTypes = { public render(): ReactElement<HTMLElement> {
packages: PropTypes.array,
};
render() {
return ( return (
<div className={'package-list-items'}> <div className={'package-list-items'}>
<div className={classes.pkgContainer}>{this.hasPackages() ? this.renderPackages() : <Help />}</div> <div className={classes.pkgContainer}>{this.hasPackages() ? this.renderPackages() : <Help />}</div>
@ -27,20 +23,19 @@ export default class PackageList extends React.Component<Props, {}> {
); );
} }
hasPackages() { private hasPackages(): boolean {
const { packages } = this.props; const { packages } = this.props;
return packages.length > 0; return packages.length > 0;
} }
renderPackages = () => { private renderPackages = () => {
return <>{this.renderList()}</>; return <>{this.renderList()}</>;
}; };
renderList = () => { private renderList = () => {
const { packages } = this.props; const { packages } = this.props;
return packages.map((pkg, i) => { return packages.map((pkg, i) => {
const { name, version, description, time, keywords, dist, homepage, bugs } = pkg; const { name, version, description, time, keywords, dist, homepage, bugs, author } = pkg;
const author = pkg.author;
// TODO: move format license to API side. // TODO: move format license to API side.
const license = formatLicense(pkg.license); const license = formatLicense(pkg.license);
return ( return (

View File

@ -13,7 +13,7 @@ import { Heading, GithubLink, RepositoryListItem } from './styles';
import git from './img/git.png'; import git from './img/git.png';
import { isURL } from '../../utils/url'; import { isURL } from '../../utils/url';
class Repository extends Component<any, any> { class Repository extends Component {
public render(): ReactElement<HTMLElement> { public render(): ReactElement<HTMLElement> {
return ( return (
<DetailContextConsumer> <DetailContextConsumer>
@ -33,12 +33,7 @@ class Repository extends Component<any, any> {
} }
private renderRepository = packageMeta => { private renderRepository = packageMeta => {
const { const { repository: { url = null } = {} } = packageMeta.latest;
repository: {
// @ts-ignore
url,
} = {},
} = packageMeta.latest;
if (!url || isURL(url) === false) { if (!url || isURL(url) === false) {
return null; return null;

View File

@ -8,7 +8,7 @@ import { formatDateDistance } from '../../utils/package';
import { Heading, Spacer, ListItemText } from './styles'; import { Heading, Spacer, ListItemText } from './styles';
class UpLinks extends React.PureComponent<any> { class UpLinks extends React.PureComponent<{}> {
public render(): ReactElement<HTMLElement> { public render(): ReactElement<HTMLElement> {
return ( return (
<DetailContextConsumer> <DetailContextConsumer>

View File

@ -4,7 +4,7 @@ import PackageList from '../../components/PackageList';
interface Props { interface Props {
isUserLoggedIn: boolean; isUserLoggedIn: boolean;
packages: any[]; packages: [];
} }
const Home: React.FC<Props> = ({ packages }) => ( const Home: React.FC<Props> = ({ packages }) => (

View File

@ -3,31 +3,44 @@ import Grid from '@material-ui/core/Grid';
import Loading from '../../components/Loading/Loading'; import Loading from '../../components/Loading/Loading';
import DetailContainer from '../../components/DetailContainer/DetailContainer'; import DetailContainer from '../../components/DetailContainer/DetailContainer';
import DetailSidebar from '../../components/DetailSidebar/DetailSidebar'; import DetailSidebar from '../../components/DetailSidebar/DetailSidebar';
import { callDetailPage, DetailPage } from '../../utils/calls'; import { callDetailPage } from '../../utils/calls';
import { getRouterPackageName } from '../../utils/package'; import { getRouterPackageName } from '../../utils/package';
import NotFound from '../../components/NotFound'; import NotFound from '../../components/NotFound';
import { PackageMetaInterface } from '../../../types/packageMeta';
export interface DetailContextProps { export interface DetailContextProps {
packageMeta: any; packageMeta: PackageMetaInterface;
readMe: any; readMe: string;
packageName: string; packageName: string;
enableLoading: () => void; enableLoading: () => void;
} }
export const DetailContext = React.createContext<DetailContextProps | null>(null); export const DetailContext = React.createContext<Partial<DetailContextProps>>({});
export interface VersionPageConsumerProps { export interface VersionPageConsumerProps {
packageMeta: any; packageMeta: PackageMetaInterface;
readMe: any; readMe: string;
packageName: any; packageName: string;
enableLoading: any; enableLoading: () => void;
} }
export const DetailContextProvider: Provider<VersionPageConsumerProps | null> = DetailContext.Provider; export const DetailContextProvider: Provider<Partial<VersionPageConsumerProps>> = DetailContext.Provider;
export const DetailContextConsumer: Consumer<VersionPageConsumerProps | null> = DetailContext.Consumer; export const DetailContextConsumer: Consumer<Partial<VersionPageConsumerProps>> = DetailContext.Consumer;
class VersionPage extends Component<any, any> { interface PropsInterface {
constructor(props: any) { match: boolean;
}
interface StateInterface {
readMe: string;
packageName: string;
packageMeta: PackageMetaInterface | null;
isLoading: boolean;
notFound: boolean;
}
class VersionPage extends Component<PropsInterface, StateInterface> {
constructor(props) {
super(props); super(props);
this.state = { this.state = {
@ -39,7 +52,7 @@ class VersionPage extends Component<any, any> {
}; };
} }
public static getDerivedStateFromProps(nextProps: any, prevState: any): any { public static getDerivedStateFromProps(nextProps, prevState): { packageName?: string; isLoading: boolean; notFound?: boolean } | null {
const { match } = nextProps; const { match } = nextProps;
const packageName = getRouterPackageName(match); const packageName = getRouterPackageName(match);
@ -65,7 +78,7 @@ class VersionPage extends Component<any, any> {
} }
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
public async componentDidUpdate(nextProps: any, prevState: any): Promise<void> { public async componentDidUpdate(nextProps, prevState: StateInterface): Promise<void> {
const { packageName } = this.state; const { packageName } = this.state;
if (packageName !== prevState.packageName) { if (packageName !== prevState.packageName) {
const { readMe, packageMeta } = await callDetailPage(packageName); const { readMe, packageMeta } = await callDetailPage(packageName);

View File

@ -12,7 +12,12 @@ const NotFound = asyncComponent(() => import('./components/NotFound'));
const VersionPackage = asyncComponent(() => import('./pages/version/Version')); const VersionPackage = asyncComponent(() => import('./pages/version/Version'));
const HomePage = asyncComponent(() => import('./pages/home')); const HomePage = asyncComponent(() => import('./pages/home'));
class RouterApp extends Component<any, any> { interface RouterAppProps {
onLogout: () => void;
onToggleLoginModal: () => void;
}
class RouterApp extends Component<RouterAppProps> {
public render(): ReactElement<HTMLDivElement> { public render(): ReactElement<HTMLDivElement> {
return ( return (
<Router history={history}> <Router history={history}>

View File

@ -6,9 +6,9 @@ import '../../types';
* @param {object} response * @param {object} response
* @returns {promise} * @returns {promise}
*/ */
function handleResponseType(response): Promise<any> { function handleResponseType(response: Response): Promise<[boolean, Blob | string]> | Promise<void> {
if (response.headers) { if (response.headers) {
const contentType = response.headers.get('Content-Type'); const contentType = response.headers.get('Content-Type') as string;
if (contentType.includes('application/pdf')) { if (contentType.includes('application/pdf')) {
return Promise.all([response.ok, response.blob()]); return Promise.all([response.ok, response.blob()]);
} }

View File

@ -1,8 +1,9 @@
import API from './api'; import API from './api';
import { PackageMetaInterface } from 'types/packageMeta';
export interface DetailPage { export interface DetailPage {
readMe: any; readMe: string;
packageMeta: any; packageMeta: PackageMetaInterface;
} }
export async function callDetailPage(packageName): Promise<DetailPage> { export async function callDetailPage(packageName): Promise<DetailPage> {

View File

@ -1,3 +1,4 @@
/* tslint:disable */
export default function fileSizeSI(a?: any, b?: any, c?: any, d?: any, e?: any) { export default function fileSizeSI(a?: any, b?: any, c?: any, d?: any, e?: any) {
return ((b = Math), (c = b.log), (d = 1e3), (e = (c(a) / c(d)) | 0), a / b.pow(d, e)).toFixed(2) + ' ' + (e ? 'kMGTPEZY'[--e] + 'B' : 'Bytes'); return ((b = Math), (c = b.log), (d = 1e3), (e = (c(a) / c(d)) | 0), a / b.pow(d, e)).toFixed(2) + ' ' + (e ? 'kMGTPEZY'[--e] + 'B' : 'Bytes');
} }

View File

@ -5,30 +5,34 @@ import { Base64 } from 'js-base64';
import API from './api'; import API from './api';
import { HEADERS } from '../../lib/constants'; import { HEADERS } from '../../lib/constants';
export function isTokenExpire(token?: any) { interface PayloadInterface {
exp: number;
}
export function isTokenExpire(token?: string): boolean {
if (!isString(token)) { if (!isString(token)) {
return true; return true;
} }
let [, payload]: any = token.split('.'); const [, payload] = token.split('.');
if (!payload) { if (!payload) {
return true; return true;
} }
let exp: number;
try { try {
payload = JSON.parse(Base64.decode(payload)); exp = JSON.parse(Base64.decode(payload)).exp;
} catch (error) { } catch (error) {
// eslint-disable-next-line console.error('Invalid token:', error, token);
console.error('Invalid token:', error, token);
return true; return true;
} }
if (!payload.exp || !isNumber(payload.exp)) { if (!exp || !isNumber(exp)) {
return true; return true;
} }
// Report as expire before (real expire time - 30s) // Report as expire before (real expire time - 30s)
const jsTimestamp = payload.exp * 1000 - 30000; const jsTimestamp = exp * 1000 - 30000;
const expired = Date.now() >= jsTimestamp; const expired = Date.now() >= jsTimestamp;
return expired; return expired;

View File

@ -1,6 +1,6 @@
import parseXSS from 'xss'; import parseXSS from 'xss';
export function preventXSS(text: string) { export function preventXSS(text: string): string {
const encodedText = parseXSS.filterXSS(text); const encodedText = parseXSS.filterXSS(text);
return encodedText; return encodedText;

View File

@ -1,7 +1,7 @@
/** /**
* CSS to represent truncated text with an ellipsis. * CSS to represent truncated text with an ellipsis.
*/ */
export function ellipsis(width: string | number) { export function ellipsis(width: string | number): {} {
return { return {
display: 'inline-block', display: 'inline-block',
maxWidth: width, maxWidth: width,
@ -24,7 +24,7 @@ interface SpacingShortHand<type> {
const positionMap = ['Top', 'Right', 'Bottom', 'Left']; const positionMap = ['Top', 'Right', 'Bottom', 'Left'];
export function spacing(property: 'padding' | 'margin', ...values: SpacingShortHand<number | string>[]) { export function spacing(property: 'padding' | 'margin', ...values: SpacingShortHand<number | string>[]): {} {
const [firstValue = 0, secondValue = 0, thirdValue = 0, fourthValue = 0] = values; const [firstValue = 0, secondValue = 0, thirdValue = 0, fourthValue = 0] = values;
const valuesWithDefaults = [firstValue, secondValue, thirdValue, fourthValue]; const valuesWithDefaults = [firstValue, secondValue, thirdValue, fourthValue];
let styles = {}; let styles = {};

7
types/custom.d.ts vendored
View File

@ -1,10 +1,7 @@
// https://stackoverflow.com/questions/44717164/unable-to-import-svg-files-in-typescript // https://stackoverflow.com/questions/44717164/unable-to-import-svg-files-in-typescript
declare module '*.svg' { declare module '*.svg' {
const content: any; const content: string;
export default content; export default content;
} }
declare module '*.png' { declare module '*.png';
const content: any;
export default content;
}

6
types/packageMeta.ts Normal file
View File

@ -0,0 +1,6 @@
export interface PackageMetaInterface {
latest: {
name: string;
};
_uplinks: {};
}