Skip to content

Commit

Permalink
feat: onboarding can be now closed (#8215)
Browse files Browse the repository at this point in the history
The boxes were merged and now the whole thing can be closed.


![image](https://github.com/user-attachments/assets/45ec680f-64df-4877-92cb-33fef506f0ad)
  • Loading branch information
sjaanus authored Sep 23, 2024
1 parent f45b7a0 commit 9f5e909
Show file tree
Hide file tree
Showing 5 changed files with 223 additions and 236 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,18 @@ import { useDefaultColumnVisibility } from './hooks/useDefaultColumnVisibility';
import { TableEmptyState } from './TableEmptyState/TableEmptyState';
import { useRowActions } from './hooks/useRowActions';
import { useSelectedData } from './hooks/useSelectedData';
import { FeatureOverviewCell } from '../../../common/Table/cells/FeatureOverviewCell/FeatureOverviewCell';
import { FeatureOverviewCell } from 'component/common/Table/cells/FeatureOverviewCell/FeatureOverviewCell';
import {
useProjectFeatureSearch,
useProjectFeatureSearchActions,
} from './useProjectFeatureSearch';
import { AvatarCell } from './AvatarCell';
import { ProjectOnboarding } from './ProjectOnboarding/ProjectOnboarding';
import { useUiFlag } from 'hooks/useUiFlag';
import { styled } from '@mui/material';
import useProjectOverview from 'hooks/api/getters/useProjectOverview/useProjectOverview';
import { ConnectSdkDialog } from '../../../onboarding/ConnectSdkDialog';
import { ProjectOnboarding } from './ProjectOnboarding/ProjectOnboarding';
import { useLocalStorageState } from 'hooks/useLocalStorageState';

interface IPaginatedProjectFeatureTogglesProps {
environments: string[];
Expand Down Expand Up @@ -114,12 +115,19 @@ export const ProjectFeatureToggles = ({

const isPlaceholder = Boolean(initialLoad || (loading && total));

const [onboardingFlow, setOnboardingFlow] = useLocalStorageState<
'visible' | 'closed'
>(`onboarding-flow:v1-${projectId}`, 'visible');

const notOnboarding =
!onboardingUIEnabled ||
(onboardingUIEnabled &&
project.onboardingStatus.status === 'onboarded');
project.onboardingStatus.status === 'onboarded') ||
onboardingFlow === 'closed';
const isOnboarding =
onboardingUIEnabled && project.onboardingStatus.status !== 'onboarded';
onboardingUIEnabled &&
project.onboardingStatus.status !== 'onboarded' &&
onboardingFlow === 'visible';
const showFeaturesTable =
(total !== undefined && total > 0) || notOnboarding;

Expand Down Expand Up @@ -413,6 +421,7 @@ export const ProjectFeatureToggles = ({
<ProjectOnboarding
projectId={projectId}
setConnectSdkOpen={setConnectSdkOpen}
setOnboardingFlow={setOnboardingFlow}
/>
}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { render } from 'utils/testRenderer';
import { Route, Routes } from 'react-router-dom';
import { testServerRoute, testServerSetup } from 'utils/testServer';
import { WelcomeToProject } from './WelcomeToProject';
import { ProjectOnboarding } from './ProjectOnboarding';
import { screen } from '@testing-library/react';

const server = testServerSetup();
Expand All @@ -18,9 +18,10 @@ test('Project can start onboarding', async () => {
<Route
path={'/projects/:projectId'}
element={
<WelcomeToProject
<ProjectOnboarding
projectId={projectId}
setConnectSdkOpen={() => {}}
setOnboardingFlow={() => {}}
/>
}
/>
Expand All @@ -45,9 +46,10 @@ test('Project can connect SDK', async () => {
<Route
path={'/projects/:projectId'}
element={
<WelcomeToProject
<ProjectOnboarding
projectId={projectId}
setConnectSdkOpen={() => {}}
setOnboardingFlow={() => {}}
/>
}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,204 @@
import { styled } from '@mui/material';
import { WelcomeToProject } from './WelcomeToProject';
import { IconButton, styled, Tooltip, Typography } from '@mui/material';
import Add from '@mui/icons-material/Add';
import { CREATE_FEATURE } from 'component/providers/AccessProvider/permissions';
import { FlagCreationButton } from '../ProjectFeatureTogglesHeader/ProjectFeatureTogglesHeader';
import ResponsiveButton from 'component/common/ResponsiveButton/ResponsiveButton';
import useProjectOverview from 'hooks/api/getters/useProjectOverview/useProjectOverview';
import { SdkExample } from './SdkExample';
import CloseIcon from '@mui/icons-material/Close';

interface IProjectOnboardingProps {
projectId: string;
setConnectSdkOpen: (open: boolean) => void;
setOnboardingFlow: (status: 'visible' | 'closed') => void;
}

interface ICreateFlagProps {
projectId: string;
}

const Container = styled('div')(({ theme }) => ({
display: 'flex',
width: '100%',
flexDirection: 'column',
backgroundColor: theme.palette.background.paper,
flexBasis: '70%',
borderRadius: theme.shape.borderRadiusLarge,
}));

const TitleBox = styled('div')(({ theme }) => ({
padding: theme.spacing(2, 7, 2, 7),
borderBottom: '1px solid',
borderColor: theme.palette.divider,
minHeight: '80px',
}));

const Actions = styled('div')(({ theme }) => ({
display: 'flex',
flexGrow: 1,
}));

const ActionBox = styled('div')(({ theme }) => ({
flexBasis: '50%',
padding: theme.spacing(3, 2, 6, 8),
display: 'flex',
gap: theme.spacing(3),
flexDirection: 'column',
}));

const TitleContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'row',
gap: theme.spacing(2),
alignItems: 'center',
fontSize: theme.spacing(1.75),
fontWeight: 'bold',
}));

const NeutralCircleContainer = styled('span')(({ theme }) => ({
width: '28px',
height: '28px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: theme.palette.neutral.border,
borderRadius: '50%',
}));

const MainCircleContainer = styled(NeutralCircleContainer)(({ theme }) => ({
backgroundColor: theme.palette.primary.main,
color: theme.palette.background.paper,
}));

const ExistingFlagContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(3),
height: '100%',
}));

const SuccessContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',

fontSize: theme.spacing(1.75),
fontWeight: 'bold',
backgroundColor: theme.palette.success.light,
borderRadius: theme.shape.borderRadiusLarge,
padding: theme.spacing(2, 2, 2, 2),
}));

