accounts-frontend/packages/app/components/dev/apps/list/ApplicationItem.tsx
2019-12-07 21:43:08 +02:00

304 lines
8.4 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React from 'react';
import { FormattedMessage as Message } from 'react-intl';
import { Link } from 'react-router-dom';
import clsx from 'clsx';
import { SKIN_LIGHT, COLOR_BLACK, COLOR_RED } from 'app/components/ui';
import { Input, Button } from 'app/components/ui/form';
import { OauthAppResponse } from 'app/services/api/oauth';
import Collapse from 'app/components/ui/collapse';
import styles from '../applicationsIndex.scss';
import messages from '../ApplicationsIndex.intl.json';
const ACTION_REVOKE_TOKENS = 'revoke-tokens';
const ACTION_RESET_SECRET = 'reset-secret';
const ACTION_DELETE = 'delete';
const actionButtons = [
{
type: ACTION_REVOKE_TOKENS,
label: messages.revokeAllTokens,
},
{
type: ACTION_RESET_SECRET,
label: messages.resetClientSecret,
},
{
type: ACTION_DELETE,
label: messages.delete,
},
];
interface State {
selectedAction: string | null;
isActionPerforming: boolean;
detailsHeight: number;
translateY: number;
}
export default class ApplicationItem extends React.Component<
{
application: OauthAppResponse;
expand: boolean;
onTileClick: (clientId: string) => void;
onResetSubmit: (
clientId: string,
resetClientSecret: boolean,
) => Promise<void>;
onDeleteSubmit: (clientId: string) => Promise<void>;
},
State
> {
state: State = {
selectedAction: null,
isActionPerforming: false,
translateY: 0,
detailsHeight: 0,
};
actionContainer: HTMLDivElement | null;
render() {
const { application: app, expand } = this.props;
const { selectedAction, translateY } = this.state;
return (
<div
className={clsx(styles.appItemContainer, {
[styles.appExpanded]: expand,
})}
data-e2e="appItem"
data-e2e-app-name={app.name}
>
<div className={styles.appItemTile} onClick={this.onTileToggle}>
<div className={styles.appTileTitle}>
<div className={styles.appName}>{app.name}</div>
<div className={styles.appStats}>
Client ID: {app.clientId}
{typeof app.countUsers !== 'undefined' && (
<span>
{' | '}
<Message
{...messages.countUsers}
values={{
count: app.countUsers,
}}
/>
</span>
)}
</div>
</div>
<div className={styles.appItemToggle}>
<div className={styles.appItemToggleIcon} />
</div>
</div>
<Collapse isOpened={expand} onRest={this.onCollapseRest}>
<div
className={styles.appDetailsContainer}
style={{ transform: `translateY(-${translateY}px)` }}
>
<div className={styles.appDetailsInfoField}>
<Link
to={`/dev/applications/${app.clientId}`}
className={styles.editAppLink}
>
<Message
{...messages.editDescription}
values={{
icon: <div className={styles.pencilIcon} />,
}}
/>
</Link>
<Input
label="Client ID:"
skin={SKIN_LIGHT}
disabled
value={app.clientId}
copy
/>
</div>
<div className={styles.appDetailsInfoField}>
<Input
label="Client Secret:"
skin={SKIN_LIGHT}
disabled
value={app.clientSecret}
copy
/>
</div>
<div className={styles.appDetailsDescription}>
<Message
{...messages.ifYouSuspectingThatSecretHasBeenCompromised}
/>
</div>
<div className={styles.appActionsButtons}>
{actionButtons.map(({ type, label }) => (
<Button
key={type}
label={label}
color={COLOR_BLACK}
className={styles.appActionButton}
disabled={!!selectedAction && selectedAction !== type}
onClick={this.onActionButtonClick(type)}
small
/>
))}
</div>
<div
className={styles.appActionContainer}
ref={el => {
this.actionContainer = el;
}}
>
{this.getActionContent()}
</div>
</div>
</Collapse>
</div>
);
}
getActionContent() {
const { selectedAction, isActionPerforming } = this.state;
switch (selectedAction) {
case ACTION_REVOKE_TOKENS:
case ACTION_RESET_SECRET:
return (
<div>
<div className={styles.appActionDescription}>
<Message {...messages.allRefreshTokensWillBecomeInvalid} />{' '}
<Message {...messages.takeCareAccessTokensInvalidation} />
</div>
<div className={styles.appActionsButtons}>
<Button
label={messages.cancel}
color={COLOR_BLACK}
className={styles.appActionButton}
onClick={this.onActionButtonClick(null)}
small
/>
<div className={styles.continueActionButtonWrapper}>
{isActionPerforming ? (
<div className={styles.performingAction}>
<Message {...messages.performing} />
</div>
) : (
<div
className={styles.continueActionLink}
onClick={this.onResetSubmit(
selectedAction === ACTION_RESET_SECRET,
)}
>
<Message {...messages.continue} />
</div>
)}
</div>
</div>
</div>
);
case ACTION_DELETE:
return (
<div>
<div className={styles.appActionDescription}>
<Message {...messages.appAndAllTokenWillBeDeleted} />{' '}
<Message {...messages.takeCareAccessTokensInvalidation} />
</div>
<div className={styles.appActionsButtons}>
<Button
label={messages.cancel}
color={COLOR_BLACK}
className={styles.appActionButton}
onClick={this.onActionButtonClick(null)}
small
/>
<div className={styles.continueActionButtonWrapper}>
{isActionPerforming ? (
<div className={styles.performingAction}>
<Message {...messages.performing} />
</div>
) : (
<Button
label={messages.delete}
color={COLOR_RED}
className={styles.appActionButton}
onClick={this.onSubmitDelete}
small
/>
)}
</div>
</div>
</div>
);
default:
return null;
}
}
setActiveAction = (type: string | null) => {
const { actionContainer } = this;
if (!actionContainer) {
return;
}
this.setState(
{
selectedAction: type,
},
() => {
const translateY = actionContainer.offsetHeight;
this.setState({ translateY });
},
);
};
onTileToggle = () => {
const { onTileClick, application } = this.props;
onTileClick(application.clientId);
};
onCollapseRest = () => {
if (!this.props.expand && this.state.selectedAction) {
this.setActiveAction(null);
}
};
onActionButtonClick = (type: string | null) => () => {
this.setActiveAction(type === this.state.selectedAction ? null : type);
};
onResetSubmit = (resetClientSecret: boolean) => async () => {
const { onResetSubmit, application } = this.props;
this.setState({
isActionPerforming: true,
});
await onResetSubmit(application.clientId, resetClientSecret);
this.setState({
isActionPerforming: false,
});
this.setActiveAction(null);
};
onSubmitDelete = () => {
const { onDeleteSubmit, application } = this.props;
this.setState({
isActionPerforming: true,
});
onDeleteSubmit(application.clientId);
};
}