licenses: convert LicenseDialog to functions

This commit is contained in:
David Lechner
2021-12-27 12:38:50 -06:00
parent 57038360f4
commit a58b30ed07
+108 -130
View File
@@ -12,155 +12,133 @@ import {
Dialog,
NonIdealState,
} from '@blueprintjs/core';
import { WithI18nProps, withI18n } from '@shopify/react-i18n';
import { useI18n } from '@shopify/react-i18n';
import React from 'react';
import { connect } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';
import { appName } from '../app/constants';
import { RootState } from '../reducers';
import { fetchList, select } from './actions';
import { LicenseStringId } from './i18n';
import en from './i18n.en.json';
import { LicenseInfo, LicenseList } from './reducers';
import { LicenseInfo } from './reducers';
import './license.scss';
type StateProps = {
licenseList: LicenseList | null;
licenseInfo: LicenseInfo | null;
type LicenseListPanelProps = {
onItemClick(info: LicenseInfo): void;
};
type DispatchProps = {
onOpening: () => void;
onSelectPackage: (info: LicenseInfo) => void;
const LicenseListPanel: React.VoidFunctionComponent<LicenseListPanelProps> = (
props,
) => {
const licenseList = useSelector((state: RootState) => state.licenses.list);
return (
<div className="pb-license-list">
{licenseList === null ? (
// TODO: this should be translated and hooked to
// state indicating if download is in progress
// or there was an actual failure.
<NonIdealState>Failed to load license data.</NonIdealState>
) : (
<ButtonGroup minimal={true} vertical={true} alignText="left">
{licenseList.map((info, i) => (
<Button key={i} onClick={() => props.onItemClick(info)}>
{info.name}
</Button>
))}
</ButtonGroup>
)}
</div>
);
};
type OwnProps = {
const LicenseInfoPanel = React.forwardRef<HTMLDivElement>((_props, ref) => {
const licenseInfo = useSelector((state: RootState) => state.licenses.selected);
const [i18n] = useI18n({ id: 'license', translations: { en }, fallback: en });
return (
<div className="pb-license-info" ref={ref}>
{licenseInfo == null ? (
<NonIdealState>
{i18n.translate(LicenseStringId.SelectPackageHelp)}
</NonIdealState>
) : (
<div>
<Card>
<p>
<strong>
{i18n.translate(LicenseStringId.PackageLabel)}
</strong>{' '}
{licenseInfo.name}{' '}
<span className={Classes.TEXT_MUTED}>
v{licenseInfo.version}
</span>
</p>
{licenseInfo.author && (
<p>
<strong>
{i18n.translate(LicenseStringId.AuthorLabel)}
</strong>{' '}
{licenseInfo.author}
</p>
)}
<p>
<strong>
{i18n.translate(LicenseStringId.LicenseLabel)}
</strong>{' '}
{licenseInfo.license}
</p>
</Card>
<div className="pb-license-text">
<pre>{licenseInfo.licenseText}</pre>
</div>
</div>
)}
</div>
);
});
LicenseInfoPanel.displayName = 'LicenseInfoPanel';
type LicenseDialogProps = {
isOpen: boolean;
onClose(): void;
};
type LicenseDialogProps = StateProps & DispatchProps & OwnProps & WithI18nProps;
const LicenseDialog: React.VoidFunctionComponent<LicenseDialogProps> = (props) => {
const infoDiv = React.useRef<HTMLDivElement>(null);
class LicenseDialog extends React.Component<LicenseDialogProps> {
render(): JSX.Element {
const infoDiv = React.createRef<HTMLDivElement>();
const dispatch = useDispatch();
const {
licenseList,
licenseInfo,
onOpening,
onSelectPackage,
isOpen,
onClose,
i18n,
} = this.props;
return (
<Dialog
title={i18n.translate(LicenseStringId.Title)}
isOpen={isOpen}
onOpening={() => onOpening()}
onClose={() => onClose()}
className="pb-license-dialog"
>
<div className={Classes.DIALOG_BODY}>
<Callout className={Classes.INTENT_PRIMARY} icon="info-sign">
{i18n.translate(LicenseStringId.Description, {
name: appName,
})}
</Callout>
<Callout className="pb-license-browser">
<div className="pb-license-list">
{licenseList === null ? (
// TODO: this should be translated and hooked to
// state indicating if download is in progress
// or there was an actual failure.
<NonIdealState>
Failed to load license data.
</NonIdealState>
) : (
<ButtonGroup
minimal={true}
vertical={true}
alignText="left"
>
{licenseList.map((info) => (
<Button
key={`${info.name}@${info.version}`}
onClick={() => {
infoDiv.current?.scrollTo(0, 0);
onSelectPackage(info);
}}
>
{info.name}
</Button>
))}
</ButtonGroup>
)}
</div>
<div className="pb-license-info" ref={infoDiv}>
{licenseInfo == null ? (
<NonIdealState>
{i18n.translate(LicenseStringId.SelectPackageHelp)}
</NonIdealState>
) : (
<div>
<Card>
<p>
<strong>
{i18n.translate(
LicenseStringId.PackageLabel,
)}
</strong>{' '}
{licenseInfo.name}{' '}
<span className={Classes.TEXT_MUTED}>
v{licenseInfo.version}
</span>
</p>
{licenseInfo.author && (
<p>
<strong>
{' '}
{i18n.translate(
LicenseStringId.AuthorLabel,
)}
</strong>{' '}
{licenseInfo.author}
</p>
)}
<p>
<strong>
{' '}
{i18n.translate(
LicenseStringId.LicenseLabel,
)}
</strong>{' '}
{licenseInfo.license}
</p>
</Card>
<div className="pb-license-text">
<pre>{licenseInfo.licenseText}</pre>
</div>
</div>
)}
</div>
</Callout>
</div>
</Dialog>
);
}
}
const [i18n] = useI18n({ id: 'license', translations: { en }, fallback: en });
const mapStateToProps = (state: RootState): StateProps => ({
licenseList: state.licenses.list,
licenseInfo: state.licenses.selected,
});
const mapDispatchToProps: DispatchProps = {
onOpening: fetchList,
onSelectPackage: select,
return (
<Dialog
title={i18n.translate(LicenseStringId.Title)}
onOpening={() => dispatch(fetchList())}
className="pb-license-dialog"
{...props}
>
<div className={Classes.DIALOG_BODY}>
<Callout className={Classes.INTENT_PRIMARY} icon="info-sign">
{i18n.translate(LicenseStringId.Description, {
name: appName,
})}
</Callout>
<Callout className="pb-license-browser">
<LicenseListPanel
onItemClick={(info) => {
infoDiv.current?.scrollTo(0, 0);
dispatch(select(info));
}}
/>
<LicenseInfoPanel ref={infoDiv} />
</Callout>
</div>
</Dialog>
);
};
export default connect(
mapStateToProps,
mapDispatchToProps,
)(withI18n({ id: 'license', fallback: en, translations: { en } })(LicenseDialog));
export default LicenseDialog;