mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-20 00:08:02 +01:00
Refactor premium feature (#2627)
https://linear.app/unleash/issue/2-491/improve-premiumfeature-component-and-how-its-implemented ![image](https://user-images.githubusercontent.com/14320932/206237837-6032c3c0-1e42-4be2-8b6f-223e0204e1b5.png) Refactors `PremiumFeature` to be a bit more straightforward and match new designs, both in standalone and tooltip modes. This also fixes the fact that the change requests tab did not display the premium feature info, along with other smaller fixes. Co-authored-by: Christopher Kolstad <chriswk@getunleash.ai>
This commit is contained in:
parent
fb2c30244c
commit
1be2483e6a
@ -271,7 +271,7 @@ export const ChangeRequestsTabs = ({
|
||||
}
|
||||
elseShow={
|
||||
<TablePlaceholder>
|
||||
None of the changes where submitted yet.
|
||||
None of the changes were submitted yet.
|
||||
</TablePlaceholder>
|
||||
}
|
||||
/>
|
||||
|
@ -5,12 +5,17 @@ import { useProjectNameOrId } from 'hooks/api/getters/useProject/useProject';
|
||||
import { ChangeRequestsTabs } from './ChangeRequestsTabs/ChangeRequestsTabs';
|
||||
import { SortingRule } from 'react-table';
|
||||
import { useProjectChangeRequests } from 'hooks/api/getters/useProjectChangeRequests/useProjectChangeRequests';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||
import { PageHeader } from 'component/common/PageHeader/PageHeader';
|
||||
import { PremiumFeature } from 'component/common/PremiumFeature/PremiumFeature';
|
||||
|
||||
const defaultSort: SortingRule<string> = { id: 'updatedAt', desc: true };
|
||||
|
||||
export const ProjectChangeRequests = () => {
|
||||
const projectId = useRequiredPathParam('projectId');
|
||||
const projectName = useProjectNameOrId(projectId);
|
||||
const { isOss, isPro } = useUiConfig();
|
||||
|
||||
usePageTitle(`Change requests – ${projectName}`);
|
||||
|
||||
@ -21,6 +26,14 @@ export const ProjectChangeRequests = () => {
|
||||
defaultSort
|
||||
);
|
||||
|
||||
if (isOss() || isPro()) {
|
||||
return (
|
||||
<PageContent sx={{ justifyContent: 'center' }}>
|
||||
<PremiumFeature feature="Change Requests" />
|
||||
</PageContent>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ChangeRequestsTabs
|
||||
changeRequests={changeRequests}
|
||||
|
@ -1,86 +1,152 @@
|
||||
import { ReactComponent as ProPlanIcon } from 'assets/icons/pro-enterprise-feature-badge.svg';
|
||||
import { Box, Link, styled, Typography } from '@mui/material';
|
||||
import { Box, Button, Link, styled, Typography } from '@mui/material';
|
||||
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
|
||||
import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender';
|
||||
|
||||
const PremiumFeatureWrapper = styled(Box)(({ theme }) => ({
|
||||
const PremiumFeatureWrapper = styled(Box, {
|
||||
shouldForwardProp: prop => prop !== 'tooltip',
|
||||
})<{ tooltip?: boolean }>(({ theme, tooltip }) => ({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
padding: theme.spacing(1, 0.5),
|
||||
alignItems: tooltip ? 'start' : 'center',
|
||||
textAlign: tooltip ? 'left' : 'center',
|
||||
backgroundColor: tooltip ? 'transparent' : theme.palette.secondaryContainer,
|
||||
borderRadius: tooltip ? 0 : theme.shape.borderRadiusLarge,
|
||||
padding: tooltip ? theme.spacing(1, 0.5) : theme.spacing(7.5, 1),
|
||||
}));
|
||||
|
||||
const StyledTitle = styled(Typography)(({ theme }) => ({
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
fontWeight: theme.fontWeight.bold,
|
||||
fontSize: theme.fontSizes.smallBody,
|
||||
gap: theme.spacing(1),
|
||||
}));
|
||||
|
||||
const StyledBody = styled(Typography)(({ theme }) => ({
|
||||
const StyledBody = styled('div', {
|
||||
shouldForwardProp: prop => prop !== 'tooltip',
|
||||
})<{ tooltip?: boolean }>(({ theme, tooltip }) => ({
|
||||
margin: tooltip ? theme.spacing(1, 0) : theme.spacing(3, 0, 5, 0),
|
||||
}));
|
||||
|
||||
const StyledTypography = styled(Typography)(({ theme }) => ({
|
||||
fontSize: theme.fontSizes.smallBody,
|
||||
margin: theme.spacing(1, 0),
|
||||
}));
|
||||
|
||||
const StyledButtonContainer = styled('div')(() => ({
|
||||
display: 'flex',
|
||||
}));
|
||||
|
||||
const StyledLink = styled(Link)(({ theme }) => ({
|
||||
fontSize: theme.fontSizes.smallBody,
|
||||
width: 'fit-content',
|
||||
}));
|
||||
|
||||
enum FeatureLevelTitle {
|
||||
PRO = 'Pro & Enterprise feature',
|
||||
ENTERPRISE = 'Enterprise feature',
|
||||
enum FeaturePlan {
|
||||
PRO = 'Pro & Enterprise',
|
||||
ENTERPRISE = 'Enterprise',
|
||||
}
|
||||
|
||||
export enum PlausibleOrigin {
|
||||
PROJECT = 'Projects',
|
||||
ACCESS = 'Access',
|
||||
CHANGE_REQUEST = 'Change Request',
|
||||
}
|
||||
const PremiumFeatures = {
|
||||
['Adding new projects']: {
|
||||
plan: FeaturePlan.PRO,
|
||||
url: '',
|
||||
},
|
||||
['Access']: {
|
||||
plan: FeaturePlan.PRO,
|
||||
url: 'https://docs.getunleash.io/reference/rbac',
|
||||
},
|
||||
['Change Requests']: {
|
||||
plan: FeaturePlan.ENTERPRISE,
|
||||
url: 'https://docs.getunleash.io/reference/change-requests',
|
||||
},
|
||||
};
|
||||
|
||||
type PremiumFeature = keyof typeof PremiumFeatures;
|
||||
|
||||
const UPGRADE_URL = 'https://www.getunleash.io/plans';
|
||||
|
||||
export interface PremiumFeatureProps {
|
||||
children: React.ReactNode;
|
||||
origin?: PlausibleOrigin;
|
||||
center?: boolean;
|
||||
enterpriseOnly?: boolean;
|
||||
feature: PremiumFeature;
|
||||
tooltip?: boolean;
|
||||
}
|
||||
|
||||
export const PremiumFeature = ({
|
||||
children,
|
||||
origin,
|
||||
center,
|
||||
enterpriseOnly = false,
|
||||
}: PremiumFeatureProps) => {
|
||||
export const PremiumFeature = ({ feature, tooltip }: PremiumFeatureProps) => {
|
||||
const { url, plan } = PremiumFeatures[feature];
|
||||
|
||||
const tracker = usePlausibleTracker();
|
||||
|
||||
const handleClick = () => {
|
||||
if (origin) {
|
||||
tracker.trackEvent('upgrade_plan_clicked', {
|
||||
props: { origin },
|
||||
});
|
||||
}
|
||||
tracker.trackEvent('upgrade_plan_clicked', {
|
||||
props: { feature },
|
||||
});
|
||||
};
|
||||
|
||||
const featureLabel = Boolean(url) ? (
|
||||
<StyledLink href={url} target="_blank">
|
||||
{feature}
|
||||
</StyledLink>
|
||||
) : (
|
||||
feature
|
||||
);
|
||||
|
||||
const featureMessage = (
|
||||
<>
|
||||
{featureLabel} is a feature available for the{' '}
|
||||
<strong>{plan}</strong>{' '}
|
||||
{plan === FeaturePlan.PRO ? 'plans' : 'plan'}
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<PremiumFeatureWrapper
|
||||
sx={{
|
||||
alignItems: center ? 'center' : 'start',
|
||||
textAlign: center ? 'center' : 'left',
|
||||
}}
|
||||
>
|
||||
<PremiumFeatureWrapper tooltip={tooltip}>
|
||||
<StyledTitle>
|
||||
<ProPlanIcon />
|
||||
{enterpriseOnly
|
||||
? FeatureLevelTitle.ENTERPRISE
|
||||
: FeatureLevelTitle.PRO}
|
||||
{`${plan} feature`}
|
||||
</StyledTitle>
|
||||
<StyledBody>{children}</StyledBody>
|
||||
<StyledLink
|
||||
href={'https://www.getunleash.io/plans'}
|
||||
target="_blank"
|
||||
onClick={handleClick}
|
||||
>
|
||||
Upgrade now
|
||||
</StyledLink>
|
||||
<ConditionallyRender
|
||||
condition={Boolean(tooltip)}
|
||||
show={
|
||||
<>
|
||||
<StyledBody tooltip>
|
||||
<StyledTypography>
|
||||
{featureMessage}. You need to upgrade your plan
|
||||
if you want to use it
|
||||
</StyledTypography>
|
||||
</StyledBody>
|
||||
<StyledButtonContainer>
|
||||
<StyledLink
|
||||
href={UPGRADE_URL}
|
||||
target="_blank"
|
||||
onClick={handleClick}
|
||||
>
|
||||
Upgrade now
|
||||
</StyledLink>
|
||||
</StyledButtonContainer>
|
||||
</>
|
||||
}
|
||||
elseShow={
|
||||
<>
|
||||
<StyledBody>
|
||||
<StyledTypography>
|
||||
{featureMessage}
|
||||
</StyledTypography>
|
||||
<StyledTypography>
|
||||
You need to upgrade your plan if you want to use
|
||||
it
|
||||
</StyledTypography>
|
||||
</StyledBody>
|
||||
<StyledButtonContainer>
|
||||
<Button
|
||||
variant="outlined"
|
||||
href={UPGRADE_URL}
|
||||
target="_blank"
|
||||
onClick={handleClick}
|
||||
>
|
||||
Upgrade now
|
||||
</Button>
|
||||
</StyledButtonContainer>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</PremiumFeatureWrapper>
|
||||
);
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useContext } from 'react';
|
||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
import { Alert, Link, styled } from '@mui/material';
|
||||
import { Alert } from '@mui/material';
|
||||
import { PageHeader } from 'component/common/PageHeader/PageHeader';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
import { UPDATE_PROJECT } from 'component/providers/AccessProvider/permissions';
|
||||
@ -9,15 +9,8 @@ import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
||||
import { usePageTitle } from 'hooks/usePageTitle';
|
||||
import { useProjectNameOrId } from 'hooks/api/getters/useProject/useProject';
|
||||
import { ChangeRequestTable } from './ChangeRequestTable';
|
||||
import {
|
||||
PlausibleOrigin,
|
||||
PremiumFeature,
|
||||
} from 'component/common/PremiumFeature/PremiumFeature';
|
||||
|
||||
const StyledLink = styled(Link)(({ theme }) => ({
|
||||
fontSize: theme.fontSizes.smallBody,
|
||||
width: 'fit-content',
|
||||
}));
|
||||
import { PremiumFeature } from 'component/common/PremiumFeature/PremiumFeature';
|
||||
import { ChangeRequestProcessHelp } from './ChangeRequestProcessHelp/ChangeRequestProcessHelp';
|
||||
|
||||
export const ChangeRequestConfiguration = () => {
|
||||
const projectId = useRequiredPathParam('projectId');
|
||||
@ -25,37 +18,29 @@ export const ChangeRequestConfiguration = () => {
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
const { isOss, isPro } = useUiConfig();
|
||||
|
||||
usePageTitle(`Project change request – ${projectName}`);
|
||||
usePageTitle(`Project change request configuration – ${projectName}`);
|
||||
|
||||
if (isOss() || isPro()) {
|
||||
return (
|
||||
<PageContent
|
||||
header={<PageHeader title="Change request configuration" />}
|
||||
header={
|
||||
<PageHeader
|
||||
titleElement="Change request configuration"
|
||||
actions={<ChangeRequestProcessHelp />}
|
||||
/>
|
||||
}
|
||||
sx={{ justifyContent: 'center' }}
|
||||
>
|
||||
<PremiumFeature
|
||||
origin={PlausibleOrigin.CHANGE_REQUEST}
|
||||
enterpriseOnly
|
||||
center
|
||||
>
|
||||
<>
|
||||
If you want to use{' '}
|
||||
<StyledLink
|
||||
href={'https://www.getunleash.io/plans'} // TODO: Add link to change request docs when available
|
||||
target="_blank"
|
||||
>
|
||||
"Change Requests"
|
||||
</StyledLink>{' '}
|
||||
you will need to upgrade to Enterprise plan
|
||||
</>
|
||||
</PremiumFeature>
|
||||
<PremiumFeature feature="Change Requests" />
|
||||
</PageContent>
|
||||
);
|
||||
}
|
||||
|
||||
if (!hasAccess(UPDATE_PROJECT, projectId)) {
|
||||
return (
|
||||
<PageContent header={<PageHeader title="Project access" />}>
|
||||
<PageContent
|
||||
header={<PageHeader title="Change request configuration" />}
|
||||
>
|
||||
<Alert severity="error">
|
||||
You need project owner permissions to access this section.
|
||||
</Alert>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useContext } from 'react';
|
||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
import { Alert, Box, Link, styled } from '@mui/material';
|
||||
import { Alert } from '@mui/material';
|
||||
import { PageHeader } from 'component/common/PageHeader/PageHeader';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
import { UPDATE_PROJECT } from 'component/providers/AccessProvider/permissions';
|
||||
@ -9,15 +9,7 @@ import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
||||
import { usePageTitle } from 'hooks/usePageTitle';
|
||||
import { ProjectAccessTable } from 'component/project/ProjectAccess/ProjectAccessTable/ProjectAccessTable';
|
||||
import { useProjectNameOrId } from 'hooks/api/getters/useProject/useProject';
|
||||
import {
|
||||
PlausibleOrigin,
|
||||
PremiumFeature,
|
||||
} from 'component/common/PremiumFeature/PremiumFeature';
|
||||
|
||||
const StyledLink = styled(Link)(({ theme }) => ({
|
||||
fontSize: theme.fontSizes.smallBody,
|
||||
width: 'fit-content',
|
||||
}));
|
||||
import { PremiumFeature } from 'component/common/PremiumFeature/PremiumFeature';
|
||||
|
||||
export const ProjectAccess = () => {
|
||||
const projectId = useRequiredPathParam('projectId');
|
||||
@ -28,37 +20,18 @@ export const ProjectAccess = () => {
|
||||
|
||||
if (isOss()) {
|
||||
return (
|
||||
<PageContent header={<PageHeader title="Project access" />}>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'inline-flex',
|
||||
maxWidth: '50%',
|
||||
margin: '0 25%',
|
||||
}}
|
||||
alignSelf={'center'}
|
||||
>
|
||||
<PremiumFeature origin={PlausibleOrigin.ACCESS} center>
|
||||
<>
|
||||
Controlling access to projects requires a paid
|
||||
version of Unleash. Check out{' '}
|
||||
<StyledLink
|
||||
href="https://www.getunleash.io"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
getunleash.io
|
||||
</StyledLink>{' '}
|
||||
to find out more.
|
||||
</>
|
||||
</PremiumFeature>
|
||||
</Box>
|
||||
<PageContent
|
||||
header={<PageHeader title="Access" />}
|
||||
sx={{ justifyContent: 'center' }}
|
||||
>
|
||||
<PremiumFeature feature="Access" />
|
||||
</PageContent>
|
||||
);
|
||||
}
|
||||
|
||||
if (!hasAccess(UPDATE_PROJECT, projectId)) {
|
||||
return (
|
||||
<PageContent header={<PageHeader title="Project access" />}>
|
||||
<PageContent header={<PageHeader title="Access" />}>
|
||||
<Alert severity="error">
|
||||
You need project owner permissions to access this section.
|
||||
</Alert>
|
||||
|
@ -20,10 +20,7 @@ import { TablePlaceholder } from 'component/common/Table';
|
||||
import { useMediaQuery } from '@mui/material';
|
||||
import theme from 'themes/theme';
|
||||
import { Search } from 'component/common/Search/Search';
|
||||
import {
|
||||
PlausibleOrigin,
|
||||
PremiumFeature,
|
||||
} from 'component/common/PremiumFeature/PremiumFeature';
|
||||
import { PremiumFeature } from 'component/common/PremiumFeature/PremiumFeature';
|
||||
import { ITooltipResolverProps } from 'component/common/TooltipResolver/TooltipResolver';
|
||||
import { ReactComponent as ProPlanIcon } from 'assets/icons/pro-enterprise-feature-badge.svg';
|
||||
|
||||
@ -48,10 +45,7 @@ function resolveCreateButtonData(
|
||||
disabled: true,
|
||||
tooltip: {
|
||||
titleComponent: (
|
||||
<PremiumFeature origin={PlausibleOrigin.PROJECT}>
|
||||
To be able to add more projects you need to upgrade to
|
||||
Pro or Enterprise plan
|
||||
</PremiumFeature>
|
||||
<PremiumFeature feature="Adding new projects" tooltip />
|
||||
),
|
||||
sx: { maxWidth: '320px' },
|
||||
variant: 'custom',
|
||||
|
Loading…
Reference in New Issue
Block a user