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

Contact import automation #2992

Merged
merged 40 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
4c0e0c8
first stab at contact import ui
akanshaaa19 Jul 23, 2024
d43bb62
upload contacts api
akanshaaa19 Jul 23, 2024
fae7127
Merge branch 'master' of github.com:glific/glific-frontend into featu…
akanshaaa19 Jul 23, 2024
5ab6226
added status
akanshaaa19 Jul 26, 2024
0f3e3ec
added support for downloading csv
akanshaaa19 Aug 8, 2024
c3dd29e
Merge branch 'master' of github.com:glific/glific-frontend into featu…
akanshaaa19 Aug 8, 2024
dd6e625
added move contacts
akanshaaa19 Aug 8, 2024
7f40de7
fixed csv issue
akanshaaa19 Aug 8, 2024
3c634e2
Merge branch 'master' of github.com:glific/glific-frontend into featu…
akanshaaa19 Aug 8, 2024
9fe5f36
changed cypress branch
akanshaaa19 Aug 8, 2024
7bc6d0f
fixed test cases
akanshaaa19 Aug 8, 2024
51b9eab
updated backend branch
akanshaaa19 Aug 9, 2024
fae3972
changed cypress branch
akanshaaa19 Aug 9, 2024
16106d3
updated backend branch
akanshaaa19 Aug 9, 2024
e6f6164
updated backend branch
akanshaaa19 Aug 9, 2024
4db15a8
fixed move contacts api
akanshaaa19 Aug 9, 2024
5bfdcf3
fixed minor issue
akanshaaa19 Aug 9, 2024
da01ffe
deepscan fixes and test cases
akanshaaa19 Aug 9, 2024
17b0e12
added test cases
akanshaaa19 Aug 9, 2024
08115ef
Merge branch 'master' of github.com:glific/glific-frontend into featu…
akanshaaa19 Aug 12, 2024
a11a5ec
deepscan fixes and test cases
akanshaaa19 Aug 12, 2024
971c393
Merge branch 'master' into feature/bulk-contact
kurund Aug 20, 2024
c30fc1b
import screen cleanup
kurund Aug 20, 2024
0f94d7b
Merge branch 'feature/bulk-contact' of github.com:glific/glific-front…
akanshaaa19 Aug 20, 2024
1fbfa26
Merge branch 'master' of github.com:glific/glific-frontend into featu…
akanshaaa19 Aug 20, 2024
f9a42c4
worked on feedbacks
akanshaaa19 Aug 20, 2024
9e539be
Merge branch 'master' of github.com:glific/glific-frontend into featu…
akanshaaa19 Aug 21, 2024
dd42e28
fixes to cypress tests
kurund Aug 27, 2024
fc6411c
Merge remote-tracking branch 'origin/master' into feature/bulk-contact
kurund Aug 27, 2024
af8733f
update import buttons
kurund Aug 27, 2024
948ffae
design consistency, remove action button icon
kurund Aug 27, 2024
a7491c6
more cleanup
kurund Aug 27, 2024
d8f8bd3
added cancel in dialog
akanshaaa19 Aug 28, 2024
053a0a9
Merge branch 'feature/bulk-contact' of github.com:glific/glific-front…
akanshaaa19 Aug 28, 2024
8b8e885
worked on feedbacks
akanshaaa19 Aug 28, 2024
640c636
fixed deepsca issues
akanshaaa19 Aug 28, 2024
9321060
fixed test cases
akanshaaa19 Aug 28, 2024
d28ae47
added test cases
akanshaaa19 Aug 28, 2024
edad1d2
updated mocks
akanshaaa19 Aug 28, 2024
1a43366
update info svg
kurund Aug 28, 2024
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
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 feat/contacts-import
cd ..
cp -r cypress-testing/cypress cypress
yarn add [email protected]
Expand Down
4 changes: 2 additions & 2 deletions src/assets/images/icons/Info.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 10 additions & 1 deletion src/components/UI/Form/Checkbox/Checkbox.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
.Checkbox {
margin-bottom: -10px;
display: flex;
align-items: center;
flex-direction: column;
}

