Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MI-2711]: Create Countdown component #61

Merged
merged 30 commits into from
Apr 7, 2023
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
eb245c6
[MI-2711]: Create Countdown component
SaurabhSharma-884 Feb 3, 2023
66282c1
[MI-2711]: Add onFinished handler function
SaurabhSharma-884 Feb 6, 2023
ac08fcd
[MI-2711]: Self review fix
SaurabhSharma-884 Feb 6, 2023
03310be
[MI-2712]: Create MultiProgress component
SaurabhSharma-884 Feb 6, 2023
5f035bb
[MI-2712]: self review fix
SaurabhSharma-884 Feb 6, 2023
cd064c7
Merge branch 'mm_v6' of s.github.com:Brightscout/mm-ui-library into M…
SaurabhSharma-884 Feb 7, 2023
d1aebce
Merge branch 'mm_v6' of s.github.com:Brightscout/mm-ui-library into M…
SaurabhSharma-884 Feb 7, 2023
116d2ef
Merge branch 'MI-2712' of s.github.com:Brightscout/mm-ui-library into…
SaurabhSharma-884 Feb 8, 2023
5900602
Merge branch 'MI-2623' of s.github.com:Brightscout/mm-ui-library into…
SaurabhSharma-884 Feb 8, 2023
35fcf70
[MI-2711]: fix Tab component
SaurabhSharma-884 Feb 17, 2023
05a3e59
MI-2752: Add MM auto suggestion search component
atisheyJain03 Feb 22, 2023
50a95b0
[MI-2752]: Fixes after self review
atisheyJain03 Mar 9, 2023
afe2baa
Merge branch 'MI-2711' of gitpro.ttaallkk.top-atishey:Brightscout/mm-ui-librar…
atisheyJain03 Mar 10, 2023
e3409f3
[MI-2752]: Review fixes
atisheyJain03 Mar 10, 2023
4e0113d
Merge pull request #64 from Brightscout/MI-2752
atisheyJain03 Mar 10, 2023
030a34f
[MI-2867]: Add search label auto-suggest hints and other style fixes
SaurabhSharma-884 Mar 14, 2023
81fd023
[MI-2867]: Revert List component changes
SaurabhSharma-884 Mar 15, 2023
274e358
[MI-2867]: Add review fix
SaurabhSharma-884 Mar 16, 2023
41d9555
Merge pull request #71 from Brightscout/MI-2867
SaurabhSharma-884 Mar 16, 2023
8d03e33
[MI-2711]: Update version
SaurabhSharma-884 Mar 17, 2023
74621e9
[MI-2925]: Open list on Input focus
SaurabhSharma-884 Mar 24, 2023
0b5c8a4
[MI-2925]: Fix prop documentation
SaurabhSharma-884 Mar 24, 2023
c3a692e
Merge pull request #74 from Brightscout/MI-2925
SaurabhSharma-884 Mar 24, 2023
d3a9162
[MI-2931]: Fix option list on open and update version
SaurabhSharma-884 Mar 25, 2023
528b290
Merge pull request #75 from Brightscout/MI-2931
SaurabhSharma-884 Mar 25, 2023
d0edc98
[MI-2711]: Fix lint errors
SaurabhSharma-884 Apr 3, 2023
9383869
[MI-2711]: Add review fixes
SaurabhSharma-884 Apr 4, 2023
8e11de1
Merge branch 'mm_v6' of s.github.com:Brightscout/mm-ui-library into M…
SaurabhSharma-884 Apr 4, 2023
a266960
[MI-2711]: Review fixes
SaurabhSharma-884 Apr 7, 2023
8a94df8
[MI-2711]: Review fix
SaurabhSharma-884 Apr 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions src/components/Countdown/Countdown.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import React, {useState, useRef, useEffect} from 'react';

import {CountdownProps} from './Countdown';
import {CountdownWrapper, TimeLabel, Timer, TimeLabelWrapper} from './Countdown.styles';