const TitleRow = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
}));

export const ProjectOnboarding = ({
projectId,
setConnectSdkOpen,
setOnboardingFlow,
}: IProjectOnboardingProps) => {
const { project } = useProjectOverview(projectId);
const isFirstFlagCreated =
project.onboardingStatus.status === 'first-flag-created';

const closeOnboardingFlow = () => {
setOnboardingFlow('closed');
};

return (
<Container>
<WelcomeToProject
projectId={projectId}
setConnectSdkOpen={setConnectSdkOpen}
/>
<SdkExample />
<TitleBox>
<TitleRow>
<Typography fontWeight='bold'>
Welcome to your project
</Typography>
<Tooltip title='Close' arrow>
<IconButton onClick={closeOnboardingFlow} size='small'>
<CloseIcon />
</IconButton>
</Tooltip>
</TitleRow>
<Typography variant='body2'>
Complete the steps below to start working with this project
</Typography>
</TitleBox>
<Actions>
<ActionBox>
{project.onboardingStatus.status ===
'first-flag-created' ? (
<ExistingFlag />
) : (
<CreateFlag projectId={projectId} />
)}
</ActionBox>
<ActionBox>
<TitleContainer>
<NeutralCircleContainer>2</NeutralCircleContainer>
Connect an SDK
</TitleContainer>
<Typography>
Your project is not yet connected to any SDK. To start
using your feature flag, connect an SDK to the project.
</Typography>
<ResponsiveButton
onClick={() => {
setConnectSdkOpen(true);
}}
maxWidth='200px'
projectId={projectId}
Icon={Add}
disabled={!isFirstFlagCreated}
permission={CREATE_FEATURE}
>
Connect SDK
</ResponsiveButton>
</ActionBox>
<ActionBox>
<SdkExample />
</ActionBox>
</Actions>
</Container>
);
};

const CreateFlag = ({ projectId }: ICreateFlagProps) => {
const { refetch } = useProjectOverview(projectId);
return (
<>
<TitleContainer>
<NeutralCircleContainer>1</NeutralCircleContainer>
Create a feature flag
</TitleContainer>
<Typography>
<div>The project currently holds no feature flags.</div>
<div>Create one to get started.</div>
</Typography>
<FlagCreationButton
text='Create flag'
skipNavigationOnComplete={true}
onSuccess={refetch}
/>
</>
);
};

const ExistingFlag = () => {
return (
<ExistingFlagContainer>
<TitleContainer>
<MainCircleContainer></MainCircleContainer>
Create a feature flag
</TitleContainer>
<SuccessContainer>
<Typography fontWeight='bold' variant='body2'>
Congratulations! You have created your first flag
</Typography>
<Typography variant='body2'>
Click into the flag below to customize the flag further
</Typography>
</SuccessContainer>
</ExistingFlagContainer>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,13 @@ import Select from 'component/common/select';
import { useState } from 'react';
import { allSdks } from '../../../../onboarding/sharedTypes';

const Container = styled('div')(({ theme }) => ({
const TitleContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
backgroundColor: theme.palette.background.paper,
flexBasis: '30%',
borderRadius: theme.shape.borderRadiusLarge,
}));

const TitleBox = styled('div')(({ theme }) => ({
padding: theme.spacing(2, 7, 2, 7),
borderBottom: '1px solid',
borderColor: theme.palette.divider,
minHeight: '80px',
flexDirection: 'row',
gap: theme.spacing(2),
alignItems: 'center',
display: 'flex',
}));

const ContentBox = styled('div')(({ theme }) => ({
padding: theme.spacing(3, 2, 6, 8),
display: 'flex',
gap: theme.spacing(3),
flexDirection: 'column',
fontSize: theme.spacing(1.75),
fontWeight: 'bold',
}));

const StyledLink = styled(Link)({
Expand All @@ -45,27 +30,22 @@ export const SdkExample = () => {
setSelectedSdk(event.target.value);
};
return (
<Container>
<TitleBox>
<Typography fontWeight='bold'>View SDK Example</Typography>
</TitleBox>

<ContentBox>
<Typography>
See an example implementation of your preferred SDK.
</Typography>
<Select
id='sdk-select'
name='sdk'
options={sdkOptions}
value={selectedSdk}
onChange={onChange}
style={{
width: '60%',
}}
/>
<StyledLink to={``}>Go to example</StyledLink>
</ContentBox>
</Container>
<>
<TitleContainer>View SDK Example</TitleContainer>
<Typography>
Choose your preferred SDK to view an example
</Typography>
<Select
id='sdk-select'
name='sdk'
options={sdkOptions}
value={selectedSdk}
onChange={onChange}
style={{
width: '60%',
}}
/>
<StyledLink to={``}>Go to example</StyledLink>
</>
);
};
Loading

0 comments on commit 9f5e909

Please sign in to comment.