Skip to content

Commit

Permalink
Merge pull request #1146 from CruGlobal/8393-user-preference
Browse files Browse the repository at this point in the history
[MPDX-8393] Add `useUserPreference` hook
  • Loading branch information
canac authored Oct 21, 2024
2 parents d59ffdd + d830fb2 commit 86d678b
Show file tree
Hide file tree
Showing 29 changed files with 490 additions and 379 deletions.
102 changes: 30 additions & 72 deletions pages/accountLists/[accountListId]/contacts/flows/setup.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,11 @@ import { HTML5Backend } from 'react-dnd-html5-backend';
import { useTranslation } from 'react-i18next';
import { v4 as uuidv4 } from 'uuid';
import { loadSession } from 'pages/api/utils/pagePropsHelpers';
import {
ContactFlowOption,
colorMap,
} from 'src/components/Contacts/ContactFlow/ContactFlow';
import { colorMap } from 'src/components/Contacts/ContactFlow/ContactFlow';
import { ContactFlowSetupColumn } from 'src/components/Contacts/ContactFlow/ContactFlowSetup/Column/ContactFlowSetupColumn';
import { UnusedStatusesColumn } from 'src/components/Contacts/ContactFlow/ContactFlowSetup/Column/UnusedStatusesColumn';
import { ContactFlowSetupDragLayer } from 'src/components/Contacts/ContactFlow/ContactFlowSetup/DragLayer/ContactFlowSetupDragLayer';
import { ContactFlowSetupHeader } from 'src/components/Contacts/ContactFlow/ContactFlowSetup/Header/ContactFlowSetupHeader';
import { useUpdateUserOptionsMutation } from 'src/components/Contacts/ContactFlow/ContactFlowSetup/UpdateUserOptions.generated';
import {
GetUserOptionsDocument,
GetUserOptionsQuery,
} from 'src/components/Contacts/ContactFlow/GetUserOptions.generated';
import { getDefaultFlowOptions } from 'src/components/Contacts/ContactFlow/contactFlowDefaultOptions';
import {
FlowOption,
Expand Down Expand Up @@ -51,7 +43,7 @@ const ContactFlowSetupPage: React.FC = () => {
const resetColumnsMessage = t(
'Since all columns have been removed, resetting columns to their default values',
);
const { options: userOptions, loading } = useFlowOptions();
const [userOptions, updateOptions, { loading }] = useFlowOptions();

useEffect(() => {
if (!userOptions.length) {
Expand All @@ -61,7 +53,6 @@ const ContactFlowSetupPage: React.FC = () => {
}
}, [userOptions]);

const [updateUserOptions] = useUpdateUserOptionsMutation();
const { appName } = useGetAppSettings();

const allUsedStatuses = flowOptions
Expand All @@ -71,49 +62,8 @@ const ContactFlowSetupPage: React.FC = () => {
(status) => !allUsedStatuses.includes(status),
);

const updateOptions = useCallback(
async (options: ContactFlowOption[]): Promise<void> => {
const stringified = JSON.stringify(options);
await updateUserOptions({
variables: {
key: 'flows',
value: stringified,
},
update: (cache, { data: updatedUserOption }) => {
const query = {
query: GetUserOptionsDocument,
};
const dataFromCache = cache.readQuery<GetUserOptionsQuery>(query);

if (dataFromCache) {
const filteredOld = dataFromCache.userOptions.filter(
(option) => option.key !== 'flows',
);

const data = {
userOptions: [
...filteredOld,
{
__typename: 'Option',
id: updatedUserOption?.createOrUpdateUserOption?.option.id,
key: 'flows',
value: stringified,
},
],
};
cache.writeQuery({ ...query, data });
}
enqueueSnackbar(t('User options updated!'), {
variant: 'success',
});
},
});
},
[],
);

const addColumn = (): Promise<void> => {
return updateOptions([
const addColumn = (): void => {
updateOptions([
...flowOptions,
{
name: 'Untitled',
Expand All @@ -138,27 +88,35 @@ const ContactFlowSetupPage: React.FC = () => {

const changeColor = (index: number, color: string): void => {
const temp = [...flowOptions];
temp[index].color = color;
temp[index] = { ...temp[index], color };
updateOptions(temp);
};

const moveStatus = (
originIndex: number,
destinationIndex: number,
draggedStatus: StatusEnum,
): void => {
const temp = [...flowOptions];
if (originIndex > -1) {
temp[originIndex].statuses = temp[originIndex].statuses.filter(
(status) => status !== draggedStatus,
);
}
if (destinationIndex > -1) {
temp[destinationIndex].statuses.push(draggedStatus);
}
updateOptions(temp);
setFlowOptions(temp);
};
const moveStatus = useCallback(
(
originIndex: number,
destinationIndex: number,
draggedStatus: StatusEnum,
): void => {
const temp = [...flowOptions];
if (originIndex > -1) {
temp[originIndex] = {
...temp[originIndex],
statuses: temp[originIndex].statuses.filter(
(status) => status !== draggedStatus,
),
};
}
if (destinationIndex > -1) {
temp[destinationIndex] = {
...temp[destinationIndex],
statuses: [...temp[destinationIndex].statuses, draggedStatus],
};
}
updateOptions(temp);
},
[flowOptions],
);

const changeTitle = (
event: React.ChangeEvent<HTMLInputElement>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ import { render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import TestRouter from '__tests__/util/TestRouter';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import { GetUserOptionsQuery } from 'src/components/Contacts/ContactFlow/GetUserOptions.generated';
import { MailchimpAccountQuery } from 'src/components/Settings/integrations/Mailchimp/MailchimpAccount.generated';
import { GetUsersOrganizationsAccountsQuery } from 'src/components/Settings/integrations/Organization/Organizations.generated';
import { PrayerlettersAccountQuery } from 'src/components/Settings/integrations/Prayerletters/PrayerlettersAccount.generated';
import { SetupStageQuery } from 'src/components/Setup/Setup.generated';
import { SetupProvider } from 'src/components/Setup/SetupProvider';
import { TestSetupProvider } from 'src/components/Setup/SetupProvider';
import useGetAppSettings from 'src/hooks/useGetAppSettings';
import theme from 'src/theme';
import Integrations from './index.page';
Expand Down Expand Up @@ -40,48 +38,36 @@ jest.mock('notistack', () => ({
}));
interface MocksProvidersProps {
children: JSX.Element;
setup?: string;
setup?: boolean;
}

const MocksProviders: React.FC<MocksProvidersProps> = ({ children, setup }) => (
const MocksProviders: React.FC<MocksProvidersProps> = ({
children,
setup = false,
}) => (
<ThemeProvider theme={theme}>
<TestRouter router={router}>
<GqlMockedProvider<{
GetUsersOrganizationsAccounts: GetUsersOrganizationsAccountsQuery;
MailchimpAccount: MailchimpAccountQuery;
PrayerlettersAccount: PrayerlettersAccountQuery;
GetUserOptions: GetUserOptionsQuery;
SetupStage: SetupStageQuery;
}>
mocks={{
GetUsersOrganizationsAccounts: {
userOrganizationAccounts: [
{
organization: {},
},
{
organization: {},
},
],
},
MailchimpAccount: { mailchimpAccount: [] },
PrayerlettersAccount: { prayerlettersAccount: [] },
SetupStage: {
user: {
setup: null,
<TestSetupProvider onSetupTour={setup}>
<GqlMockedProvider<{
GetUsersOrganizationsAccounts: GetUsersOrganizationsAccountsQuery;
MailchimpAccount: MailchimpAccountQuery;
PrayerlettersAccount: PrayerlettersAccountQuery;
}>
mocks={{
GetUsersOrganizationsAccounts: {
userOrganizationAccounts: [
{ organization: {} },
{ organization: {} },
],
},
userOptions: [
{
key: 'setup_position',
value: setup || '',
},
],
},
}}
onCall={mutationSpy}
>
<SetupProvider>{children}</SetupProvider>
</GqlMockedProvider>
MailchimpAccount: { mailchimpAccount: [] },
PrayerlettersAccount: { prayerlettersAccount: [] },
}}
onCall={mutationSpy}
>
{children}
</GqlMockedProvider>
</TestSetupProvider>
</TestRouter>
</ThemeProvider>
);
Expand Down Expand Up @@ -132,7 +118,7 @@ describe('Connect Services page', () => {

it('should show setup banner and open google', async () => {
const { findByText, getByRole, getByText } = render(
<MocksProviders setup="preferences.integrations">
<MocksProviders setup>
<Integrations />
</MocksProviders>,
);
Expand All @@ -141,10 +127,10 @@ describe('Connect Services page', () => {
).toBeInTheDocument();

//Accordions should be disabled
await waitFor(() => {
const label = getByText('Organization');
expect(() => userEvent.click(label)).toThrow();
});
expect(getByRole('button', { name: 'Organization' })).toHaveAttribute(
'aria-disabled',
'true',
);

const nextButton = getByRole('button', { name: 'Next Step' });

Expand All @@ -168,7 +154,7 @@ describe('Connect Services page', () => {
// Move to finish
userEvent.click(nextButton);
await waitFor(() => {
expect(mutationSpy).toHaveGraphqlOperation('UpdateUserOptions', {
expect(mutationSpy).toHaveGraphqlOperation('UpdateUserOption', {
key: 'setup_position',
value: 'finish',
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { useRouter } from 'next/router';
import React, { useEffect, useState } from 'react';
import { Button } from '@mui/material';
import { useSnackbar } from 'notistack';
import { useTranslation } from 'react-i18next';
import { loadSession } from 'pages/api/utils/pagePropsHelpers';
import { useUpdateUserOptionsMutation } from 'src/components/Contacts/ContactFlow/ContactFlowSetup/UpdateUserOptions.generated';
import { ChalklineAccordion } from 'src/components/Settings/integrations/Chalkline/ChalklineAccordion';
import { GoogleAccordion } from 'src/components/Settings/integrations/Google/GoogleAccordion';
import { TheKeyAccordion } from 'src/components/Settings/integrations/Key/TheKeyAccordion';
Expand All @@ -17,6 +15,7 @@ import { AccordionGroup } from 'src/components/Shared/Forms/Accordions/Accordion
import { StickyBox } from 'src/components/Shared/Header/styledComponents';
import { useAccountListId } from 'src/hooks/useAccountListId';
import useGetAppSettings from 'src/hooks/useGetAppSettings';
import { useUserPreference } from 'src/hooks/useUserPreference';
import { SettingsWrapper } from '../Wrapper';

const Integrations: React.FC = () => {
Expand All @@ -27,13 +26,15 @@ const Integrations: React.FC = () => {
);
const accountListId = useAccountListId() || '';
const { appName } = useGetAppSettings();
const { enqueueSnackbar } = useSnackbar();
const { onSetupTour } = useSetupContext();
const [setup, setSetup] = useState(0);

const setupAccordions = ['google', 'mailchimp', 'prayerletters.com'];

const [updateUserOptions] = useUpdateUserOptionsMutation();
const [_, setSetupPosition] = useUserPreference({
key: 'setup_position',
defaultValue: '',
});

const handleSetupChange = async () => {
if (!onSetupTour) {
Expand All @@ -42,17 +43,7 @@ const Integrations: React.FC = () => {
const nextNav = setup + 1;

if (setupAccordions.length === nextNav) {
await updateUserOptions({
variables: {
key: 'setup_position',
value: 'finish',
},
onError: () => {
enqueueSnackbar(t('Saving setup phase failed.'), {
variant: 'error',
});
},
});
setSetupPosition('finish');
push(`/accountLists/${accountListId}/setup/finish`);
} else {
setSetup(nextNav);
Expand Down
Loading

0 comments on commit 86d678b

Please sign in to comment.