From 3ade6099562236ce1282297447256ffd7a677ee5 Mon Sep 17 00:00:00 2001 From: Mateusz Kwasniewski Date: Fri, 12 Jul 2024 15:39:37 +0200 Subject: [PATCH] feat: user seats component (#7583) --- .../UserSeats/UserSeats.test.tsx | 40 ++++++++++++ .../componentsStat/UserSeats/UserSeats.tsx | 62 +++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 frontend/src/component/insights/componentsStat/UserSeats/UserSeats.test.tsx create mode 100644 frontend/src/component/insights/componentsStat/UserSeats/UserSeats.tsx diff --git a/frontend/src/component/insights/componentsStat/UserSeats/UserSeats.test.tsx b/frontend/src/component/insights/componentsStat/UserSeats/UserSeats.test.tsx new file mode 100644 index 0000000000..8cfc96cabc --- /dev/null +++ b/frontend/src/component/insights/componentsStat/UserSeats/UserSeats.test.tsx @@ -0,0 +1,40 @@ +import { testServerRoute, testServerSetup } from '../../../../utils/testServer'; +import { screen } from '@testing-library/react'; +import { render } from 'utils/testRenderer'; +import { UserSeats } from './UserSeats'; + +const server = testServerSetup(); +const user1 = {}; +const user2 = {}; + +const setupApiWithSeats = (seats: number | undefined) => { + testServerRoute(server, '/api/admin/user-admin', { + users: [user1, user2], + }); + testServerRoute(server, '/api/instance/status', { + plan: 'Enterprise', + seats, + }); + testServerRoute(server, '/api/admin/ui-config', { + flags: { + UNLEASH_CLOUD: true, + }, + }); +}; + +test('User seats display when seats are available', async () => { + setupApiWithSeats(20); + + render(); + + await screen.findByText('User seats'); + await screen.findByText('2/20 seats used'); +}); + +test('User seats does not display when seats are not available', async () => { + setupApiWithSeats(undefined); + + render(); + + expect(screen.queryByText('User seats')).not.toBeInTheDocument(); +}); diff --git a/frontend/src/component/insights/componentsStat/UserSeats/UserSeats.tsx b/frontend/src/component/insights/componentsStat/UserSeats/UserSeats.tsx new file mode 100644 index 0000000000..bf79caec9e --- /dev/null +++ b/frontend/src/component/insights/componentsStat/UserSeats/UserSeats.tsx @@ -0,0 +1,62 @@ +import LicenseIcon from '@mui/icons-material/ReceiptLongOutlined'; +import { Box, styled, Typography } from '@mui/material'; +import LinearProgress from '@mui/material/LinearProgress'; +import { useUsers } from 'hooks/api/getters/useUsers/useUsers'; +import { useInstanceStatus } from 'hooks/api/getters/useInstanceStatus/useInstanceStatus'; + +const SeatsUsageBar = styled(LinearProgress)(({ theme }) => ({ + marginTop: theme.spacing(0.5), + height: theme.spacing(0.5), + borderRadius: theme.shape.borderRadiusMedium, +})); + +const TotalSeatsRow = styled(Box)(({ theme }) => ({ + display: 'flex', + gap: 1, + alignItems: 'center', +})); + +const TotalSeats = styled(Typography)(({ theme }) => ({ + fontWeight: theme.typography.fontWeightBold, + fontSize: theme.typography.h1.fontSize, + color: theme.palette.primary.main, +})); + +const SeatsUsageRow = styled(Box)(({ theme }) => ({ + marginTop: theme.spacing(2), +})); + +const SeatsUsageText = styled(Box)(({ theme }) => ({ + textAlign: 'right', +})); + +export const UserSeats = () => { + const { users } = useUsers(); + const { instanceStatus } = useInstanceStatus(); + const seats = instanceStatus?.seats; + + if (typeof seats === 'number') { + const percentageSeats = Math.floor((users.length / seats) * 100); + + return ( + + + + User seats + {seats} + + + + {users.length}/{seats} seats used + + + + + ); + } + + return null; +};