Migrate to twenty-ui - feedback/progress-bar (#8002)

This PR was created by [GitStart](https://gitstart.com/) to address the
requirements from this ticket:
[TWNTY-7527](https://clients.gitstart.com/twenty/5449/tickets/TWNTY-7527).

 --- 

### Description

Migrate `feedback/progress-bar` to twenty ui:

- CircularProgressBar
- ProgressBar

### Demo

ProgressBar on Storybook


![](https://assets-service.gitstart.com/4814/10b11cf5-e52e-420c-b70b-274c532f5f94.png)

CircularProgressBar on Storybook


![](https://assets-service.gitstart.com/4814/e483d3db-1b4c-4062-af40-c596c406c221.png)

###### Fixes twentyhq/private-issues#91

Co-authored-by: gitstart-twenty <gitstart-twenty@users.noreply.github.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
gitstart-app[bot]
2024-10-24 14:05:04 +02:00
committed by GitHub
parent 414f2ac498
commit 445ab83c14
12 changed files with 15 additions and 14 deletions

View File

@ -1,7 +1,6 @@
import styled from '@emotion/styled';
import { CircularProgressBar } from '@/ui/feedback/progress-bar/components/CircularProgressBar';
import { MainButton } from 'twenty-ui';
import { CircularProgressBar, MainButton } from 'twenty-ui';
import { Modal } from '@/ui/layout/modal/components/Modal';
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';

View File

@ -3,10 +3,10 @@ import styled from '@emotion/styled';
import { useCallback, useState } from 'react';
import { useSpreadsheetImportInternal } from '@/spreadsheet-import/hooks/useSpreadsheetImportInternal';
import { CircularProgressBar } from '@/ui/feedback/progress-bar/components/CircularProgressBar';
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { Modal } from '@/ui/layout/modal/components/Modal';
import { CircularProgressBar } from 'twenty-ui';
import { SpreadsheetImportStep } from '@/spreadsheet-import/steps/types/SpreadsheetImportStep';
import { SpreadsheetImportStepType } from '@/spreadsheet-import/steps/types/SpreadsheetImportStepType';

View File

@ -1,71 +0,0 @@
import React, { useEffect, useMemo } from 'react';
import { motion, useAnimation } from 'framer-motion';
interface CircularProgressBarProps {
size?: number;
barWidth?: number;
barColor?: string;
}
export const CircularProgressBar = ({
size = 50,
barWidth = 5,
barColor = 'currentColor',
}: CircularProgressBarProps) => {
const controls = useAnimation();
const circumference = useMemo(
() => 2 * Math.PI * (size / 2 - barWidth),
[size, barWidth],
);
useEffect(() => {
const animateIndeterminate = async () => {
const baseSegment = Math.max(5, circumference / 10); // Adjusting for smaller values
// Adjusted sequence based on baseSegment
const dashSequences = [
`${baseSegment} ${circumference - baseSegment}`,
`${baseSegment * 2} ${circumference - baseSegment * 2}`,
`${baseSegment * 3} ${circumference - baseSegment * 3}`,
`${baseSegment * 2} ${circumference - baseSegment * 2}`,
`${baseSegment} ${circumference - baseSegment}`,
];
await controls.start({
strokeDasharray: dashSequences,
rotate: [0, 720],
transition: {
strokeDasharray: {
duration: 2,
ease: 'linear',
repeat: Infinity,
repeatType: 'loop',
},
rotate: {
duration: 2,
ease: 'linear',
repeat: Infinity,
repeatType: 'loop',
},
},
});
};
animateIndeterminate();
}, [circumference, controls]);
return (
<motion.svg width={size} height={size} animate={controls}>
<motion.circle
cx={size / 2}
cy={size / 2}
r={size / 2 - barWidth}
fill="none"
stroke={barColor}
strokeWidth={barWidth}
strokeLinecap="round"
/>
</motion.svg>
);
};

View File

@ -1,43 +0,0 @@
import { useState } from 'react';
import styled from '@emotion/styled';
import { motion } from 'framer-motion';
export type ProgressBarProps = {
className?: string;
color?: string;
value: number;
};
export type StyledBarProps = {
className?: string;
};
const StyledBar = styled.div<StyledBarProps>`
height: ${({ theme }) => theme.spacing(2)};
overflow: hidden;
width: 100%;
`;
const StyledBarFilling = styled(motion.div)<{ color?: string }>`
background-color: ${({ color, theme }) => color ?? theme.font.color.primary};
height: 100%;
`;
export const ProgressBar = ({ className, color, value }: ProgressBarProps) => {
const [initialValue] = useState(value);
return (
<StyledBar
className={className}
role="progressbar"
aria-valuenow={Math.ceil(value)}
>
<StyledBarFilling
initial={{ width: `${initialValue}%` }}
animate={{ width: `${value}%` }}
color={color}
transition={{ ease: 'linear' }}
/>
</StyledBar>
);
};

View File

@ -1,53 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import { CatalogDecorator, CatalogStory, ComponentDecorator } from 'twenty-ui';
import { CircularProgressBar } from '../CircularProgressBar';
const meta: Meta<typeof CircularProgressBar> = {
title: 'UI/Feedback/CircularProgressBar/CircularProgressBar',
component: CircularProgressBar,
args: {
size: 50,
},
parameters: {
chromatic: { disableSnapshot: true },
},
};
export default meta;
type Story = StoryObj<typeof CircularProgressBar>;
export const Default: Story = {
decorators: [ComponentDecorator],
};
export const Catalog: CatalogStory<Story, typeof CircularProgressBar> = {
argTypes: {},
parameters: {
catalog: {
dimensions: [
{
name: 'barColor',
values: [undefined, 'red'],
props: (barColor: string) => ({ barColor }),
labels: (color: string) => `Segment Color: ${color ?? 'default'}`,
},
{
name: 'barWidth',
values: [undefined, 5, 10],
props: (barWidth: number) => ({ barWidth }),
labels: (width: number) =>
`Stroke Width: ${width ? width + ' px' : 'default'}`,
},
{
name: 'size',
values: [undefined, 80, 30],
props: (size: number) => ({ size }),
labels: (size: number) => `Size: ${size ? size + ' px' : 'default'}`,
},
],
},
},
decorators: [CatalogDecorator],
};

View File

@ -1,49 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from 'twenty-ui';
import { useProgressAnimation } from '@/ui/feedback/progress-bar/hooks/useProgressAnimation';
import { ProgressBar } from '../ProgressBar';
const meta: Meta<typeof ProgressBar> = {
title: 'UI/Feedback/ProgressBar/ProgressBar',
component: ProgressBar,
decorators: [ComponentDecorator],
argTypes: {
className: { control: false },
value: { control: { type: 'range', min: 0, max: 100, step: 1 } },
},
};
export default meta;
type Story = StoryObj<typeof ProgressBar>;
export const Default: Story = {
args: {
value: 75,
},
};
export const Animated: Story = {
argTypes: {
value: { control: false },
},
decorators: [
(Story) => {
const { value } = useProgressAnimation({
autoPlay: true,
initialValue: 0,
finalValue: 100,
options: {
duration: 10000,
},
});
return <Story args={{ value }} />;
},
],
parameters: {
chromatic: { disableSnapshot: true },
},
};

View File

@ -1,58 +0,0 @@
import { useCallback, useEffect, useState } from 'react';
import { millisecondsToSeconds } from 'date-fns';
import {
animate,
AnimationPlaybackControls,
ValueAnimationTransition,
} from 'framer-motion';
import { isDefined } from '~/utils/isDefined';
export const useProgressAnimation = ({
autoPlay = true,
initialValue = 0,
finalValue = 100,
options,
}: {
autoPlay?: boolean;
initialValue?: number;
finalValue?: number;
options?: ValueAnimationTransition<number>;
}) => {
const [animation, setAnimation] = useState<
AnimationPlaybackControls | undefined
>();
const [value, setValue] = useState(initialValue);
const startAnimation = useCallback(() => {
if (isDefined(animation)) return;
const duration = isDefined(options?.duration)
? millisecondsToSeconds(options.duration)
: undefined;
setAnimation(
animate(initialValue, finalValue, {
...options,
duration,
onUpdate: (nextValue) => {
if (value === nextValue) return;
setValue(nextValue);
options?.onUpdate?.(nextValue);
},
}),
);
}, [animation, finalValue, initialValue, options, value]);
useEffect(() => {
if (autoPlay && !animation) {
startAnimation();
}
}, [animation, autoPlay, startAnimation]);
return {
animation,
startAnimation,
value,
};
};

View File

@ -10,10 +10,10 @@ import {
LightButton,
LightIconButton,
MOBILE_VIEWPORT,
ProgressBar,
useProgressAnimation,
} from 'twenty-ui';
import { ProgressBar } from '@/ui/feedback/progress-bar/components/ProgressBar';
import { useProgressAnimation } from '@/ui/feedback/progress-bar/hooks/useProgressAnimation';
import { isDefined } from '~/utils/isDefined';
export enum SnackBarVariant {