Skip to content

Commit

Permalink
Merge pull request #639 from nordnet/DISCO-2775
Browse files Browse the repository at this point in the history
move ProgressBar to UI as MultiStepProgress
  • Loading branch information
kmelkon authored Jul 24, 2020
2 parents a1e3f9f + 92eaad1 commit 59ad6c7
Show file tree
Hide file tree
Showing 16 changed files with 1,210 additions and 2 deletions.
129 changes: 129 additions & 0 deletions src/Molecules/MultiStepProgress/LevelOne/LevelOne.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import React from 'react';
import styled from 'styled-components';
import Box from '../../../Atoms/Box';
import Button from '../../Button';
import Typography from '../../../Atoms/Typography';
import { InternalProps, LevelOneComponent } from './LevelOne.types';
import { LevelTwo } from '../LevelTwo';
import Status from '../Status';
import {
listReset,
HORIZONTAL_PADDING,
HORIZONTAL_PADDING_DESKTOP,
SPACE_TO_STEP_NUMBER,
STEP_NUMBER_SIZE,
VERTICAL_PADDING,
} from '../constants';

const OrderedList = styled.ol`
${listReset}
`;

const ListItem = styled.li<InternalProps>`
display: block;
position: relative;
&::before {
content: '';
display: block;
background: ${p => p.theme.color.cta};
width: 2px;
height: 100%;
position: absolute;
top: 0;
left: 0;
transition: opacity 0.16s ease-out;
opacity: ${p => (p.$current ? 1 : 0)};
}
& + & {
border-top: ${p => p.theme.spacing.unit(2)}px solid ${p => p.theme.color.divider};
}
`;

const Content = styled(Box)`
position: relative;
`;

const StyledButton = styled(Button)`
justify-content: flex-start;
`;

export const LevelOne: LevelOneComponent = ({
onStepClick,
onSubStepClick,
steps = [],
titleDone,
titleNotDone,
}) => {
const contentLeftPadding = HORIZONTAL_PADDING + STEP_NUMBER_SIZE + SPACE_TO_STEP_NUMBER;
const contentLeftPaddingDesktop =
HORIZONTAL_PADDING_DESKTOP + STEP_NUMBER_SIZE + SPACE_TO_STEP_NUMBER;

return (
<OrderedList>
{steps.map((step, i) => {
const { current, done, label, name, steps: substeps = [] } = step;
const number = i + 1;

return (
<ListItem key={label} $current={current}>
{current || done ? (
<StyledButton
onClick={() => onStepClick && onStepClick(name)}
variant="neutral"
fullWidth
>
<Typography type="primary" weight={current ? 'bold' : 'regular'}>
<Content
py={VERTICAL_PADDING}
pr={HORIZONTAL_PADDING}
pl={contentLeftPadding}
sm={{ pl: contentLeftPaddingDesktop, pr: HORIZONTAL_PADDING_DESKTOP }}
>
<Status
current={current}
done={done}
number={number}
titleDone={titleDone}
titleNotDone={titleNotDone}
/>
{label}
</Content>
</Typography>
</StyledButton>
) : (
<>
<Typography color={t => t.color.disabledText} type="primary">
<Content
py={VERTICAL_PADDING}
pr={HORIZONTAL_PADDING}
pl={contentLeftPadding}
sm={{ pl: contentLeftPaddingDesktop }}
>
<Status
current={current}
done={done}
number={number}
titleDone={titleDone}
titleNotDone={titleNotDone}
/>
{label}
</Content>
</Typography>
</>
)}
{substeps.length > 0 && current && (
<LevelTwo
onStepClick={onSubStepClick}
steps={substeps}
titleDone={titleDone}
titleNotDone={titleNotDone}
/>
)}
</ListItem>
);
})}
</OrderedList>
);
};
19 changes: 19 additions & 0 deletions src/Molecules/MultiStepProgress/LevelOne/LevelOne.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { StepLevelTwoProps } from '../LevelTwo/LevelTwo.types';
import { A11yProps } from '../Status/Status.types';
import { StepBaseProps } from '../MultiStepProgress.types';

export type InternalProps = {
$current?: boolean;
};

export type StepLevelOneProps = {
steps?: StepLevelTwoProps[];
} & StepBaseProps;

type Props = {
onStepClick?: (stepName: string) => void;
onSubStepClick?: (stepName: string) => void;
steps?: StepLevelOneProps[];
};

export type LevelOneComponent = React.FC<Props & A11yProps>;
3 changes: 3 additions & 0 deletions src/Molecules/MultiStepProgress/LevelOne/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { LevelOne } from './LevelOne';

export { LevelOne };
75 changes: 75 additions & 0 deletions src/Molecules/MultiStepProgress/LevelTwo/LevelTwo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React from 'react';
import styled from 'styled-components';
import Typography from '../../../Atoms/Typography';
import Box from '../../../Atoms/Box';
import Button from '../../Button';
import Status from '../Status';
import { LevelTwoComponent } from './LevelTwo.types';
import {
listReset,
HORIZONTAL_PADDING,
HORIZONTAL_PADDING_DESKTOP,
SPACE_TO_STEP_NUMBER,
STEP_NUMBER_SIZE,
VERTICAL_PADDING,
} from '../constants';

const OrderedList = styled.ol`
${listReset}
padding-bottom: ${p => p.theme.spacing.unit(VERTICAL_PADDING)}px;
`;

