oak-general-business/es/components/oauth/records/web.pc.js

135 lines
6.9 KiB
JavaScript

import React from 'react';
import { Modal, Avatar, Pagination } from 'antd';
import { AppstoreOutlined } from '@ant-design/icons';
import Styles from './styles.module.less';
const Records = (props) => {
const { list, oakPagination } = props.data;
const { pageSize, currentPage, total } = oakPagination || {};
const { t, revoke, setCurrentPage, setPageSize } = props.methods;
const handleRevoke = (item) => {
Modal.confirm({
title: t('revoke_confirm_title'),
content: t('revoke_confirm_content', { appName: item.application?.name || t('unknown_app') }),
okText: t('confirm'),
cancelText: t('cancel'),
okButtonProps: { danger: true },
onOk: () => {
revoke(item);
},
});
};
const formatDate = (date) => {
if (!date)
return '-';
return new Date(date).toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
});
};
function formateScope(scope) {
if (!scope || scope.length === 0 || scope.includes('')) {
return t('full_access');
}
return scope.join(', ');
}
const getStatusTag = (item) => {
if (item.token?.revokedAt) {
return <span className={Styles.statusRevoked}>{t('status_revoked')}</span>;
}
if (item.usageState === 'denied') {
return <span className={Styles.statusDenied}>{t('status_denied')}</span>;
}
if (item.token?.refreshExpiresAt && new Date(item.token.refreshExpiresAt) < new Date()) {
return <span className={Styles.statusExpired}>{t('status_expired')}</span>;
}
if (item.usageState === 'granted') {
return <span className={Styles.statusActive}>{t('status_active')}</span>;
}
if (item.usageState === 'revoked') {
return <span className={Styles.statusRevoked}>{t('status_revoked')}</span>;
}
return <span className={Styles.statusUnknown}>{t('status_unknown')}</span>;
};
const isRevokable = (item) => {
return item.usageState === 'granted' && !item.token?.revokedAt;
};
return (<div className={Styles.container}>
<div className={Styles.header}>
<h2>{t('page_title')}</h2>
<p className={Styles.description}>{t('page_description')}</p>
</div>
{!list || list.length === 0 ? (<div className={Styles.empty}>
<div className={Styles.emptyIcon}>🔐</div>
<p>{t('no_records')}</p>
</div>) : (<>
<div className={Styles.listContainer}>
{list.map((item) => {
return (<div key={item.id} className={Styles.item}>
<div className={Styles.itemHeader}>
<div className={Styles.appInfo}>
<Avatar src={item.application?.logo} icon={!item.application?.logo && <AppstoreOutlined />} size={48} shape="square" className={Styles.appLogo}/>
<div className={Styles.appNameWrapper}>
<h3 className={Styles.appName}>
{item.application?.name || t('unknown_app')}
</h3>
{getStatusTag(item)}
</div>
</div>
{isRevokable(item) && (<button className={Styles.revokeButton} onClick={() => handleRevoke(item)}>
{t('revoke')}
</button>)}
</div>
{item.application?.description && (<p className={Styles.appDescription}>
{item.application?.description}
</p>)}
<div className={Styles.itemDetails}>
<div className={Styles.detailRow}>
<span className={Styles.label}>{t('authorized_at')}:</span>
<span className={Styles.value}>{formatDate(item.authorizedAt)}</span>
</div>
<div className={Styles.detailRow}>
<span className={Styles.label}>{t('scope')}:</span>
<span className={Styles.value}>
{formateScope(item.code?.scope)}
</span>
</div>
{item.token?.lastUsedAt && (<div className={Styles.detailRow}>
<span className={Styles.label}>{t('last_used_at')}:</span>
<span className={Styles.value}>{formatDate(item.token.lastUsedAt)}</span>
</div>)}
{/* {item.token?.accessExpiresAt && (
<div className={Styles.detailRow}>
<span className={Styles.label}>{t('access_expires_at')}:</span>
<span className={Styles.value}>{formatDate(item.token.accessExpiresAt)}</span>
</div>
)} */}
{item.token?.revokedAt && (<div className={Styles.detailRow}>
<span className={Styles.label}>{t('revoked_at')}:</span>
<span className={Styles.value}>{formatDate(item.token.revokedAt)}</span>
</div>)}
</div>
</div>);
})}
</div>
{total && total > 0 && (<div className={Styles.paginationWrapper}>
<Pagination current={currentPage} pageSize={pageSize} total={total} onChange={(page) => setCurrentPage(page)} onShowSizeChange={(current, size) => {
setPageSize(size);
setCurrentPage(1);
}} showSizeChanger showQuickJumper showTotal={(total) => t('pagination_total', { total })} pageSizeOptions={['5', '10', '20', '50', '100']} className={Styles.pagination}/>
</div>)}
</>)}
</div>);
};
export default Records;