accounts-frontend/packages/app/components/dev/apps/list/ApplicationItem.tsx

304 lines
8.5 KiB
TypeScript
Raw Normal View History

2019-12-07 16:58:52 +05:30
import React from 'react';
import { FormattedMessage as Message } from 'react-intl';
import { Link } from 'react-router-dom';
import classNames from 'classnames';
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,
},
];
2019-12-07 16:58:52 +05:30
interface State {
selectedAction: string | null;
isActionPerforming: boolean;
detailsHeight: number;
translateY: number;
}
export default class ApplicationItem extends React.Component<
{
2019-12-07 16:58:52 +05:30
application: OauthAppResponse;
expand: boolean;
onTileClick: (clientId: string) => void;
onResetSubmit: (
clientId: string,
resetClientSecret: boolean,
) => Promise<void>;
onDeleteSubmit: (clientId: string) => Promise<void>;
},
2019-12-07 16:58:52 +05:30
State
> {
2019-12-07 16:58:52 +05:30
state: State = {
selectedAction: null,
isActionPerforming: false,
translateY: 0,
detailsHeight: 0,
};
2019-12-07 16:58:52 +05:30
actionContainer: HTMLDivElement | null;
2018-11-04 11:37:04 +05:30
render() {
const { application: app, expand } = this.props;
const { selectedAction, translateY } = this.state;
return (
<div
className={classNames(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}
2019-12-07 16:58:52 +05:30
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;
2018-05-14 01:02:53 +05:30
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;
}
}
2019-12-07 16:58:52 +05:30
setActiveAction = (type: string | null) => {
const { actionContainer } = this;
2018-11-04 11:37:04 +05:30
if (!actionContainer) {
return;
}
2018-11-04 11:37:04 +05:30
this.setState(
{
selectedAction: type,
},
() => {
const translateY = actionContainer.offsetHeight;
2018-11-04 11:37:04 +05:30
this.setState({ translateY });
},
);
};
2018-11-04 11:37:04 +05:30
onTileToggle = () => {
const { onTileClick, application } = this.props;
2018-11-04 11:37:04 +05:30
onTileClick(application.clientId);
};
onCollapseRest = () => {
if (!this.props.expand && this.state.selectedAction) {
this.setActiveAction(null);
}
};
2019-12-07 16:58:52 +05:30
onActionButtonClick = (type: string | null) => () => {
this.setActiveAction(type === this.state.selectedAction ? null : type);
};
onResetSubmit = (resetClientSecret: boolean) => async () => {
const { onResetSubmit, application } = this.props;
2018-11-04 11:37:04 +05:30
this.setState({
isActionPerforming: true,
});
2018-11-04 11:37:04 +05:30
await onResetSubmit(application.clientId, resetClientSecret);
2018-11-04 11:37:04 +05:30
this.setState({
isActionPerforming: false,
});
this.setActiveAction(null);
};
onSubmitDelete = () => {
const { onDeleteSubmit, application } = this.props;
2018-11-04 11:37:04 +05:30
this.setState({
isActionPerforming: true,
});
2018-11-04 11:37:04 +05:30
onDeleteSubmit(application.clientId);
};
}