Skip to content

Commit

Permalink
feat(edit-profile): migrates component to material ui
Browse files Browse the repository at this point in the history
Migrates the EditProfile component to material ui

re #144
  • Loading branch information
anguspiv committed Apr 6, 2023
1 parent 06217e9 commit 71ac900
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 92 deletions.
2 changes: 1 addition & 1 deletion pages/account/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { NextPage } from 'next';
import Head from 'next/head';
import { Flex } from '@chakra-ui/react';
import PageHeader from '@components/organisms/PageHeader';
import EditProfile from '@components/account/EditProfile';
import EditProfile from '@components/organisms/EditProfile';

const Account: NextPage = () => {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { UPLOAD_IMAGE } from '@components/molecules/ImageUpload';
import { EditProfileProps, EditProfile } from './EditProfile';

export default {
title: 'components/account/EditProfile',
title: 'Organisms/EditProfile',
component: EditProfile,
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import { useQuery as useQueryOrig, useMutation as useMutationOrig, QueryResult } from '@apollo/client';
import { fireEvent, render, waitFor } from '@testing-library/react';
import { fireEvent, render, waitFor, screen } from '@testing-library/react';
import { useDropzone } from 'react-dropzone';
import { useToast } from '@chakra-ui/react';
import logger from '@utils/logger';
import { EditProfile, EditProfileProps } from './EditProfile';

const useMutate = jest.fn();

const FILE = new File(['(⌐□_□)'], 'chucknorris.png', { type: 'image/png' });

jest.mock<typeof import('@apollo/client')>('@apollo/client', () => ({
Expand All @@ -33,6 +30,8 @@ jest.mock<typeof import('react-dropzone')>('react-dropzone', () => ({
const useQuery = useQueryOrig as jest.MockedFunction<typeof useQueryOrig>;
const useMutation = useMutationOrig as jest.MockedFunction<typeof useMutationOrig>;

const useMutate = jest.fn();

describe('<EditProfile />', () => {
// eslint-disable-next-line jest/no-hooks
beforeAll(() => {
Expand All @@ -44,7 +43,7 @@ describe('<EditProfile />', () => {
{ profile, ...getQuery } = {
profile: {},
},
results = {} as QueryResult<unknown, unknown>,
results = {} as QueryResult<unknown>,
) => {
logger.mockTypes(() => jest.fn());

Expand Down Expand Up @@ -94,9 +93,9 @@ describe('<EditProfile />', () => {
firstName: 'John',
};

const { getByDisplayValue } = setupEditProfile({}, { profile });
setupEditProfile({}, { profile });

await waitFor(() => expect(getByDisplayValue('John')).toBeInTheDocument());
await waitFor(() => expect(screen.getByDisplayValue('John')).toBeInTheDocument());
});

it('should save the form values', async () => {
Expand All @@ -109,11 +108,13 @@ describe('<EditProfile />', () => {
lastName: 'Doe',
};

const { getByDisplayValue, getAllByRole } = setupEditProfile({}, { profile });
setupEditProfile({}, { profile });

fireEvent.change(getByDisplayValue('John'), { target: { value: 'Jane' } });
fireEvent.change(screen.getByLabelText('First Name'), { target: { value: 'Jane' } });

fireEvent.click(getAllByRole('button', { name: 'Save' })[1]);
await waitFor(() => expect(screen.getAllByRole('button', { name: 'Save' })[1]).not.toBeDisabled());

fireEvent.click(screen.getAllByRole('button', { name: 'Save' })[1]);

await waitFor(() =>
expect(useMutate).toHaveBeenCalledWith({
Expand All @@ -132,9 +133,9 @@ describe('<EditProfile />', () => {
it('should set the form loading while waiting to fetch profile', () => {
expect.assertions(1);

const { getByRole } = setupEditProfile({}, { loading: true });
setupEditProfile({}, { loading: true });

expect(getByRole('button', { name: /Saving/i })).toBeDisabled();
expect(screen.getAllByRole('button', { name: /Save/i })[1]).toBeDisabled();
});

it('should set the form loading while waiting to save profile', async () => {
Expand All @@ -147,7 +148,7 @@ describe('<EditProfile />', () => {
expect(button).toBeDisabled();
});

it('should log the update profile error', async () => {
it('should display an error message', async () => {
expect.hasAssertions();

const error = new Error('Something went wrong');
Expand All @@ -159,58 +160,25 @@ describe('<EditProfile />', () => {
lastName: 'Doe',
};

const { getByDisplayValue, getAllByRole } = setupEditProfile({}, { profile });
setupEditProfile({}, { profile });

useMutate.mockImplementation(() => {
throw error;
});

fireEvent.change(getByDisplayValue('John'), { target: { value: 'Jane' } });

fireEvent.click(getAllByRole('button', { name: 'Save' })[1]);

await waitFor(() => expect(logger.error).toHaveBeenCalledWith(error));
});

it('should display an error message', async () => {
expect.hasAssertions();

const toast = jest.fn();

useToast.mockReturnValue(toast);

const error = new Error('Something went wrong');

const profile = {
id: '1',
userId: '1',
firstName: 'John',
lastName: 'Doe',
};

const { getByDisplayValue, getAllByRole } = setupEditProfile({}, { profile });
fireEvent.change(screen.getByDisplayValue('John'), { target: { value: 'Jane' } });

useMutate.mockImplementation(() => {
throw error;
});
await waitFor(() => expect(screen.getAllByRole('button', { name: 'Save' })[1]).not.toBeDisabled());

fireEvent.change(getByDisplayValue('John'), { target: { value: 'Jane' } });
fireEvent.click(screen.getAllByRole('button', { name: 'Save' })[1]);

fireEvent.click(getAllByRole('button', { name: 'Save' })[1]);
await waitFor(() => expect(logger.error).toHaveBeenCalledWith(error));

await waitFor(() =>
expect(toast.mock.calls[0][0]).toMatchObject({
status: 'error',
}),
);
await waitFor(() => expect(screen.getByText('Error saving profile')).toBeInTheDocument());
});

it('should display an succes message', async () => {
expect.assertions(1);

const toast = jest.fn();

useToast.mockReturnValue(toast);
expect.hasAssertions();

const profile = {
id: '1',
Expand All @@ -225,21 +193,19 @@ describe('<EditProfile />', () => {

fireEvent.change(getByDisplayValue('John'), { target: { value: 'Jane' } });

await waitFor(() => expect(screen.getAllByRole('button', { name: 'Save' })[1]).not.toBeDisabled());

fireEvent.click(getAllByRole('button', { name: 'Save' })[1]);

await waitFor(() =>
expect(toast.mock.calls[0][0]).toMatchObject({
status: 'success',
}),
);
await waitFor(() => expect(screen.getByText('Profile saved')).toBeInTheDocument());
});

it('should display the image upload form', () => {
expect.assertions(1);

const { getByTestId } = setupEditProfile();
setupEditProfile();

expect(getByTestId('image-upload-form')).toBeInTheDocument();
expect(screen.getByTestId('image-upload-form')).toBeInTheDocument();
});

// eslint-disable-next-line jest/no-disabled-tests
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useState, useEffect } from 'react';
import { Box, Center, useToast } from '@chakra-ui/react';
import { Alert, Box, Snackbar } from '@mui/material';
import { useQuery, useMutation } from '@apollo/client';
import ProfileForm from '@components/account/ProfileForm';
import ProfileForm from '@components/molecules/ProfileForm';
import ImageUpload from '@components/molecules/ImageUpload';
import { GET_PROFILE, UPDATE_PROFILE } from '@graphql/queries';
import logger from '@utils/logger';
Expand All @@ -10,11 +10,15 @@ import logger from '@utils/logger';
export interface EditProfileProps {}

export function EditProfile() {
const toast = useToast();
const { data, loading } = useQuery(GET_PROFILE);
const [updateProfile] = useMutation(UPDATE_PROFILE);
const [isLoading, setIsLoading] = useState(loading);
const [userProfile, setUserProfile] = useState(data?.profile || {});
const [alert, setAlert] = useState<Alert>({ open: false, message: '', severity: 'success' });

const handleMessageClose = () => {
setAlert({ open: false, message: '', severity: 'success' });
};

const { avatar, ...profile } = userProfile;

Expand All @@ -35,21 +39,18 @@ export function EditProfile() {

setUserProfile(updated?.data?.updateProfile || {});

toast({
title: 'Profile saved!',
description: 'Changes saved successfully.',
status: 'success',
duration: 9000,
isClosable: true,
setAlert({
open: true,
message: 'Profile saved',
severity: 'success',
});
} catch (err) {
logger.error(err);
toast({
title: 'Error saving profile',
description: 'Please try again later.',
status: 'error',
duration: 9000,
isClosable: true,

setAlert({
open: true,
message: 'Error saving profile',
severity: 'error',
});
}

Expand All @@ -64,34 +65,43 @@ export function EditProfile() {

setUserProfile(updated?.data?.updateProfile || {});

toast({
title: 'Avatar updated',
description: 'Your avatar has been updated',
status: 'success',
duration: 5000,
isClosable: true,
setAlert({
open: true,
message: 'Avatar updated',
severity: 'success',
});
} catch (err) {
logger.error(err);

toast({
title: 'Error Saving Avatar',
description: 'We could not save your avatar. Please try again.',
status: 'error',
duration: 9000,
isClosable: true,
setAlert({
open: true,
message: 'Error Saving Avatar',
severity: 'error',
});
}

setIsLoading(false);
};

return (
<Box data-testid="edit-profile" p={4} maxW="xl" width="100%">
<Center mb={4}>
<Box data-testid="edit-profile" sx={{ p: 4, width: '100%', maxWidth: 640 }}>
<Box sx={{ mb: 4, textAlign: 'center' }}>
<ImageUpload onUpload={onAvatarUpload} placeholder={avatar} />
</Center>
</Box>
<ProfileForm profile={profile} onSubmit={onSubmit} loading={isLoading} />
<Snackbar
open={alert.open}
autoHideDuration={6000}
onClose={handleMessageClose}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
>
<Alert sx={{ width: '100%' }} onClose={handleMessageClose} severity={alert.severity}>
{alert.message}
</Alert>
</Snackbar>
</Box>
);
}
Expand Down
File renamed without changes.
5 changes: 5 additions & 0 deletions types/Alert.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
interface Alert {
open: boolean;
message: string;
severity: 'error' | 'warning' | 'info' | 'success';
}

0 comments on commit 71ac900

Please sign in to comment.