Skip to content

Commit

Permalink
Merge pull request #2453 from innovaccer/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
anuradha9712 authored Dec 12, 2024
2 parents 0001106 + 56067ab commit a2eaacc
Show file tree
Hide file tree
Showing 85 changed files with 5,129 additions and 3,439 deletions.
56 changes: 47 additions & 9 deletions core/components/atoms/avatar/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import AvatarIcon from './avatarIcon';
import AvatarImage from './avatarImage';
import AvatarProvider from './AvatarProvider';

type TPresence = 'active' | 'away';

export interface AvatarProps extends BaseProps {
/**
* Color of the `Avatar`
Expand Down Expand Up @@ -57,6 +59,18 @@ export interface AvatarProps extends BaseProps {
* Defines tabIndex of the `Avatar`
*/
tabIndex?: number;
/**
* Show presence indicator for the `Avatar`
*/
presence?: TPresence;
/**
* Show status indicator for the `Avatar`
*/
status?: React.ReactNode;
/**
* Stroke color of `Presence indicator` & `Status indicator` in `Avatar`
*/
strokeColor?: string;
}

const initialsLength = 2;
Expand All @@ -77,6 +91,9 @@ export const Avatar = (props: AvatarProps) => {
disabled,
tooltipSuffix,
tabIndex,
presence,
status,
strokeColor,
role = 'presentation',
} = props;