/**
* Countdown component
*
* @example Correct usage for showing full time
*
* ```ts
* <Countdown endTime={1675488600000} onFinished={()=>{}}/>
* ```
*
* @example Correct usage when showing custom fields
*
* ```ts
* <Countdown
* endTime={1675488600000}
* showHours={true}
* showMinutes={true}
* onFinished={()=>{}}
* />
* ```
*
* @param props CountdownProps
* @returns JSX.Element
*/
export const Countdown = (props: CountdownProps) => {
const {endTime,
showDays = false,
showHours = false,
showMinutes = false,
showSeconds = false,
className = '',
onFinished,
} = props;

// Check if full time is shown or not
const showingFullTime = () => {
return (showDays || showHours || showMinutes || showSeconds);
};

// Make time string
const getTimeString = () => {
const timerProps = [!showDays, !showHours, !showMinutes, !showSeconds].filter((value) => !value);
const timerString = timerProps.join(' : ').replaceAll('false', '00');
return timerString;
};

// We need ref in this, because we are dealing
// with JS setInterval to keep track of it and
// stop it when needed
const Ref = useRef<number>(0);

// The state for our timer
const [timer, setTimer] = useState(showingFullTime() ? getTimeString() : '00 : 00 : 00 : 00');

// Remaining time for countdown
const getTimeRemaining = (e: Date) => {
const total = Date.parse(e.toUTCString()) - Date.now();
const seconds = Math.floor((total / 1000) % 60);
const minutes = Math.floor((total / 1000 / 60) % 60);
const hours = Math.floor((total / 1000 / 60 / 60) % 24);
const days = Math.floor(total / (1000 * 60 * 60 * 24));
return {
SaurabhSharma-884 marked this conversation as resolved.
Show resolved Hide resolved
total, hours, minutes, seconds, days,
};
};

// Update time every second
const startTimer = (e: Date) => {
const {total, hours, minutes, seconds, days} =
getTimeRemaining(e);

if (total >= 0) {
// if any of these is true show that
if (showingFullTime()) {
let timeArray = [(showDays) && days.toString().padStart(2, '0'),
(showHours) && hours.toString().padStart(2, '0'),
(showMinutes) && minutes.toString().padStart(2, '0'),
(showSeconds) && seconds.toString().padStart(2, '0'),
];

// remove false values
timeArray = timeArray.filter((value) => value);
setTimer(timeArray.join(' : '));
} else {
// show full timer
setTimer(
`${days.toString().padStart(2, '0')} : ${hours.toString().padStart(2, '0')} : ${minutes.toString().padStart(2, '0')} : ${seconds.toString().padStart(2, '0')} `,
);
}
} else {
clearInterval(Ref.current);
if (onFinished) {
onFinished();
}
}
};

const clearTimer = (e: Date) => {
// reset initial time
if (showingFullTime()) {
setTimer(getTimeString());
} else {
setTimer('00 : 00 : 00 : 00');
}

// If you try to remove this line the
// updating of timer Variable will be
// after 1000ms or 1sec
if (Ref.current) {
clearInterval(Ref.current);
}
const id = window.setInterval(() => {
startTimer(e);
}, 1000);

Ref.current = id;
};

// start the timer when component mounts
useEffect(() => {
clearTimer(new Date(endTime));
}, [showDays, showHours, showMinutes, showSeconds]);

return (
<CountdownWrapper className={`mm-countdown ${className}`}>
<Timer>
{timer}
</Timer>
<TimeLabelWrapper>
{
(showingFullTime()) ? (
<>
{showDays && <TimeLabel>{'Days'}</TimeLabel>}
{showHours && <TimeLabel>{'Hrs'}</TimeLabel>}
{showMinutes && <TimeLabel>{'Mins'}</TimeLabel>}
{showSeconds && <TimeLabel>{'Sec'}</TimeLabel>}
</>
) : (
<>
<TimeLabel>{'Days'}</TimeLabel>
<TimeLabel>{'Hrs'}</TimeLabel>
<TimeLabel>{'Mins'}</TimeLabel>
<TimeLabel>{'Sec'}</TimeLabel>
</>
)
}

</TimeLabelWrapper>
</CountdownWrapper>
);
};
41 changes: 41 additions & 0 deletions src/components/Countdown/Countdown.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
export interface CountdownProps {

/**
* Time at which countdown will end in milliseconds
*/
endTime: number;

/**
* Flag to show days in timer
* @default false
*/
showDays?: boolean;

/**
* Flag to show hours in timer
* @default false
*/
showHours?: boolean;

/**
* Flag to show minutes in timer
* @default false
*/
showMinutes?: boolean;

/**
* Flag to show seconds in timer
* @default false
*/
showSeconds?: boolean;

/**
* To override or extend the styles applied to the component
*/
className?: string;

/**
* To be called when countdown is over
*/
onFinished?: () => void;
}
28 changes: 28 additions & 0 deletions src/components/Countdown/Countdown.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';
import {Story, Meta} from '@storybook/react';

import {Countdown} from './Countdown.component';
import {CountdownProps} from './Countdown';

export default {
title: 'Component/Countdown',
component: Countdown,
} as Meta<typeof Countdown>;

const CountdownTemplate: Story<CountdownProps> = (args) => <Countdown {...args}/>;

// Default
export const Default = CountdownTemplate.bind({});
Default.args = {
endTime: 1676007000000, // 2023/02/10 11:00
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I open the storybook, it shows 0:0:0... Can we do something so that the countdown works if I open the storybook.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added, Now it shows 2 days countdown time from when the component is rendered

};