.Label {
Expand Down Expand Up @@ -33,3 +33,12 @@
.Disabled {
opacity: 60%;
}

.DangerText {
margin-left: 30px;
font-size: 12px;
margin-top: -12px;
line-height: 18px;
font-weight: 400;
color: #fb5c5c;
}
67 changes: 36 additions & 31 deletions src/components/UI/Form/Checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Checkbox as CheckboxElement, FormControlLabel } from '@mui/material';
import { Checkbox as CheckboxElement, FormControlLabel, FormHelperText } from '@mui/material';
import InfoIcon from 'assets/images/icons/Info.svg?react';
import Tooltip from 'components/UI/Tooltip/Tooltip';
import styles from './Checkbox.module.css';
Expand Down Expand Up @@ -38,37 +38,42 @@ export const Checkbox = ({

return (
<div className={`${styles.Checkbox} ${className} ${disabled && styles.Disabled}`}>
<FormControlLabel
control={
<CheckboxElement
data-testid="checkboxLabel"
classes={darkCheckbox ? { colorPrimary: styles.CheckboxColor } : null}
{...field}
color="primary"
checked={field.value ? field.value : false}
onChange={handleChangeCallback}
disabled={disabled}
/>
}
labelPlacement="end"
label={title}
classes={{
label: addLabelStyle ? styles.Label : undefined,
root: styles.Root,
}}
/>
{info?.title && infoType === 'tooltip' && (
<Tooltip tooltipClass={styles.Tooltip} title={info.title} placement="right">
<InfoIcon className={styles.InfoIcon} />
</Tooltip>
)}
{info && infoType === 'dialog' && (
<InfoIcon
className={styles.InfoIcon}
data-testid="info-icon"
onClick={() => handleInfoClick()}
<div>
<FormControlLabel
control={
<CheckboxElement
data-testid="checkboxLabel"
classes={darkCheckbox ? { colorPrimary: styles.CheckboxColor } : null}
{...field}
color="primary"
checked={field.value ? field.value : false}
onChange={handleChangeCallback}
disabled={disabled}
/>
}
labelPlacement="end"
label={title}
classes={{
label: addLabelStyle ? styles.Label : undefined,
root: styles.Root,
}}
/>
)}
{info?.title && infoType === 'tooltip' && (
<Tooltip tooltipClass={styles.Tooltip} title={info.title} placement="right">
<InfoIcon className={styles.InfoIcon} />
</Tooltip>
)}
{info && infoType === 'dialog' && (
<InfoIcon
className={styles.InfoIcon}
data-testid="info-icon"
onClick={() => handleInfoClick()}
/>
)}
</div>
{form && form.errors[field.name] && form.touched[field.name] ? (
<FormHelperText className={styles.DangerText}>{form.errors[field.name]}</FormHelperText>
) : null}
</div>
);
};
2 changes: 1 addition & 1 deletion src/components/UI/ImportButton/ImportButton.module.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.ImportIcon {
.FileIcon {
height: 24px;
width: 24px;
margin-right: 5px;
Expand Down
24 changes: 18 additions & 6 deletions src/components/UI/ImportButton/ImportButton.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
import { useRef } from 'react';
import ImportIcon from 'assets/images/icons/Flow/Import.svg?react';
import FileIcon from 'assets/images/icons/Document/Light.svg?react';
import { Button } from 'components/UI/Form/Button/Button';
import styles from './ImportButton.module.css';

export interface ImportButtonProps {
title: string;
onImport: any;
onImport?: any;
afterImport: any;
id?: string;
fileType?: string;
}

export const ImportButton = ({ title, onImport, afterImport }: ImportButtonProps) => {
export const ImportButton = ({
title,
onImport,
afterImport,
id,
fileType = '*',
}: ImportButtonProps) => {
const inputRef = useRef<HTMLInputElement>(null);
const changeHandler = (event: any) => {
const media = event.target.files[0];
const fileReader = new FileReader();
fileReader.onload = function setImport() {
afterImport(fileReader.result, media);
};
onImport();
if (onImport) {
onImport();
}
fileReader.readAsText(media);
};
return (
Expand All @@ -29,15 +39,17 @@ export const ImportButton = ({ title, onImport, afterImport }: ImportButtonProps
name="file"
onChange={changeHandler}
data-testid="import"
id={id}
accept={fileType}
/>
<Button
onClick={() => {
inputRef.current?.click();
}}
variant="outlined"
color="primary"
color="secondary"
>
<ImportIcon data-testid="import-icon" className={styles.ImportIcon} />
<FileIcon data-testid="import-icon" className={styles.FileIcon} />
{title}
</Button>
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ const SideMenus = ({ opened }: SideMenusProps) => {
variables: {
filter: {
is_read: false,
severity: 'critical',
},
},
fetchPolicy: 'cache-and-network',
Expand Down
3 changes: 2 additions & 1 deletion src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ export const ONBOARD_URL_UPDATE = `${GLIFIC_API_URL}/v1/onboard/update-registrat
export const ONBOARD_URL_REACT_OUT = `${GLIFIC_API_URL}/v1/onboard/reachout`;
export const ONBOARD_URL = `${GLIFIC_API_URL}/v1/onboard/setup`;
export const RECAPTCHA_CLIENT_KEY = envVariables.VITE_RECAPTCHA_CLIENT_KEY;
export const UPLOAD_CONTACTS_SAMPLE = 'https://storage.googleapis.com/cc-tides/sample_import.csv';
export const UPLOAD_CONTACTS_SAMPLE =
'https://storage.googleapis.com/cc-tides/sample_contacts_import.csv';
export const UPLOAD_CONTACTS_ADMIN_SAMPLE =
'https://storage.googleapis.com/cc-tides/sample_import_admin.csv';
export const REGISTRATION_HELP_LINK =
Expand Down
20 changes: 16 additions & 4 deletions src/containers/Collection/CollectionList/CollectionList.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,28 @@ import {
updateCollectionWaGroupQuery,
} from 'mocks/Groups';
import { setNotification } from 'common/notification';
import { setVariables } from 'common/constants';
import { CONTACTS_COLLECTION, setVariables } from 'common/constants';
import { setUserRolePermissions } from 'context/role';

const variables = {
filter: {
groupType: CONTACTS_COLLECTION,
},
opts: {
limit: 50,
offset: 0,
order: 'ASC',
orderWith: 'label',
},
};

const mocks = [
countCollectionQuery,
countCollectionQuery,
countCollectionQuery,
filterCollectionQuery,
filterCollectionQuery,
filterCollectionQuery,
filterCollectionQuery(variables),
filterCollectionQuery(variables),
filterCollectionQuery(variables),
getPublishedFlowQuery,
getPublishedFlowQuery,
getCollectionContactsQuery,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
.Container {
padding-left: 40px;
margin-top: 36px;
display: flex;
flex-direction: column;
justify-content: space-between;
width: 50%;
max-height: 65%;
background-color: #fff;
border-radius: 15px;
padding: 1rem 2rem;
}

.Instructions {
max-width: 500px;
color: #93a29b;
font-size: 16px;
}

Expand Down Expand Up @@ -67,10 +72,6 @@
cursor: not-allowed;
}

.FileIcon {
margin-right: 10px;
}

.WaitUpload {
font-size: 14px;
margin-left: 16px;
Expand Down Expand Up @@ -105,3 +106,8 @@
position: absolute;
right: 12px;
}

.Buttons button {
border-radius: 8px;
width: 30%;
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
import { render, screen, waitFor } from '@testing-library/react';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { MockedProvider } from '@apollo/client/testing';

import { BrowserRouter as Router } from 'react-router-dom';

import { getAllOrganizations } from 'mocks/Organization';
import { moveContacts } from 'mocks/Contact';

import { setUserSession } from 'services/AuthService';
import { setNotification } from 'common/notification';
import { AdminContactManagement } from './AdminContactManagement';

const mocks = [...getAllOrganizations, moveContacts];
const mocks = getAllOrganizations;

setUserSession(JSON.stringify({ roles: [{ label: 'Admin' }], organization: { id: '1' } }));

const contactManagement = (
<MockedProvider mocks={mocks} addTypename={false}>
<Router>
<AdminContactManagement />
<AdminContactManagement setShowStatus={vi.fn()} />
</Router>
</MockedProvider>
);
Expand All @@ -43,7 +41,7 @@ test('Admin contact management form renders correctly', async () => {
test('the page should have a disabled upload button by default', async () => {
render(contactManagement);

const uploadButton = await screen.getByTestId('uploadButton');
const uploadButton = await screen.getByTestId('moveContactsBtn');
expect(uploadButton).toBeInTheDocument();
expect(uploadButton).toHaveAttribute('disabled');
});
Expand All @@ -63,10 +61,11 @@ test('Files other than .csv should raise a warning message upon upload', async (
});
});

test('Success Notification should be called upon successful CSV upload', async () => {
test('it removes the selected file', async () => {
render(contactManagement);

// Valid CSV
fireEvent.click(screen.getByTestId('uploadFile'));

const csvContent = `name,phone,collection
John Doe,919876543210,"Optin collection,Optout Collection"
Virat Kohli,919876543220,Cricket`;
Expand All @@ -76,15 +75,15 @@ test('Success Notification should be called upon successful CSV upload', async (
const fileInput = screen.getByTestId('uploadFile');
userEvent.upload(fileInput, file);
});

await waitFor(() => {
// the filename should be visible instead of Select .csv after upload
expect(screen.getByText('test.csv')).toBeInTheDocument();
});

const uploadBtn = screen.getByTestId('uploadButton');
userEvent.click(uploadBtn);
fireEvent.click(screen.getByTestId('cross-icon'));

await waitFor(() => {
expect(setNotification).toHaveBeenCalled();
expect(screen.queryByText('test.csv')).not.toBeInTheDocument();
});
});
Loading
Loading