const ListItem = styled.li`
display: block;
& + & {
padding-top: ${p => p.theme.spacing.unit(2)}px;
}
`;

export const LevelTwo: LevelTwoComponent = ({
onStepClick,
steps = [],
titleDone,
titleNotDone,
}) => {
const contentPadding = HORIZONTAL_PADDING + STEP_NUMBER_SIZE + SPACE_TO_STEP_NUMBER;
const contentPaddingDesktop =
HORIZONTAL_PADDING_DESKTOP + STEP_NUMBER_SIZE + SPACE_TO_STEP_NUMBER;

return (
<OrderedList>
{steps.map(step => {
const { current, done, name, label } = step;

return (
<ListItem key={step.label}>
<Box
pl={contentPadding}
pr={HORIZONTAL_PADDING}
sm={{ pl: contentPaddingDesktop, pr: HORIZONTAL_PADDING_DESKTOP }}
>
{current || done ? (
<Button onClick={() => onStepClick && onStepClick(name)} variant="neutral">
<Typography
color={t => (current ? t.color.text : t.color.disabledText)}
type="secondary"
weight={current ? 'bold' : 'regular'}
>
<Status done={done} noIcons titleDone={titleDone} titleNotDone={titleNotDone} />
{label}
</Typography>
</Button>
) : (
<Typography color={t => t.color.disabledText} type="secondary">
<Status done={done} noIcons titleDone={titleDone} titleNotDone={titleNotDone} />
{label}
</Typography>
)}
</Box>
</ListItem>
);
})}
</OrderedList>
);
};
11 changes: 11 additions & 0 deletions src/Molecules/MultiStepProgress/LevelTwo/LevelTwo.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { StepBaseProps } from '../MultiStepProgress.types';
import { A11yProps } from '../Status/Status.types';

export type StepLevelTwoProps = StepBaseProps;

export type Props = {
onStepClick?: (stepName: string) => void;
steps: StepLevelTwoProps[];
};

export type LevelTwoComponent = React.FC<Props & A11yProps>;
3 changes: 3 additions & 0 deletions src/Molecules/MultiStepProgress/LevelTwo/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { LevelTwo } from './LevelTwo';

export { LevelTwo };
56 changes: 56 additions & 0 deletions src/Molecules/MultiStepProgress/MultiStepProgress.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React from 'react';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import MultiStepProgress from './MultiStepProgress';

export const mockedSteps = [
{ current: false, done: true, label: 'Investment objective', name: 'investment_objective' },
{
current: true,
done: false,
label: 'Time and risk',
name: 'time_and_risk',
steps: [
{ current: false, done: true, label: 'Investment period', name: 'investment_period' },
{ current: true, done: false, label: 'Frequency', name: 'frequency' },
{ current: false, done: false, label: 'Amount', name: 'amount' },
],
},
{ current: false, done: false, label: 'Allocations', name: 'allocations' },
];

export const mockedStepsNotStarted = [
{ current: false, done: false, label: 'Investment objective', name: 'investment_objective' },
{
current: false,
done: false,
label: 'Time and risk',
name: 'time_and_risk',
steps: [
{ current: false, done: false, label: 'Investment period', name: 'investment_period' },
{ current: false, done: false, label: 'Frequency', name: 'frequency' },
{ current: false, done: false, label: 'Amount', name: 'amount' },
],
},
{ current: false, done: false, label: 'Allocations', name: 'allocations' },
];

storiesOf('Molecules | Multi Step Progress', module)
.add('Default', () => (
<>
<MultiStepProgress
steps={mockedSteps}
onStepClick={action(`step click`)}
onSubStepClick={action(`sub step click`)}
/>
</>
))
.add('Not started', () => (
<>
<MultiStepProgress
steps={mockedStepsNotStarted}
onStepClick={action(`step click`)}
onSubStepClick={action(`sub step click`)}
/>
</>
));
29 changes: 29 additions & 0 deletions src/Molecules/MultiStepProgress/MultiStepProgress.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import Card from '../../Atoms/Card';
import { LevelOne } from './LevelOne';
import { MultiStepProgressComponent } from './MultiStepProgress.types';

const MultiStepProgress: MultiStepProgressComponent = ({
onStepClick,
onSubStepClick,
steps,
title = 'Progress',
titleDone = 'Completed',
titleNotDone = 'Not completed',
}) => {
return (
<Card>
<div role="group" aria-label={title}>
<LevelOne
onStepClick={onStepClick}
onSubStepClick={onSubStepClick}
steps={steps}
titleDone={titleDone}
titleNotDone={titleNotDone}
/>
</div>
</Card>
);
};

export default MultiStepProgress;
22 changes: 22 additions & 0 deletions src/Molecules/MultiStepProgress/MultiStepProgress.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { StepLevelOneProps } from './LevelOne/LevelOne.types';

export type StepBaseProps = {
current?: boolean;
done?: boolean;
name: string;
label: string;
};

export type MultiStepProgressProps = {
onStepClick?: (stepName: string) => void;
onSubStepClick?: (stepName: string) => void;
steps?: StepLevelOneProps[];
/** Used to label the component */
title?: string;
/** Visible on completed steps */
titleDone?: string;
/** Visible on non completed steps */
titleNotDone?: string;
};

export type MultiStepProgressComponent = React.FC<MultiStepProgressProps>;
Loading

0 comments on commit 59ad6c7

Please sign in to comment.