feat(company): add expiry warning banner, route wrapper, and conditional UI for expired companies
- Add CompanyExpireWarning component to layout header for expiring subscription alerts - Add CompanyExpire wrapper to guard rules and data-source routes - Refactor CompanyExpireGuard to support optional fullscreen mode via prop - Add responsive Popover support to VoiceCheck for mobile breakpoints - Hide rule CRUD action buttons when company validity is expired - Update profile page to display expiry status alongside validity date - Update i18n strings for clearer expiry messaging Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,17 @@
|
||||
import { ChromeOutlined, SoundOutlined } from '@ant-design/icons';
|
||||
import { useBreakpoint } from '@ant-design/pro-components';
|
||||
import { getLocale, Icon } from '@umijs/max';
|
||||
import { Alert, Divider, Image, Modal, Space, Tabs, Typography } from 'antd';
|
||||
import {
|
||||
Alert,
|
||||
Divider,
|
||||
Flex,
|
||||
Image,
|
||||
Modal,
|
||||
Popover,
|
||||
Space,
|
||||
Tabs,
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import useRichI18n from '@/hooks/useRichI18n';
|
||||
import { checkAudioPermission } from '@/utils';
|
||||
@@ -8,9 +19,9 @@ import bus from '@/utils/eventBus';
|
||||
import { $t } from '@/utils/i18n';
|
||||
|
||||
const { Paragraph } = Typography;
|
||||
const ChangePassTips: React.FC = () => {
|
||||
const VoiceCheck: React.FC = () => {
|
||||
const { richFormat } = useRichI18n();
|
||||
|
||||
const screens = useBreakpoint();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [hasAudioPermission, setHasAudioPermission] = useState(true);
|
||||
|
||||
@@ -69,25 +80,46 @@ const ChangePassTips: React.FC = () => {
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const tipsNode = (
|
||||
<>
|
||||
<Alert
|
||||
message={$t('pages.voiceCheck.alertMessage')}
|
||||
type="warning"
|
||||
showIcon
|
||||
/>
|
||||
</>
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<Space align="center" onClick={() => setVisible(true)}>
|
||||
{!hasAudioPermission && (
|
||||
<>
|
||||
<Alert
|
||||
message={$t('pages.voiceCheck.alertMessage')}
|
||||
type="warning"
|
||||
showIcon
|
||||
/>
|
||||
<Icon
|
||||
icon="local:silence"
|
||||
height="20px"
|
||||
fill="#f59e0b"
|
||||
className="flex align-center"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<Flex align="center" onClick={() => setVisible(true)}>
|
||||
{!hasAudioPermission &&
|
||||
(['xs', 'sm'].includes(screens || '') ? (
|
||||
<Popover
|
||||
content={tipsNode}
|
||||
styles={{
|
||||
body: { padding: 0 },
|
||||
}}
|
||||
zIndex={999}
|
||||
defaultOpen={true}
|
||||
>
|
||||
<Icon
|
||||
icon="local:silence"
|
||||
height="20px"
|
||||
fill="#f59e0b"
|
||||
className="flex align-center"
|
||||
/>
|
||||
</Popover>
|
||||
) : (
|
||||
<>
|
||||
{tipsNode}
|
||||
<Icon
|
||||
icon="local:silence"
|
||||
height="20px"
|
||||
fill="#f59e0b"
|
||||
className="flex align-center"
|
||||
/>
|
||||
</>
|
||||
))}
|
||||
{/* {hasAudioPermission ? (
|
||||
<Icon
|
||||
icon="local:voice"
|
||||
@@ -103,7 +135,7 @@ const ChangePassTips: React.FC = () => {
|
||||
className="flex align-center"
|
||||
/>
|
||||
)} */}
|
||||
</Space>
|
||||
</Flex>
|
||||
|
||||
<Modal
|
||||
title={
|
||||
@@ -154,4 +186,4 @@ const ChangePassTips: React.FC = () => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default ChangePassTips;
|
||||
export default VoiceCheck;
|
||||
|
||||
Reference in New Issue
Block a user