Skip to content

Commit

Permalink
feat: info about unlimited projects option
Browse files Browse the repository at this point in the history
  • Loading branch information
Tymek committed Nov 20, 2024
1 parent 3324404 commit 121aaef
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 75 deletions.
Binary file added frontend/src/assets/img/upgradeProjects.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const StyledProjectCardBody = styled(Box)(({ theme }) => ({
flexFlow: 'column',
justifyContent: 'space-between',
height: '100%',
position: 'relative',
}));

export const StyledDivHeader = styled('div')(({ theme }) => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ interface IProjectCardFooterProps {
isFavorite?: boolean;
children?: React.ReactNode;
disabled?: boolean;
owners: IProjectOwnersProps['owners'];
owners?: IProjectOwnersProps['owners'];
}

const StyledFooter = styled(Box)<{ disabled: boolean }>(
Expand All @@ -34,7 +34,7 @@ export const ProjectCardFooter: FC<IProjectCardFooterProps> = ({
}) => {
return (
<StyledFooter disabled={disabled}>
<ProjectOwners owners={owners} />
{owners ? <ProjectOwners owners={owners} /> : null}
{children}
</StyledFooter>
);
Expand Down
110 changes: 110 additions & 0 deletions frontend/src/component/project/ProjectCard/UpgradeProjectCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { IconButton, styled, Tooltip, Typography } from '@mui/material';
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
import CloseIcon from '@mui/icons-material/Close';
import { StyledProjectCard, StyledProjectCardBody } from './ProjectCard.styles';
import { ProjectCardFooter } from './ProjectCardFooter/ProjectCardFooter';
import upgradeProjects from 'assets/img/upgradeProjects.png';
import { formatAssetPath } from 'utils/formatPath';
import { useLocalStorageState } from 'hooks/useLocalStorageState';

const StyledFooter = styled('div')(({ theme }) => ({
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
padding: theme.spacing(0.5, 1, 0.5, 2),
height: 53,
}));

const StyledCloseButton = styled(IconButton)(({ theme }) => ({
position: 'absolute',
top: theme.spacing(0.75),
right: theme.spacing(0.75),
}));

const StyledInfo = styled('a')(({ theme }) => ({
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
gap: theme.spacing(1),
textDecoration: 'none',
color: 'inherit',
height: '100%',
paddingTop: theme.spacing(0.5),
}));

const StyledImage = styled('img')(({ theme }) => ({
width: 95,
margin: theme.spacing(1),
}));

export const UpgradeProjectCard = () => {
const [moreProjectsUpgrade, setMoreProjectsUpgrade] = useLocalStorageState<
'open' | 'closed'
>('upgrade-projects:v1', 'open');

if (moreProjectsUpgrade === 'closed') {
return null;
}

const onDismiss = () => {
setMoreProjectsUpgrade('closed');
};

return (
<StyledProjectCard>
<StyledProjectCardBody>
<Tooltip title='Dismiss' arrow>
<StyledCloseButton
aria-label='dismiss'
onClick={onDismiss}
size='small'
>
<CloseIcon fontSize='inherit' />
</StyledCloseButton>
</Tooltip>
<StyledInfo
href='https://www.getunleash.io/upgrade-unleash?utm_source=environments'
target='_blank'
>
<Typography component='span' fontWeight='bold'>
More{' '}
<Typography
component='span'
color='secondary'
fontWeight='bold'
>
projects
</Typography>{' '}
<br />
easy collaboration
</Typography>
<StyledImage
src={formatAssetPath(upgradeProjects)}
alt='Upgrade environments'
/>
</StyledInfo>
</StyledProjectCardBody>
<ProjectCardFooter>
<StyledFooter>
<Typography
variant='body2'
color='text.secondary'
lineHeight={1.2}
>
Get unlimited projects, and scale Unleash in your
organization
</Typography>
<IconButton
color='primary'
href='https://www.getunleash.io/upgrade-unleash?utm_source=environments'
target='_blank'
>
<ArrowForwardIcon />
</IconButton>
</StyledFooter>
</ProjectCardFooter>
</StyledProjectCard>
);
};
58 changes: 9 additions & 49 deletions frontend/src/component/project/ProjectList/ProjectGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,14 @@
import type { ComponentType, ReactNode } from 'react';
import { Link } from 'react-router-dom';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { ProjectCard as NewProjectCard } from '../ProjectCard/ProjectCard';
import { ProjectCard as DefaultProjectCard } from '../ProjectCard/ProjectCard';
import type { ProjectSchema } from 'openapi';
import loadingData from './loadingData';
import { TablePlaceholder } from 'component/common/Table';
import { styled, Typography } from '@mui/material';
import { styled } from '@mui/material';
import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
import { flexColumn } from 'themes/themeStyles';

const StyledContainer = styled('article')(({ theme }) => ({
...flexColumn,
gap: theme.spacing(2),
}));

const StyledHeaderContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column-reverse',
gap: theme.spacing(2),
[theme.breakpoints.up('md')]: {
flexDirection: 'row',
alignItems: 'flex-end',
},
}));

const StyledHeaderTitle = styled('div')(() => ({
flexGrow: 0,
}));
import { UpgradeProjectCard } from '../ProjectCard/UpgradeProjectCard';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';

