Skip to content

Commit

Permalink
Merge pull request #276 from Ferlab-Ste-Justine/feat/CLIN-1763
Browse files Browse the repository at this point in the history
feat: CLIN-1763 ajout assignation tag et select
  • Loading branch information
claudia1296 committed May 11, 2023
2 parents 51d23fe + ffec212 commit 1155c5f
Show file tree
Hide file tree
Showing 10 changed files with 448 additions and 1 deletion.
2 changes: 1 addition & 1 deletion packages/ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ferlab/ui",
"version": "7.0.1",
"version": "7.1.0",
"description": "Core components for scientific research data portals",
"publishConfig": {
"access": "public"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
.selectInput {
width: 100%;
}

.noAssignments {
font-size: 12px;
line-height: 20px;
padding: 0;
margin-top: 8px;
span{
text-decoration: underline;
}
}

.optionsList {
max-height: 160px;
width: 100%;
overflow-y: auto;

&.withMargin {
margin-bottom: 12px;
}

button {
width: -webkit-fill-available;
padding: 0;
text-align: left;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react';
import { render, screen } from '@testing-library/react';

import AssignmentsSelect, { TAssignmentsSelect } from '.';

describe('AssignmentTag', () => {
test('make sure all options is renderer if visible is true', () => {
const props = {
assignedPractionnerRoles: [],
handleSelect: ([]) => undefined,
options: [
{
email: 'email1@ferlab.bio',
ldm: 'LDM-01',
name: [
{
family: 'Family01',
given: ['given01'],
},
],
practitionerRoles_Id: 'PR01',
},
{
email: 'email2@ferlab.bio',
ldm: 'LDM-02',
name: [
{
family: 'Family02',
given: ['given02'],
},
],
practitionerRoles_Id: 'PR02',
},
{
email: 'email3@ferlab.bio',
ldm: 'LDM-03',
name: [
{
family: 'Family03',
given: ['given03'],
},
],
practitionerRoles_Id: 'PR03',
},
],
visibleOptions: true,
} as TAssignmentsSelect;

render(<AssignmentsSelect {...props} />);
props.options.forEach((o) => {
expect(screen.getByText(o.ldm)).toBeTruthy();
});
});
});
113 changes: 113 additions & 0 deletions packages/ui/src/components/Assignments/AssignmentsSelect/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import React, { useEffect, useState } from 'react';
import { Button, Select } from 'antd';
import type { CustomTagProps } from 'rc-select/lib/BaseSelect';

import ScrollContent from '../../../layout/ScrollContent';
import AssignmentsTag from '../AssignmentsTag';
import { TPractitionnerInfo, TPractitionnerName } from '../types';

import styles from './index.module.scss';

export type TAssignmentsSelect = {
options: TPractitionnerInfo[];
visibleOptions?: boolean;
handleSelect: (practitionerRoles_ids: string[]) => void;
assignedPractionnerRoles: string[];
};

const getPractitionnerName = (name: TPractitionnerName) => `${name[0].given.join(' ')} ${name[0].family}`;

const tagRender =
(
selectedItems: TPractitionnerInfo[],
setSelectedItems: React.Dispatch<React.SetStateAction<TPractitionnerInfo[]>>,
) =>
(props: CustomTagProps) => {
const { value } = props;
const practitionerInfo = selectedItems.find((s) => s.practitionerRoles_Id === value);
const handleClose = () => {
setSelectedItems(selectedItems.filter((s) => s.practitionerRoles_Id !== value));
};
return (
<AssignmentsTag
closable
email={practitionerInfo?.email ? practitionerInfo.email : ''}
handleClose={handleClose}
name={practitionerInfo?.name ? getPractitionnerName(practitionerInfo.name) : value}
organization={practitionerInfo?.ldm ? practitionerInfo.ldm : ''}
/>
);
};

export const AssignmentsSelect = ({
assignedPractionnerRoles,
handleSelect,
options,
visibleOptions = false,
}: TAssignmentsSelect) => {
const alreadySelectedOption = options.filter((r) => assignedPractionnerRoles?.includes(r.practitionerRoles_Id));
const [selectedItems, setSelectedItems] = useState<TPractitionnerInfo[]>(alreadySelectedOption);
const filteredOptions = options.filter(
({ practitionerRoles_Id: id1 }) => !selectedItems.some(({ practitionerRoles_Id: id2 }) => id2 === id1),
);
const selectedOptions = selectedItems.reduce(
(acc: { value: string }[], curr: TPractitionnerInfo) => [...acc, { value: curr.practitionerRoles_Id }],
[],
);

useEffect(() => {
handleSelect(
selectedItems.reduce((acc: string[], curr: TPractitionnerInfo) => [...acc, curr.practitionerRoles_Id], []),
);
}, [selectedItems]);

return (
<>
<Select
className={styles.selectInput}
mode="multiple"
open={false}
options={selectedOptions}
placeholder="Recherche"
style={{ width: '100%' }}
tagRender={tagRender(selectedItems, setSelectedItems)}
value={selectedOptions}
/>
{visibleOptions && (
<div className={styles.selectedOption}>
<Button
className={styles.noAssignments}
disabled={selectedOptions.length === 0 ? true : false}
onClick={() => {
setSelectedItems([]);
}}
size="small"
type="link"
>
Aucune Assignation
</Button>
<ScrollContent className={styles.optionsList}>
{filteredOptions?.map((value: TPractitionnerInfo) => (
<Button
key={value.practitionerRoles_Id}
onClick={() => {
setSelectedItems([...selectedItems, value]);
}}
type="text"
>
<AssignmentsTag
background={false}
email={value.email ? value.email : ''}
name={getPractitionnerName(value.name)}
organization={value.ldm}
/>
</Button>
))}
</ScrollContent>
</div>
)}
</>
);
};

export default AssignmentsSelect;
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@import "theme.template";

.assignmentsTag{
background-color: $gray-3;
border-radius: 100px;
margin: 0;
padding: 0 8px 0 0;

}

.noBackground{
background-color: inherit;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';
import { render, screen } from '@testing-library/react';

import AssignmentsTag from '.';

describe('AssignmentTag', () => {
test('make sure the name is rendered', () => {
const props = {
email: 'email@ferlab.bio',
name: 'Prenom Nom',
organization: 'LDM-01',
};

render(<AssignmentsTag {...props} />);
expect(screen.getByText(props.name)).toBeTruthy();
});

test('make sure the organization is rendered', () => {
const props = {
email: 'email@ferlab.bio',
name: 'Prenom Nom',
organization: 'LDM-01',
};

render(<AssignmentsTag {...props} />);
expect(screen.getByText(props.organization)).toBeTruthy();
});
});
45 changes: 45 additions & 0 deletions packages/ui/src/components/Assignments/AssignmentsTag/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';
import { Space, Tag, Typography } from 'antd';

import Gravatar from '../../Gravatar';

import styles from './index.module.scss';

export type TAssignmentsTag = {
email: string;
name: string;
organization: string;
background?: boolean;
disable?: boolean;
closable?: boolean;
handleClose?: () => void;
};

export const AssignmentsTag = ({
background = true,
closable = false,
disable = false,
email,
handleClose,
name,
organization,
}: TAssignmentsTag) => {
const { Text } = Typography;
return (
<Tag
className={background ? `${styles.assignmentsTag}` : `${styles.assignmentsTag} ${styles.noBackground}`}
closable={closable && true}
onClose={handleClose}
>
<Space size={8}>
<Gravatar circle email={email} size={24} />
<Space size={4}>
<Text strong>{name}</Text>
<Text type="secondary">{organization}</Text>
</Space>
</Space>
</Tag>
);
};

export default AssignmentsTag;
13 changes: 13 additions & 0 deletions packages/ui/src/components/Assignments/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export type TPractitionnerInfo = {
practitionerRoles_Id: string;
name: TPractitionnerName;
email?: string;
ldm: string;
};

export type TPractitionnerName = [
{
family: string;
given: string[];
},
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React from 'react';
import { Meta } from '@storybook/react/types-6-0';
import AssignementsSelect, { TAssignmentsSelect } from '@ferlab/ui/components/Assignments/AssignmentsSelect';
import { TPractitionnerInfo } from '@ferlab/ui/components/Assignments/types';

export default {
title: '@ferlab/Components/Assignments/AssignmentsSelect',
component: AssignementsSelect,
decorators: [
(Story) => (
<>
<h2>{Story}</h2>
<Story />
</>
),
],
} as Meta;

const AssignmentsSelectPropsStory = ({
storyTitle,
options,
handleSelect,
assignedPractionnerRoles,
...props
}: {
storyTitle: string;
options: TPractitionnerInfo[];
handleSelect: (practitionerRoles_ids: string[]) => void;
assignedPractionnerRoles: string[];
props: TAssignmentsSelect;
}) => (
<>
<h3>{storyTitle}</h3>
<AssignementsSelect
handleSelect={handleSelect}
options={options}
assignedPractionnerRoles={assignedPractionnerRoles}
visibleOptions={true}
/>
</>
);

export const VisibleOption = AssignmentsSelectPropsStory.bind({});
VisibleOption.args = {
storyTitle: 'Assignment Select',
options: [
{
practitionerRoles_Id: 'PR01',
name: [
{
family: 'Family01',
given: ['given01'],
},
],
email: 'email1@ferlab.bio',
ldm: 'LDM-01',
},
{
practitionerRoles_Id: 'PR02',
name: [
{
family: 'Family02',
given: ['given02'],
},
],
email: 'email2@ferlab.bio',
ldm: 'LDM-01',
},
{
practitionerRoles_Id: 'PR03',
name: [
{
family: 'Family03',
given: ['given03'],
},
],
email: 'email3@ferlab.bio',
ldm: 'LDM-03',
},
],
handleSelect: ([]) => {},
assignedPractionnerRoles: [],
};
Loading

0 comments on commit 1155c5f

Please sign in to comment.