diff --git a/src/components/edit/RecentChangeHistory.tsx b/src/components/edit/RecentChangeHistory.tsx index 364076098..576116303 100644 --- a/src/components/edit/RecentChangeHistory.tsx +++ b/src/components/edit/RecentChangeHistory.tsx @@ -148,7 +148,7 @@ const UpdatedFields = ({ fields, doc }: UpdatedFieldsProps): JSX.Element | null // double access - doc[parent][child] if (field.includes('.')) { - var [parent, child] = field.split('.') + let [parent, child] = field.split('.') if (parent === 'content' && doc.__typename === DocumentTypeName.Area) { parent = 'areaContent' // I had to alias this in the query bc of the overlap with ClimbType } diff --git a/src/components/ui/micro/AlertDialogue.tsx b/src/components/ui/micro/AlertDialogue.tsx index f2346aa4b..c8e058b07 100644 --- a/src/components/ui/micro/AlertDialogue.tsx +++ b/src/components/ui/micro/AlertDialogue.tsx @@ -142,6 +142,7 @@ interface LeanAlertProps { description?: ReactNode children?: ReactNode className?: string + stackChildren?: boolean } /** * A reusable popup alert @@ -150,7 +151,7 @@ interface LeanAlertProps { * @param cancelAction A button of type `AlertDialogPrimitive.Action` that closes the alert on click. You can register an `onClick()` to perform some action. * @param noncancelAction Any kind of React component/button that doesn't close the alert on click. Use this if you want to perform an action on click and keep the alert open. */ -export const LeanAlert = ({ icon = null, title = null, description = null, children = DefaultOkButton, closeOnEsc = true, className = '' }: LeanAlertProps): JSX.Element => { +export const LeanAlert = ({ icon = null, title = null, description = null, children = DefaultOkButton, closeOnEsc = true, className = '', stackChildren = false }: LeanAlertProps): JSX.Element => { return ( @@ -164,7 +165,7 @@ export const LeanAlert = ({ icon = null, title = null, description = null, child {title} {description} -
+
{children}
diff --git a/src/components/users/ImportFromMtnProj.tsx b/src/components/users/ImportFromMtnProj.tsx index 8f7b76c6a..ceb8aa4ec 100644 --- a/src/components/users/ImportFromMtnProj.tsx +++ b/src/components/users/ImportFromMtnProj.tsx @@ -1,7 +1,7 @@ import { Fragment, useEffect, useState } from 'react' import { useRouter } from 'next/router' -import { Transition } from '@headlessui/react' -import { FolderArrowDownIcon, XMarkIcon } from '@heroicons/react/24/outline' +import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog' +import { FolderArrowDownIcon } from '@heroicons/react/24/outline' import { useMutation } from '@apollo/client' import { signIn, useSession } from 'next-auth/react' import { toast } from 'react-toastify' @@ -11,6 +11,7 @@ import { graphqlClient } from '../../js/graphql/Client' import { MUTATION_IMPORT_TICKS } from '../../js/graphql/gql/fragments' import { INPUT_DEFAULT_CSS } from '../ui/form/TextArea' import Spinner from '../ui/Spinner' +import { LeanAlert } from '../ui/micro/AlertDialogue' interface Props { isButton: boolean @@ -132,96 +133,75 @@ export function ImportFromMtnProj ({ isButton, username }: Props): JSX.Element { return ( <> {isButton && } -
-
- -
-
-
-
-
-
- {(errors != null) && errors.length > 0 && errors.map((err, i) =>

{err}

)} -

{showInput ? 'Input your Mountain Project profile link' : 'Import your ticks from Mountain Project'}

- {!showInput && -

- Don't lose your progress, bring it over to Open Beta. -

} - {showInput && -
-
- setMPUID(e.target.value)} - className={clx(INPUT_DEFAULT_CSS, 'w-full')} - placeholder='https://www.mountainproject.com/user/123456789/username' - /> -
-
} -
- {!showInput && - } - {showInput && - } - {!isButton && - } -
-
-
- -
-
-
+ + {show && ( +
-
+ )} + +
+ {!showInput && ( + + )} + + {showInput && ( + + )} + + {!isButton && ( + + )} + + { + setShow(false) + setErrors([]) + }} + > + + +
+ + )} ) } diff --git a/src/components/users/__tests__/ImportFromMtnProj.test.tsx b/src/components/users/__tests__/ImportFromMtnProj.test.tsx new file mode 100644 index 000000000..ca543f9c4 --- /dev/null +++ b/src/components/users/__tests__/ImportFromMtnProj.test.tsx @@ -0,0 +1,96 @@ +import React from 'react' +import { render, fireEvent, waitFor, screen, act } from '@testing-library/react' +import { MockedProvider } from '@apollo/client/testing' +import ImportFromMtnProj from '../ImportFromMtnProj' +import '@testing-library/jest-dom/extend-expect' + +jest.mock('next-auth/react', () => ({ + useSession: jest.fn(() => ({ status: 'authenticated' })) +})) + +jest.mock('next/router', () => ({ + useRouter: jest.fn(() => ({ replace: jest.fn() })) +})) + +jest.mock('../../../js/graphql/Client', () => ({ + + graphqlClient: jest.fn() +})) + +jest.mock('react-toastify', () => ({ + toast: { + info: jest.fn(), + error: jest.fn() + } +})) + +describe('', () => { + it('renders without crashing', () => { + render( + + + + ) + }) + + it('renders a button when isButton prop is true', () => { + render( + + + + ) + + const button = screen.getByText('Import ticks') + expect(button).toBeInTheDocument() + }) + + it('renders modal on button click', async () => { + render( + + + + ) + + const button = screen.getByText('Import ticks') + await waitFor(() => { + act(() => { + fireEvent.click(button) + }) + }) + + await waitFor(() => { + const modalText = screen.getByText('Input your Mountain Project profile link') + expect(modalText).toBeInTheDocument() + }) + }) + + it('accepts input for the Mountain Project profile link', async () => { + render( + ) + + // Simulate a click to open the modal. + const openModalButton = screen.getByText('Import ticks') + await waitFor(() => { + act(() => { + fireEvent.click(openModalButton) + }) + }) + + // Use findBy to wait for the input field to appear. + const inputField = await screen.findByPlaceholderText('https://www.mountainproject.com/user/123456789/username') + + if (!(inputField instanceof HTMLInputElement)) { + throw new Error('Expected an input field') + } + + // Simulate entering a Mountain Project URL. + + await waitFor(() => { + act(() => { + fireEvent.change(inputField, { target: { value: 'https://www.mountainproject.com/user/123456789/sampleuser' } }) + }) + }) + + expect(inputField.value).toBe('https://www.mountainproject.com/user/123456789/sampleuser') + }) +})