// Custom countdown
export const Custom = CountdownTemplate.bind({});
Custom.args = {
endTime: 1676007000000, // 2023/02/10 11:00
showDays: true,
showHours: true,
showMinutes: true,
};

52 changes: 52 additions & 0 deletions src/components/Countdown/Countdown.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import styled from 'styled-components';

import Colors from '@Styles/colorsForJs.module.scss';

// Styles from card wrapper
export const CountdownWrapper = styled.div(() => {
return {
display: 'flex',
flexDirection: 'column' as const,
alignItems: 'center',
justifyContent: 'center',
background: Colors.centerChannel_4,
borderRadius: '4px',
padding: 16,
minWidth: 'fit-content',
};
});
SaurabhSharma-884 marked this conversation as resolved.
Show resolved Hide resolved

// Styles for timer
export const Timer = styled.h2(() => {
return {
fontWeight: 600,
fontSize: '22px',
lineHeight: '28px',
color: Colors.centerChannel,
letterSpacing: '0.09em',
SaurabhSharma-884 marked this conversation as resolved.
Show resolved Hide resolved
marginBottom: '4px',
minWidth: 'max-content',
minHeight: '28px',
};
});

// Styles for time label
export const TimeLabel = styled.p(() => {
return {
fontWeight: 400,
fontSize: '12px',
lineHeight: '20px',
color: Colors.centerChannel_72,
minWidth: '22px',
margin: 0,
};
});
SaurabhSharma-884 marked this conversation as resolved.
Show resolved Hide resolved

// Styles for time label wrapper
export const TimeLabelWrapper = styled.div(() => {
return {
display: 'flex',
alignItems: 'center',
gap: 30,
};
});
SaurabhSharma-884 marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions src/components/Countdown/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {Countdown} from './Countdown.component';
SaurabhSharma-884 marked this conversation as resolved.
Show resolved Hide resolved
47 changes: 47 additions & 0 deletions src/components/MultiProgress/MultiProgress.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';

import {ProgressBar} from 'react-bootstrap';

import {MultiProgressBarProps, ProgressBarProps} from './MultiProgress';
import {StyledMultiProgressBarContainer} from './MultiProgress.styles';

/**
* MultiProgress Component
*
* @example Correct usage for MultiProgress
*
* ```ts
* <MultiProgress
* progressBarConfig={[{value: 10, color: 'red'}, {value: 7, color: 'blue'}, {value: 3, color: 'green'}]}
* />
* ```
*
*/
export const MultiProgress = (props: MultiProgressBarProps) => {
const {progressBarConfig, className} = props;
atisheyJain03 marked this conversation as resolved.
Show resolved Hide resolved

// get percentage of progress of a progress bar with respect to progress of all the progress bars
const getBarFraction = (value: number) => {
let total = 0;
progressBarConfig.forEach((bar: ProgressBarProps) => {
total += bar.value;
});
return (value / total) * 100;
};

return (
<StyledMultiProgressBarContainer>
<ProgressBar className={`mm-multiProgress ${className}`}>
{progressBarConfig.map((bar: ProgressBarProps, index: number) => (
<ProgressBar
key={index}
now={getBarFraction(bar.value)}
style={{
backgroundColor: bar.color,
}}
/>
))}
</ProgressBar>
</StyledMultiProgressBarContainer>
);
};
25 changes: 25 additions & 0 deletions src/components/MultiProgress/MultiProgress.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export interface ProgressBarProps {

/**
* Value of the progress in percentage of linear progress bar component
*/
value: number;

/**
* Color of the spinner based on available options
*/
color: string;
}

export interface MultiProgressBarProps {

/**
* Configuration array for the multiple progress bars
*/
progressBarConfig: ProgressBarProps[];

/**
* To override or extend the styles applied to the component
*/
className: string;
SaurabhSharma-884 marked this conversation as resolved.
Show resolved Hide resolved
}
35 changes: 35 additions & 0 deletions src/components/MultiProgress/MultiProgress.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import {Story, Meta} from '@storybook/react';

import {MultiProgress} from './MultiProgress.component';
import {MultiProgressBarProps} from './MultiProgress';

export default {
title: ' Component/MultiProgress',
component: MultiProgress,
} as Meta;

const MultiProgressTemplate: Story<MultiProgressBarProps> = (args) => <MultiProgress {...args}/>;

// Default
export const Default = MultiProgressTemplate.bind({});
Default.args = {
progressBarConfig: [
{
value: 10,
color: 'green',
},
{
value: 7,
color: 'blue',
},
{
value: 3,
color: 'red',
},
{
value: 4,
color: 'orange',
},
],
};
Loading