Expand All @@ -99,6 +116,8 @@ export const Avatar = (props: AvatarProps) => {
appearance || colors[(initials.charCodeAt(0) + (initials.charCodeAt(1) || 0)) % 8] || DefaultAppearance;

const darkAppearance = ['secondary', 'success', 'warning', 'accent1', 'accent4'];
const showPresence = presence && !disabled && shape === 'round';
const showStatus = status && size === 'regular' && shape === 'round';

const AvatarClassNames = classNames(
{
Expand Down Expand Up @@ -127,6 +146,16 @@ export const Avatar = (props: AvatarProps) => {
['Avatar-content']: darkAppearance.includes(AvatarAppearance),
});

const presenceClassNames = classNames({
['Avatar-presence']: presence,
['Avatar-presence--active']: presence === 'active',
['Avatar-presence--away']: presence === 'away',
});

const borderStyle = {
boxShadow: `0 0 0 var(--spacing-s) ${strokeColor}`,
};

const sharedProp = {
size,
firstName,
Expand Down Expand Up @@ -180,17 +209,25 @@ export const Avatar = (props: AvatarProps) => {
);
};

const renderTooltip = () => {
if (withTooltip && initials) {
return (
<Tooltip tooltip={getTooltipName()} position={tooltipPosition} triggerClass={'flex-grow-0'}>
const renderTooltip = () => (
<span className="position-relative d-inline-flex">
{withTooltip && initials ? (
<Tooltip tooltip={getTooltipName()} position={tooltipPosition} triggerClass="flex-grow-0">
{renderAvatar()}
</Tooltip>
);
}

return renderAvatar();
};
) : (
renderAvatar()
)}
{showPresence && (
<span data-test="DesignSystem-Avatar--Presence" className={presenceClassNames} style={borderStyle} />
)}
{showStatus && (
<span data-test="DesignSystem-Avatar--Status" className="Avatar-status" style={borderStyle}>
{status}
</span>
)}
</span>
);

return renderTooltip();
};
Expand All @@ -205,6 +242,7 @@ Avatar.defaultProps = {
withTooltip: true,
size: 'regular',
shape: 'round',
strokeColor: 'var(--white)',
};

export default Avatar;
36 changes: 36 additions & 0 deletions core/components/atoms/avatar/__stories__/Presence.story.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import * as React from 'react';
import { Avatar, Row, Column, Text } from '@/index';

// CSF format story
export const presence = () => {
const weight = 'strong';

return (
<Row className="w-50">
<Column>
<Text weight={weight}>Active</Text>
<br />
<br />
<Avatar firstName="John" lastName="Doe" presence="active" />
</Column>
<Column>
<Text weight={weight}>Away</Text>
<br />
<br />
<Avatar firstName="John" lastName="Doe" presence="away" />
</Column>
</Row>
);
};

export default {
title: 'Components/Avatar/Avatar/Presence',
component: Avatar,
parameters: {
docs: {
docPage: {
title: 'Avatar',
},
},
},
};
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 30 additions & 0 deletions core/components/atoms/avatar/__stories__/statusWithIcon.story.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as React from 'react';
import { Avatar, Icon, Tooltip } from '@/index';

// CSF format story
export const statusWithIcon = () => {
return (
<Avatar
lastName="Doe"
firstName="John"
appearance="primary"
status={
<Tooltip tooltip="Verified" position="top">
<Icon name="done" size={10} appearance="white" className="p-1 bg-success" />
</Tooltip>
}
/>
);
};

export default {
title: 'Components/Avatar/Avatar/Status/Status With Icon',
component: Avatar,
parameters: {
docs: {
docPage: {
title: 'Avatar',
},
},
},
};
31 changes: 31 additions & 0 deletions core/components/atoms/avatar/__stories__/statusWithImage.story.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import * as React from 'react';
import { Avatar, Tooltip } from '@/index';
import StatusImage from './assets/status-image.png';

// CSF format story
export const statusWithImage = () => {
return (
<Avatar
firstName="Tom"
lastName="Yusuf"
appearance="accent1"
status={
<Tooltip tooltip="DND" position="top">
<img width="14px" alt="DND" src={StatusImage} />
</Tooltip>
}
/>
);
};

export default {
title: 'Components/Avatar/Avatar/Status/Status With Image',
component: Avatar,
parameters: {
docs: {
docPage: {
title: 'Avatar',
},
},
},
};
87 changes: 86 additions & 1 deletion core/components/atoms/avatar/__tests__/Avatar.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { fireEvent, render } from '@testing-library/react';
import { fireEvent, render, screen } from '@testing-library/react';
import Avatar, { AvatarProps as Props } from '../Avatar';
import { AccentAppearance, AvatarShape, AvatarSize } from '@/common.type';
import { testHelper, filterUndefined, valueHelper, testMessageHelper } from '@/utils/testHelper';
Expand All @@ -20,6 +20,8 @@ const sizes: AvatarSize[] = ['regular', 'tiny'];
const shapes: AvatarShape[] = ['round', 'square'];
const booleanValues = [true, false];

const statusComponent = <div>status</div>;

describe('Avatar component', () => {
const mapper = {
appearance: valueHelper(appearances, { required: true, iterate: true }),
Expand Down Expand Up @@ -231,3 +233,86 @@ describe('Avatar component with tooltip', () => {
expect(tooltip).toHaveTextContent('John Doe (Deactivated)');
});
});

describe('Avatar component with prop:presence', () => {
it('presence should be available for only round avatar', () => {
const { getByTestId } = render(<Avatar firstName="John" lastName="Doe" presence="active" shape="round" />);
const presenceEle = getByTestId('DesignSystem-Avatar--Presence');
expect(presenceEle).toBeInTheDocument();
expect(presenceEle).toHaveClass('Avatar-presence');
});

it('presence should not be available for square avatar', () => {
render(<Avatar firstName="John" lastName="Doe" presence="active" shape="square" />);
const presenceEle = screen.queryByText('DesignSystem-Avatar--Presence');
expect(presenceEle).not.toBeInTheDocument();
});

it('presence should not be available for disabled avatar', () => {
render(<Avatar firstName="John" lastName="Doe" presence="active" disabled={true} />);
const presenceEle = screen.queryByText('DesignSystem-Avatar--Presence');
expect(presenceEle).not.toBeInTheDocument();
});

it('presence should have active class for prop presence:active', () => {
const { getByTestId } = render(<Avatar firstName="John" lastName="Doe" presence="active" />);
const presenceEle = getByTestId('DesignSystem-Avatar--Presence');
expect(presenceEle).toHaveClass('Avatar-presence--active');
});

it('presence should have active class for prop presence:away', () => {
const { getByTestId } = render(<Avatar firstName="John" lastName="Doe" presence="away" />);
const presenceEle = getByTestId('DesignSystem-Avatar--Presence');
expect(presenceEle).toHaveClass('Avatar-presence--away');
});

it('presence should have custom stroke color', () => {
const { getByTestId } = render(<Avatar firstName="John" lastName="Doe" presence="away" strokeColor="red" />);
const presenceEle = getByTestId('DesignSystem-Avatar--Presence');
expect(presenceEle).toHaveStyle('box-shadow: 0 0 0 var(--spacing-s) red');
});
});

describe('Avatar component with prop:status', () => {
it('should have the Avatar-status class when size is regular', () => {
const { getByTestId } = render(<Avatar status={statusComponent}>Design</Avatar>);
const statusElement = getByTestId('DesignSystem-Avatar--Status');
expect(statusElement).toBeInTheDocument();
expect(statusElement).toHaveClass('Avatar-status');
});

it('should not have the Avatar-status class when size is tiny', () => {
render(
<Avatar status={statusComponent} size="tiny">
Design
</Avatar>
);
const statusElement = screen.queryByText('DesignSystem-Avatar--Status');
expect(statusElement).not.toBeInTheDocument();
});

it('should have the Avatar-status class when shape is round', () => {
const { getByTestId } = render(<Avatar status={statusComponent}>Design</Avatar>);
const statusElement = getByTestId('DesignSystem-Avatar--Status');
expect(statusElement).toBeInTheDocument();
expect(statusElement).toHaveClass('Avatar-status');
});

it('should not have the Avatar-status class when shape is square', () => {
render(
<Avatar status={statusComponent} shape="square">
Design
</Avatar>
);
const statusElement = screen.queryByText('DesignSystem-Avatar--Status');
expect(statusElement).not.toBeInTheDocument();
});

it('status should have custom stroke color', () => {
const { getByTestId } = render(
<Avatar firstName="John" lastName="Doe" status={statusComponent} strokeColor="red" />
);
const statusElement = getByTestId('DesignSystem-Avatar--Status');
expect(statusElement).toHaveStyle('box-shadow: 0 0 0 var(--spacing-s) red');
});
});
Loading

0 comments on commit a2eaacc

Please sign in to comment.