Skip to content

Commit

Permalink
Merge pull request #2908 from glific/collection-management
Browse files Browse the repository at this point in the history
Collection management
  • Loading branch information
kurund authored Jul 8, 2024
2 parents b6c8217 + 3d716d4 commit 5f34414
Show file tree
Hide file tree
Showing 25 changed files with 904 additions and 278 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cypress-testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ jobs:
git clone https://github.com/glific/cypress-testing.git
echo done. go to dir.
cd cypress-testing
git checkout main
git checkout collections-management
cd ..
cp -r cypress-testing/cypress cypress
yarn add cypress@13.6.2
Expand Down
4 changes: 4 additions & 0 deletions src/assets/images/icons/AddGroupIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/components/UI/DialogBox/DialogBox.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
width: 474px;
}

.FullWidth {
width: 600px !important;
}

.ScrollPaper {
align-items: unset !important;
}
Expand Down
4 changes: 3 additions & 1 deletion src/components/UI/DialogBox/DialogBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface DialogProps {
buttonMiddle?: string | null;
additionalTitleStyles?: string | null;
buttonOkLoading?: boolean;
fullWidth?: boolean;
}

export const DialogBox = ({
Expand All @@ -48,6 +49,7 @@ export const DialogBox = ({
alwaysOntop = false,
buttonMiddle,
buttonOkLoading = false,
fullWidth = false,
}: DialogProps) => {
let cancelButtonDisplay = null;
if (!skipCancel) {
Expand Down Expand Up @@ -124,7 +126,7 @@ export const DialogBox = ({
open={open}
classes={{
container: styles.Dialogbox,
paper: styles.DialogboxPaper,
paper: `${styles.DialogboxPaper} ${fullWidth && styles.FullWidth}`,
scrollPaper: styles.ScrollPaper,
root: alwaysOntop ? styles.DialogboxRoot : '',
}}
Expand Down
7 changes: 4 additions & 3 deletions src/components/UI/Form/AutoComplete/AutoComplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export interface AutocompleteProps {
hasCreateOption?: boolean;
handleCreateItem?: any;
isFilterType?: boolean;
showTags?: boolean;
}

export const AutoComplete = ({
Expand Down Expand Up @@ -82,6 +83,7 @@ export const AutoComplete = ({
handleCreateItem = () => {},
placeholder = '',
isFilterType = false,
showTags = true,
}: AutocompleteProps) => {
const errorText = getIn(errors, field.name);
const touchedVal = getIn(touched, field.name);
Expand Down Expand Up @@ -125,6 +127,7 @@ export const AutoComplete = ({
};

const getRenderTags = (value: Array<any>, getTagProps: any) => {
if (!showTags) return null;
let tagsToRender = value;

/**
Expand Down Expand Up @@ -196,8 +199,6 @@ export const AutoComplete = ({
onChange={(_event, value: any) => {
if (asyncSearch && value.length > 0) {
asyncValues.setValue([...value]);
setSearchTerm('');
onChange('');
} else if (asyncSearch && value.length === 0) {
asyncValues.setValue([]);
}
Expand Down Expand Up @@ -225,7 +226,7 @@ export const AutoComplete = ({
disableCloseOnSelect={multiple}
renderTags={getRenderTags}
renderOption={(props, option, { selected }) => (
<li {...props}>
<li key={option.id} {...props}>
{multiple && (
<Checkbox
icon={icon}
Expand Down
25 changes: 25 additions & 0 deletions src/components/UI/Pager/Pager.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,28 @@
.Skeleton {
margin: 10px;
}

.SelectedItems {
composes: RowHeadStyle;
font-weight: 700;
text-align: left;
}

.Icon {
composes: RowHeadStyle;
}

.Icon span {
background-color: #fff;
border-radius: 100%;
padding: 8px;
display: flex;
align-items: center;
width: 30px;
margin-left: auto;
cursor: pointer;
}

.Checkbox {
padding: 1rem;
}
104 changes: 70 additions & 34 deletions src/components/UI/Pager/Pager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ interface PagerProps {
collapseRow: string | undefined;
noItemsText?: any;
showPagination?: boolean;
checkboxSupport?: { action: any; icon: any; selectedItems: any };
}

// TODO: cleanup the translations code
Expand Down Expand Up @@ -120,41 +121,68 @@ const tableHeadColumns = (
columnNames: Array<any>,
columnStyles: any,
tableVals: any,
handleTableChange: Function
handleTableChange: Function,
totalRows: number,
checkboxSupport?: { action: any; icon: any; selectedItems: any }
) => {
const headerRow = (
<TableRow className={styles.TableHeadRow}>
{columnNames.map((field: any, i: number) => (
<TableCell
key={field.label}
className={`${columnStyles && columnStyles[i]} ${styles.RowHeadStyle}`}
>
{i !== columnNames.length - 1 && field.name ? (
<TableSortLabel
active={field.name === tableVals.sortCol}
direction={tableVals.sortDirection}
onClick={() => {
if (field.name !== tableVals.sortCol) {
handleTableChange('sortCol', field.name);
} else {
handleTableChange('sortCol', field.name);
handleTableChange(
'sortDirection',
tableVals.sortDirection === 'asc' ? 'desc' : 'asc'
);
}
}}
className={styles.HeaderColor}
>
{field.label}
</TableSortLabel>
) : (
field.label
)}
let headerRow;

if (checkboxSupport?.selectedItems && checkboxSupport?.selectedItems.length > 0) {
headerRow = (
<TableRow className={styles.TableHeadRow}>
<TableCell className={`${styles.Checkbox} ${styles.RowHeadStyle}`}>
{columnNames[0].label}
</TableCell>
))}
</TableRow>
);
<TableCell className={styles.SelectedItems}>
{checkboxSupport?.selectedItems.length} of {totalRows} selected
</TableCell>
<TableCell colSpan={3} className={styles.Icon}>
<span
onClick={() => {
checkboxSupport?.action();
}}
>
{checkboxSupport?.icon}
</span>
</TableCell>
</TableRow>
);
} else {
headerRow = (
<TableRow className={styles.TableHeadRow}>
{columnNames.map((field: any, i: number) => (
<TableCell
key={field.label}
className={`${columnStyles && columnStyles[i]} ${styles.RowHeadStyle}`}
>
{i !== columnNames.length - 1 && field.name ? (
<TableSortLabel
active={field.name === tableVals.sortCol}
direction={tableVals.sortDirection}
onClick={() => {
if (field.name !== tableVals.sortCol) {
handleTableChange('sortCol', field.name);
} else {
handleTableChange('sortCol', field.name);
handleTableChange(
'sortDirection',
tableVals.sortDirection === 'asc' ? 'desc' : 'asc'
);
}
}}
className={styles.HeaderColor}
>
{field.label}
</TableSortLabel>
) : (
field.label
)}
</TableCell>
))}
</TableRow>
);
}

return headerRow;
};

Expand Down Expand Up @@ -193,9 +221,17 @@ export const Pager = ({
loadingList = false,
noItemsText,
showPagination = true,
checkboxSupport,
}: PagerProps) => {
const rows = createRows(data, columnStyles, collapseRow, collapseOpen);
const tableHead = tableHeadColumns(columnNames, columnStyles, tableVals, handleTableChange);
const tableHead = tableHeadColumns(
columnNames,
columnStyles,
tableVals,
handleTableChange,
totalRows,
checkboxSupport
);
const tablePagination = pagination(columnNames, totalRows, handleTableChange, tableVals);

return (
Expand Down
45 changes: 20 additions & 25 deletions src/components/UI/SearchDialogBox/SearchDialogBox.test.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { render, fireEvent } from '@testing-library/react';
import { render, fireEvent, screen, waitFor } from '@testing-library/react';
import { MockedProvider } from '@apollo/client/testing';
import { vi } from 'vitest';

import { SearchDialogBox } from './SearchDialogBox';
import * as AutoComplete from '../Form/AutoComplete/AutoComplete';

const mockHandleOk = vi.fn();
const mockHandleCancel = vi.fn();
Expand All @@ -15,6 +14,7 @@ const defaultProps: any = {
onChange: mockHandleChange,
options: [{ id: '1', label: 'something' }],
selectedOptions: ['1'],
multiple: false,
};

const asyncSearchProps = {
Expand All @@ -37,9 +37,16 @@ test('it should render the title correctly', () => {
expect(getByTestId('dialogTitle')).toHaveTextContent('Search Box');
});

test('it should contain the selected option', () => {
const { getByTestId } = render(searchDialog());
expect(getByTestId('searchChip').querySelector('span')).toHaveTextContent('something');
test('it should contain the selected option', async () => {
const { getByRole } = render(searchDialog());
const [interactiveType] = screen.getAllByTestId('autocomplete-element');
interactiveType.focus();
fireEvent.keyDown(interactiveType, { key: 'ArrowDown' });
fireEvent.keyDown(interactiveType, { key: 'Enter' });

await waitFor(() => {
expect(getByRole('option')).toHaveTextContent('something');
});
});

test('save with normal props', () => {
Expand All @@ -54,26 +61,14 @@ test('save with async prop', () => {
// need assertions here
});

test('change value in dialog box', () => {
const spy = vi.spyOn(AutoComplete, 'AutoComplete');
spy.mockImplementation((props: any) => {
const { form, onChange } = props;
test('change value in dialog box', async () => {
render(searchDialog(defaultProps));
const [interactiveType] = screen.getAllByTestId('autocomplete-element');
interactiveType.focus();
fireEvent.keyDown(interactiveType, { key: 'ArrowDown' });
fireEvent.keyDown(interactiveType, { key: 'Enter' });

return (
<div data-testid="searchDialogBox">
<input
onChange={(value) => {
onChange(value);
form.setFieldValue(value);
}}
/>
</div>
);
await waitFor(() => {
expect(screen.getByRole('option')).toHaveTextContent('something');
});
const { getByTestId } = render(searchDialog(defaultProps));
fireEvent.change(getByTestId('searchDialogBox').querySelector('input') as Element, {
target: { value: 'change' },
});

// need assertions here
});
23 changes: 22 additions & 1 deletion src/components/UI/SearchDialogBox/SearchDialogBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export interface SearchDialogBoxProps {
buttonOk?: string;
description?: string;
colorOk?: string;
fullWidth?: boolean;
placeholder?: string;
showTags?: boolean;
}

export const SearchDialogBox = (props: SearchDialogBoxProps) => {
Expand All @@ -45,10 +48,18 @@ export const SearchDialogBox = (props: SearchDialogBoxProps) => {
buttonOk = 'Save',
description = '',
colorOk,
fullWidth = false,
showTags = true,
placeholder,
} = props;

const [selectedOption, setSelectedOptions] = useState<any>(multiple ? [] : null);
const [asyncSelectedOptions, setAsyncSelectedOptions] = useState<Array<any>>([]);
const [optionsData, setOptionsData] = useState<any>(options);

useEffect(() => {
setOptionsData(options);
}, [options]);

useEffect(() => {
if (!asyncSearch) {
Expand All @@ -68,6 +79,13 @@ export const SearchDialogBox = (props: SearchDialogBoxProps) => {

const changeValue = (event: any, value: any) => {
setSelectedOptions(value);
if (multiple) {
const selectedIds = value.map((option: any) => option.id);
setOptionsData([
...value,
...options.filter((option: any) => !selectedIds.includes(option.id)),
]);
}
};

const selectedOptionsIds = multiple
Expand All @@ -86,14 +104,15 @@ export const SearchDialogBox = (props: SearchDialogBoxProps) => {
titleAlign="left"
colorOk={colorOk}
buttonOk={buttonOk}
fullWidth={fullWidth}
>
<div>
<FormControl fullWidth>
<AutoComplete
disableClearable={disableClearable}
asyncSearch={asyncSearch}
asyncValues={{ value: asyncSelectedOptions, setValue: setAsyncSelectedOptions }}
options={options}
options={optionsData}
optionLabel={optionLabel || 'label'}
additionalOptionLabel={additionalOptionLabel}
field={{ value: selectedOption }}
Expand All @@ -111,6 +130,8 @@ export const SearchDialogBox = (props: SearchDialogBoxProps) => {
renderTags={renderTags}
selectedOptionsIds={selectedOptionsIds}
multiple={multiple}
placeholder={placeholder}
showTags={showTags}
/>
</FormControl>
<div className={styles.Description} data-testid="description">
Expand Down
Loading

0 comments on commit 5f34414

Please sign in to comment.