feat: show usage alert as of threshold
This commit is contained in:
@@ -12,6 +12,7 @@ import AccountCircleIcon from '@mui/icons-material/AccountCircle';
|
||||
|
||||
import * as URLS from 'config/urls';
|
||||
import AccountDropdownMenu from 'components/AccountDropdownMenu';
|
||||
import UsageAlert from 'components/UsageAlert/index.ee';
|
||||
import Container from 'components/Container';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Link } from './style';
|
||||
@@ -81,6 +82,8 @@ export default function AppBar(props: AppBarProps): React.ReactElement {
|
||||
</Toolbar>
|
||||
</Container>
|
||||
|
||||
<UsageAlert />
|
||||
|
||||
<AccountDropdownMenu
|
||||
anchorEl={accountMenuAnchorElement}
|
||||
id={accountMenuId}
|
||||
|
57
packages/web/src/components/UsageAlert/index.ee.tsx
Normal file
57
packages/web/src/components/UsageAlert/index.ee.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import * as React from 'react';
|
||||
import Alert from '@mui/material/Alert';
|
||||
import Snackbar from '@mui/material/Snackbar';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import Button from '@mui/material/Button';
|
||||
import LinearProgress from '@mui/material/LinearProgress';
|
||||
|
||||
import useFormatMessage from 'hooks/useFormatMessage';
|
||||
import useUsageAlert from 'hooks/useUsageAlert.ee';
|
||||
|
||||
const LinkBehavior = React.forwardRef<any>(
|
||||
(props, ref) => <a ref={ref} target="_blank" {...props} role={undefined} />,
|
||||
);
|
||||
|
||||
export default function UsageAlert() {
|
||||
const formatMessage = useFormatMessage();
|
||||
const usageAlert = useUsageAlert();
|
||||
|
||||
if (!usageAlert.showAlert) return (<React.Fragment />);
|
||||
|
||||
return (
|
||||
<Snackbar
|
||||
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
|
||||
open
|
||||
>
|
||||
<Alert
|
||||
icon={false}
|
||||
sx={{ fontWeight: 500, minWidth: 410 }}
|
||||
severity={usageAlert.hasExceededLimit ? 'error' : 'warning'}
|
||||
>
|
||||
<Stack direction="row" gap={4} mb={1}>
|
||||
<Typography
|
||||
variant="subtitle2"
|
||||
sx={{ display: 'flex', alignItems: 'center' }}
|
||||
>
|
||||
{usageAlert.alertMessage}
|
||||
</Typography>
|
||||
|
||||
<Button
|
||||
component={LinkBehavior}
|
||||
size="small"
|
||||
href={usageAlert.url}
|
||||
sx={{ minWidth: 100 }}
|
||||
>
|
||||
{formatMessage('usageAlert.viewPlans')}
|
||||
</Button>
|
||||
</Stack>
|
||||
|
||||
<LinearProgress
|
||||
variant="determinate"
|
||||
value={usageAlert.consumptionPercentage}
|
||||
/>
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
);
|
||||
}
|
@@ -7,6 +7,7 @@ const config: Config = {
|
||||
graphqlUrl: process.env.REACT_APP_GRAPHQL_URL as string,
|
||||
notificationsUrl: process.env.REACT_APP_NOTIFICATIONS_URL as string,
|
||||
chatwootBaseUrl: 'https://app.chatwoot.com',
|
||||
supportEmailAddress: 'support@automatisch.io'
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
46
packages/web/src/hooks/useUsageAlert.ee.ts
Normal file
46
packages/web/src/hooks/useUsageAlert.ee.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import useFormatMessage from './useFormatMessage';
|
||||
import useUsageData from './useUsageData.ee';
|
||||
import usePaymentPortalUrl from './usePaymentPortalUrl.ee';
|
||||
|
||||
type UseUsageAlertReturn = {
|
||||
showAlert: boolean;
|
||||
hasExceededLimit?: boolean;
|
||||
alertMessage?: string;
|
||||
url?: string;
|
||||
consumptionPercentage?: number;
|
||||
};
|
||||
|
||||
export default function useUsageAlert(): UseUsageAlertReturn {
|
||||
const { url, loading: paymentPortalUrlLoading } = usePaymentPortalUrl();
|
||||
const {
|
||||
allowedTaskCount,
|
||||
consumedTaskCount,
|
||||
nextResetAt,
|
||||
loading: usageDataLoading
|
||||
} = useUsageData();
|
||||
const formatMessage = useFormatMessage();
|
||||
|
||||
if (paymentPortalUrlLoading || usageDataLoading) {
|
||||
return { showAlert: false };
|
||||
}
|
||||
|
||||
const hasLoaded = !paymentPortalUrlLoading || usageDataLoading;
|
||||
const withinUsageThreshold = consumedTaskCount > allowedTaskCount * 0.7;
|
||||
const consumptionPercentage = consumedTaskCount / allowedTaskCount * 100;
|
||||
const showAlert = hasLoaded && withinUsageThreshold;
|
||||
const hasExceededLimit = consumedTaskCount >= allowedTaskCount;
|
||||
|
||||
const alertMessage = formatMessage('usageAlert.informationText', {
|
||||
allowedTaskCount,
|
||||
consumedTaskCount,
|
||||
relativeResetDate: nextResetAt?.toRelative(),
|
||||
});
|
||||
|
||||
return {
|
||||
showAlert,
|
||||
hasExceededLimit,
|
||||
alertMessage,
|
||||
consumptionPercentage,
|
||||
url,
|
||||
};
|
||||
}
|
@@ -136,5 +136,7 @@
|
||||
"resetPasswordForm.submit": "Reset password",
|
||||
"resetPasswordForm.passwordFieldLabel": "Password",
|
||||
"resetPasswordForm.confirmPasswordFieldLabel": "Confirm password",
|
||||
"resetPasswordForm.passwordUpdated": "The password has been updated. Now, you can login."
|
||||
}
|
||||
"resetPasswordForm.passwordUpdated": "The password has been updated. Now, you can login.",
|
||||
"usageAlert.informationText": "Tasks: {consumedTaskCount}/{allowedTaskCount} (Resets {relativeResetDate})",
|
||||
"usageAlert.viewPlans": "View plans"
|
||||
}
|
Reference in New Issue
Block a user