const StyledGridContainer = styled('div')(({ theme }) => ({
display: 'grid',
Expand Down Expand Up @@ -56,41 +38,18 @@ type ProjectGroupProps = {
};

export const ProjectGroup = ({
sectionTitle,
sectionSubtitle,
HeaderActions,
projects,
loading,
placeholder = 'No projects available.',
ProjectCardComponent,
link = true,
}: ProjectGroupProps) => {
const ProjectCard = ProjectCardComponent ?? NewProjectCard;
const ProjectCard = ProjectCardComponent ?? DefaultProjectCard;
const { isOss } = useUiConfig();
const { searchQuery } = useSearchHighlightContext();

return (
<StyledContainer>
<StyledHeaderContainer>
<StyledHeaderTitle>
<ConditionallyRender
condition={Boolean(sectionTitle)}
show={
<Typography component='h2' variant='h2'>
{sectionTitle}
</Typography>
}
/>
<ConditionallyRender
condition={Boolean(sectionSubtitle)}
show={
<Typography variant='body2' color='text.secondary'>
{sectionSubtitle}
</Typography>
}
/>
</StyledHeaderTitle>
{HeaderActions}
</StyledHeaderContainer>
<>
<ConditionallyRender
condition={projects.length < 1 && !loading}
show={
Expand Down Expand Up @@ -157,9 +116,10 @@ export const ProjectGroup = ({
</>
)}
/>
{isOss() ? <UpgradeProjectCard /> : null}
</StyledGridContainer>
}
/>
</StyledContainer>
</>
);
};
64 changes: 40 additions & 24 deletions frontend/src/component/project/ProjectList/ProjectList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { ProjectCreationButton } from './ProjectCreationButton/ProjectCreationBu
import { useGroupedProjects } from './hooks/useGroupedProjects';
import { useProjectsSearchAndSort } from './hooks/useProjectsSearchAndSort';
import { ProjectArchiveLink } from './ProjectArchiveLink/ProjectArchiveLink';
import { ProjectsListHeader } from './ProjectsListHeader/ProjectsListHeader';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';

const StyledApiError = styled(ApiError)(({ theme }) => ({
maxWidth: '500px',
Expand All @@ -30,6 +32,7 @@ const StyledContainer = styled('div')(({ theme }) => ({

export const ProjectList = () => {
const { projects, loading, error, refetch } = useProjects();
const { isOss } = useUiConfig();

const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));

Expand Down Expand Up @@ -63,7 +66,7 @@ export const ProjectList = () => {
actions={
<>
<ConditionallyRender
condition={!isSmallScreen}
condition={!isOss && !isSmallScreen}
show={
<>
<Search
Expand All @@ -88,7 +91,7 @@ export const ProjectList = () => {
}
>
<ConditionallyRender
condition={isSmallScreen}
condition={!isOss() && isSmallScreen}
show={
<Search
initialValue={state.query || ''}
Expand All @@ -110,29 +113,42 @@ export const ProjectList = () => {
)}
/>
<SearchHighlightProvider value={state.query || ''}>
<ProjectGroup
sectionTitle='My projects'
sectionSubtitle='Favorite projects, projects you own, and projects you are a member of'
HeaderActions={
<ProjectsListSort
sortBy={state.sortBy}
setSortBy={(sortBy) =>
setState({
sortBy: sortBy as typeof state.sortBy,
})
}
<div>
<ProjectsListHeader
subtitle='Favorite projects, projects you own, and projects you are a member of'
actions={
<ProjectsListSort
sortBy={state.sortBy}
setSortBy={(sortBy) =>
setState({
sortBy: sortBy as typeof state.sortBy,
})
}
/>
}
>
My projects
</ProjectsListHeader>
<ProjectGroup
loading={loading}
projects={
isOss()
? sortedProjects
: groupedProjects.myProjects
}
/>
</div>
{!isOss() ? (
<div>
<ProjectsListHeader subtitle='Projects in Unleash that you have access to.'>
Other projects
</ProjectsListHeader>
<ProjectGroup
loading={loading}
projects={groupedProjects.otherProjects}
/>
}
loading={loading}
projects={groupedProjects.myProjects}
/>

<ProjectGroup
sectionTitle='Other projects'
sectionSubtitle='Projects in Unleash that you have access to.'
loading={loading}
projects={groupedProjects.otherProjects}
/>
</div>
) : null}
</SearchHighlightProvider>
</StyledContainer>
</PageContent>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { styled, Typography } from '@mui/material';
import type { FC, ReactNode } from 'react';

type ProjectsListHeaderProps = {
children?: ReactNode;
subtitle?: string;
actions?: ReactNode;
};

const StyledHeaderContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column-reverse',
gap: theme.spacing(2),
[theme.breakpoints.up('md')]: {
flexDirection: 'row',
alignItems: 'flex-end',
},
marginBottom: theme.spacing(2),
}));

const StyledHeaderTitle = styled('div')(() => ({
flexGrow: 0,
}));

export const ProjectsListHeader: FC<ProjectsListHeaderProps> = ({
children,
subtitle,
actions,
}) => {
return (
<StyledHeaderContainer>
<StyledHeaderTitle>
{children ? (
<Typography component='h2' variant='h2'>
{children}
</Typography>
) : null}
{subtitle ? (
<Typography variant='body2' color='text.secondary'>
{subtitle}
</Typography>
) : null}
</StyledHeaderTitle>
{actions}
</StyledHeaderContainer>
);
};

0 comments on commit 121aaef

Please sign in to comment.