Skip to content

Commit

Permalink
Merge branch 'master' into unlink-discord-account
Browse files Browse the repository at this point in the history
  • Loading branch information
flacial committed Sep 4, 2022
2 parents 9664353 + e32c673 commit 1a3aa25
Show file tree
Hide file tree
Showing 17 changed files with 875 additions and 1,327 deletions.
1,255 changes: 302 additions & 953 deletions __tests__/__snapshots__/storyshots.test.js.snap

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion __tests__/pages/__snapshots__/reset.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,6 @@ exports[`ResetPassword Page Should render confirm success on success 1`] = `
<a
class="btn btn-primary btn-lg mb-3"
href="/curriculum"
role="button"
>
Continue to dashboard
</a>
Expand Down
9 changes: 9 additions & 0 deletions components/DropdownMenu.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import React from 'react'
import { render, fireEvent, screen, waitFor } from '@testing-library/react'
import { DropdownMenu } from './DropdownMenu'

// Imported to be able to use expect(...).toBeInTheDocument()
import '@testing-library/jest-dom'

const dropdownMenuItems = [
{ title: 'Lessons', path: '/admin/lessons', as: 'button' },
null,
Expand All @@ -22,6 +25,12 @@ describe('MdInput Component', () => {
expect(container).toMatchSnapshot()
})

test('Should display default title when no title is passed', () => {
const { queryByText } = render(<DropdownMenu items={dropdownMenuItems} />)

expect(queryByText('None')).toBeInTheDocument()
})

test('Should change value of testBtnOnClick upon click', () => {
dropdownMenuItems[0].onClick = val => (testBtnOnClick = val)

Expand Down
85 changes: 36 additions & 49 deletions components/DropdownMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react'
import DropdownButton from 'react-bootstrap/DropdownButton'
import React, { useState } from 'react'
import Dropdown from 'react-bootstrap/Dropdown'
import styles from '../scss/dropDown.module.scss'
import { DropDirection } from 'react-bootstrap/esm/DropdownContext'
import { ChevronRightIcon } from '@primer/octicons-react'

//a null item indicates a dropdown divider
export type Item = {
Expand All @@ -14,62 +14,49 @@ export type Item = {

type DropDownMenuProps = {
drop?: DropDirection
items: Item[]
title: string
size?: 'sm' | 'lg' | undefined
variant?:
| 'primary'
| 'secondary'
| 'success'
| 'info'
| 'warning'
| 'danger'
| 'none'
items?: Item[] | null
title?: string
//changes the underlying component CSS base class name
//https://react-bootstrap.github.io/components/dropdowns/#api
bsPrefix?: string
}

const ChevronRight = () => <ChevronRightIcon size={17} />

export const DropdownMenu: React.FC<DropDownMenuProps> = ({
drop = 'down',
variant = 'none',
title,
size,
items,
bsPrefix
title,
bsPrefix = ''
}) => {
const menuItems = items.map((item: Item, itemsIndex: number) =>
!item ? (
<Dropdown.Divider key={itemsIndex} />
) : (
<div className="text-center py-2 px-4" key={item.title}>
<Dropdown.Item
as={item.as || 'a'}
key={itemsIndex}
href={item.path}
onClick={() => item.onClick && item.onClick(item.title)}
bsPrefix={bsPrefix}
>
{item.title}
</Dropdown.Item>
</div>
)
)
const [activeItem, setActiveItem] = useState({ title })

return (
<>
<div className="d-none d-lg-block">
<DropdownButton
title={title}
variant={variant}
size={size}
drop={drop}
bsPrefix={styles.title}
>
{menuItems}
</DropdownButton>
</div>
<div className="d-lg-none">{menuItems}</div>
</>
<Dropdown bsPrefix={bsPrefix}>
<Dropdown.Toggle bsPrefix={styles.dropdown} id="dropdown-lesson">
{activeItem.title || 'None'}
<ChevronRight />
</Dropdown.Toggle>

<Dropdown.Menu className={styles.dropdown__menu}>
{items?.map((item, index) =>
item ? (
<Dropdown.Item
key={`${item?.title}-${index}`}
onClick={() => {
item?.onClick?.(item)

setActiveItem({
title: item?.title
})
}}
>
{item?.title}
</Dropdown.Item>
) : (
<Dropdown.Divider key={index} />
)
)}
</Dropdown.Menu>
</Dropdown>
)
}
95 changes: 95 additions & 0 deletions components/QueryInfo/QueryInfo.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import React from 'react'
import QueryInfo from './'
import { render, screen } from '@testing-library/react'

// Imported to be able to use .toBeInTheDocument()
import '@testing-library/jest-dom'

describe('QueryInfo component', () => {
it('should display successful state', () => {
expect.assertions(1)

render(
<QueryInfo
hide={false}
data={{
name: 'noob'
}}
loading={false}
error={''}
texts={{
loading: 'Loading message...',
data: 'Submitted successfully'
}}
/>
)

expect(screen.getByText('Submitted successfully')).toBeInTheDocument()
})

it('should display loading state', () => {
expect.assertions(1)

render(
<QueryInfo
hide={false}
data={{
name: 'noob'
}}
loading={true}
error={''}
texts={{
loading: 'Loading message...',
data: 'Submitted successfully'
}}
/>
)

expect(screen.getByText('Loading message...')).toBeInTheDocument()
})

it('should display error state', () => {
expect.assertions(1)

render(
<QueryInfo
hide={false}
data={{
name: 'noob'
}}
loading={false}
error={'Missing arguments'}
texts={{
loading: 'Loading message...',
data: 'Submitted successfully'
}}
/>
)

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(
<QueryInfo
hide={false}
data={undefined}
loading={false}
error={''}
texts={{
loading: 'Loading message...',
data: 'Submitted successfully'
}}
/>
)

expect(
screen.queryByText('Submitted the item successfully!')
).not.toBeInTheDocument()
expect(screen.queryByText('Loading message...')).not.toBeInTheDocument()
})
})
67 changes: 67 additions & 0 deletions components/QueryInfo/QueryInfo.tsx
Original file line number Diff line number Diff line change
@@ -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<T> = {
data: T
loading: boolean
error: string
texts: {
loading: string
data: string
}
dismiss?: {
onDismissError?: (id: number) => void
onDismissData?: (id: number) => void
}
}

const QueryInfo = <T,>({
data,
loading,
error,
texts,
dismiss
}: QueryInfo<T>) => {
if (loading) {
return (
<div className={styles.loading}>
<Spinner animation="grow" size="sm" />
<span>{texts.loading}</span>
</div>
)
}

if (error) {
return (
<Alert
alert={{
text: 'An error occurred. Please try again.',
type: 'urgent',
id: 1
}}
onDismiss={get(dismiss, 'onDismissError')}
key={error}
/>
)
}

if (data) {
return (
<Alert
alert={{
text: texts.data,
type: 'info',
id: 2
}}
onDismiss={get(dismiss, 'onDismissData')}
/>
)
}

return <></>
}

export default QueryInfo
1 change: 1 addition & 0 deletions components/QueryInfo/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './QueryInfo'
Loading

0 comments on commit 1a3aa25

Please sign in to comment.