diff --git a/__tests__/__snapshots__/storyshots.test.js.snap b/__tests__/__snapshots__/storyshots.test.js.snap index a8653fec1..4b76d7a0e 100644 --- a/__tests__/__snapshots__/storyshots.test.js.snap +++ b/__tests__/__snapshots__/storyshots.test.js.snap @@ -1,5 +1,122 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Storyshots Component/QueryInfo Basic 1`] = ` +
+
+
+ +
+ Update the module successfully! +
+
+`; + +exports[`Storyshots Component/QueryInfo Basic With Dismiss 1`] = ` +
+
+`; + +exports[`Storyshots Component/QueryInfo Error 1`] = ` +
+
+
+ +
+ An error occurred. Please try again. +
+
+`; + +exports[`Storyshots Component/QueryInfo Error With Dismiss 1`] = ` +
+
+`; + +exports[`Storyshots Component/QueryInfo With Loading 1`] = ` +
+
+ + Sending the request... + +
+`; + exports[`Storyshots Components/AdditionalResources Basic 1`] = `
{ + it('should display successful state', () => { + expect.assertions(1) + + render( + + ) + + expect(screen.getByText('Submitted successfully')).toBeInTheDocument() + }) + + it('should display loading state', () => { + expect.assertions(1) + + render( + + ) + + expect(screen.getByText('Loading message...')).toBeInTheDocument() + }) + + it('should display error state', () => { + expect.assertions(1) + + render( + + ) + + expect( + screen.getByText('An error occurred. Please try again.') + ).toBeInTheDocument() + }) + + it('should render nothing when there is no data, error, and loading', () => { + expect.assertions(2) + + render( + + ) + + expect( + screen.queryByText('Submitted the item successfully!') + ).not.toBeInTheDocument() + expect(screen.queryByText('Loading message...')).not.toBeInTheDocument() + }) +}) diff --git a/components/QueryInfo/QueryInfo.tsx b/components/QueryInfo/QueryInfo.tsx new file mode 100644 index 000000000..37ebdc71f --- /dev/null +++ b/components/QueryInfo/QueryInfo.tsx @@ -0,0 +1,67 @@ +import { get } from 'lodash' +import React from 'react' +import { Spinner } from 'react-bootstrap' +import styles from '../../scss/queryInfo.module.scss' +import Alert from '../Alert' + +type QueryInfo = { + data: T + loading: boolean + error: string + texts: { + loading: string + data: string + } + dismiss?: { + onDismissError?: (id: number) => void + onDismissData?: (id: number) => void + } +} + +const QueryInfo = ({ + data, + loading, + error, + texts, + dismiss +}: QueryInfo) => { + if (loading) { + return ( +
+ + {texts.loading} +
+ ) + } + + if (error) { + return ( + + ) + } + + if (data) { + return ( + + ) + } + + return <> +} + +export default QueryInfo diff --git a/components/QueryInfo/index.tsx b/components/QueryInfo/index.tsx new file mode 100644 index 000000000..b2454455e --- /dev/null +++ b/components/QueryInfo/index.tsx @@ -0,0 +1 @@ +export { default } from './QueryInfo' diff --git a/components/admin/lessons/AdminLessonInputs/AdminLessonInputs.test.js b/components/admin/lessons/AdminLessonInputs/AdminLessonInputs.test.js index 4537e0b0d..2316ad86f 100644 --- a/components/admin/lessons/AdminLessonInputs/AdminLessonInputs.test.js +++ b/components/admin/lessons/AdminLessonInputs/AdminLessonInputs.test.js @@ -109,7 +109,7 @@ describe('AdminLessonInputs component', () => { it('Should add module', async () => { expect.assertions(1) - const { getByText, getByTestId, container } = render( + const { getByText, getByTestId } = render( { await waitFor(() => expect( - container.querySelector('.octicon-check-circle') + getByText('Added the item Functions successfully!') ).toBeInTheDocument() ) }) @@ -142,7 +142,7 @@ describe('AdminLessonInputs component', () => { it('Should update module', async () => { expect.assertions(1) - const { getByText, getByTestId, container } = render( + const { getByText, getByTestId } = render( { await waitFor(() => expect( - container.querySelector('.octicon-check-circle') + getByText('Updated the item Functions successfully!') ).toBeInTheDocument() ) }) @@ -176,7 +176,7 @@ describe('AdminLessonInputs component', () => { it('Should display error message if inputs are empty', async () => { expect.assertions(1) - const { getByText, getByTestId, container } = render( + const { getByText, getByTestId } = render( @@ -189,14 +189,16 @@ describe('AdminLessonInputs component', () => { await userEvent.click(submit) await waitFor(() => - expect(container.querySelector('.octicon-alert-fill')).toBeInTheDocument() + expect( + getByText('An error occurred. Please try again.') + ).toBeInTheDocument() ) }) it('Should display error message if network or GraphQL error', async () => { expect.assertions(1) - const { getByText, getByTestId, container } = render( + const { getByText, getByTestId } = render( @@ -213,7 +215,9 @@ describe('AdminLessonInputs component', () => { await userEvent.click(submit) await waitFor(() => - expect(container.querySelector('.octicon-alert-fill')).toBeInTheDocument() + expect( + getByText('An error occurred. Please try again.') + ).toBeInTheDocument() ) }) @@ -458,7 +462,66 @@ describe('AdminLessonInputs component', () => { await userEvent.click(submit) await waitFor(() => - expect(getByText('Updated the module successfully!')).toBeInTheDocument() + expect(getByText('Updated the item successfully!')).toBeInTheDocument() + ) + }) + + it('Should dismiss success message', async () => { + expect.assertions(1) + + const { getByText, getByTestId, queryByText, getByLabelText } = render( + + {}} + /> + + ) + + await userEvent.type(getByTestId('input0'), 'Functions', { + delay: 1 + }) + await userEvent.type(getByTestId('input2'), '1', { + delay: 1 + }) + await userEvent.type(getByTestId('textbox'), 'Functions are cool', { + delay: 1 + }) + + const submit = getByText('ADD MODULE') + await userEvent.click(submit) + + await userEvent.click(getByLabelText('Close alert')) + + await waitFor(() => + expect( + queryByText('Added the item Functions successfully!') + ).not.toBeInTheDocument() + ) + }) + + it('Should dismiss error message', async () => { + expect.assertions(1) + + const { getByText, getByTestId, queryByText, getByLabelText } = render( + + + + ) + + await userEvent.clear(getByTestId('input0')) + await userEvent.clear(getByTestId('textbox')) + + const submit = getByText('ADD MODULE') + await userEvent.click(submit) + + await userEvent.click(getByLabelText('Close alert')) + + await waitFor(() => + expect( + queryByText('An error occurred. Please try again.') + ).not.toBeInTheDocument() ) }) }) diff --git a/components/admin/lessons/AdminLessonInputs/AdminLessonInputs.tsx b/components/admin/lessons/AdminLessonInputs/AdminLessonInputs.tsx index 19fb6b995..36f79f479 100644 --- a/components/admin/lessons/AdminLessonInputs/AdminLessonInputs.tsx +++ b/components/admin/lessons/AdminLessonInputs/AdminLessonInputs.tsx @@ -7,15 +7,14 @@ import { } from '../../../../graphql' import { formChange } from '../../../../helpers/formChange' import { FormCard, MD_INPUT, Option, TextField } from '../../../FormCard' -import { AlertFillIcon, CheckCircleIcon } from '@primer/octicons-react' import styles from './adminLessonInputs.module.scss' -import { Spinner } from 'react-bootstrap' -import { get } from 'lodash' +import { get, isEqual } from 'lodash' import { ApolloError, OperationVariables, ApolloQueryResult } from '@apollo/client' +import QueryInfo from '../../../QueryInfo' type Module = { id: number; name: string; content: string; order: number } @@ -96,6 +95,12 @@ const AdminModuleInputs = ({ }) : useAddModuleMutation({ variables: mutationVariables }) + const [dataDiff, setDataDiff] = useState(data) + useEffect( + () => setDataDiff(prev => (isEqual(data, prev) ? undefined : data)), + [data] + ) + const [errorMsg, setErrorMsg] = useState(get(error, 'message', '')) const handleChange = async (value: string, propertyIndex: number) => { @@ -148,49 +153,33 @@ const AdminModuleInputs = ({ } } - const QueryStateMessage = () => { - if (loading) { - return ( -
- - Adding the module... -
- ) - } - - if (errorMsg) { - return ( -
- - Failed to add the module: {errorMsg} -
- ) - } + const dataText = () => { + const updateModule = get(data, 'updateModule') + const addModule = get(data, 'addModule') - if (data) { - const updateModule = get(data, 'updateModule') - const addModule = get(data, 'addModule') - - return ( -
- - - {updateModule ? 'Updated' : 'Added'} the module{' '} - - {get(addModule, 'name') || get(updateModule, 'name') || ''} - {' '} - successfully! - -
- ) - } - - return <> + return `${updateModule ? 'Updated' : 'Added'} the item ${ + get(addModule, 'name') || get(updateModule, 'name') || '' + } successfully!` } return (
- + { + setErrorMsg('') + setDataDiff(undefined) + }, + onDismissData: () => {} + }} + /> ( + +) + +export const BasicWithDismiss = () => ( + {} + }} + /> +) + +export const Error = () => ( + +) + +export const ErrorWithDismiss = () => ( + {} + }} + /> +) + +export const _WithLoading = () => ( + +)