-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LUN-357: Replace vocabulary detail modal with own route #306
Changes from 10 commits
fa4f629
c4dfe41
48e872e
9e2b0ce
460f962
2aa4801
738587e
f5b8990
b102c08
df5fb04
967acfc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import React from 'react' | ||
import { FlatList } from 'react-native' | ||
import styled from 'styled-components/native' | ||
|
||
import { Document } from '../constants/endpoints' | ||
import labels from '../constants/labels.json' | ||
import Title from './Title' | ||
import VocabularyListItem from './VocabularyListItem' | ||
|
||
const Root = styled.View` | ||
background-color: ${props => props.theme.colors.background}; | ||
height: 100%; | ||
width: 100%; | ||
padding: 0 ${props => props.theme.spacings.sm}; | ||
` | ||
|
||
interface VocabularyListScreenProps { | ||
documents: Document[] | ||
onItemPress: (index: number) => void | ||
} | ||
|
||
const VocabularyList = ({ documents, onItemPress }: VocabularyListScreenProps): JSX.Element => { | ||
const renderItem = ({ item, index }: { item: Document; index: number }): JSX.Element => ( | ||
<VocabularyListItem document={item} onPress={() => onItemPress(index)} /> | ||
) | ||
|
||
return ( | ||
<Root> | ||
<FlatList | ||
ListHeaderComponent={ | ||
<Title | ||
title={labels.exercises.vocabularyList.title} | ||
description={`${documents.length} ${documents.length === 1 ? labels.general.word : labels.general.words}`} | ||
/> | ||
} | ||
data={documents} | ||
renderItem={renderItem} | ||
keyExtractor={item => `${item.id}`} | ||
showsVerticalScrollIndicator={false} | ||
/> | ||
</Root> | ||
) | ||
} | ||
|
||
export default VocabularyList |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,11 +2,11 @@ import React, { ReactElement } from 'react' | |
import { widthPercentageToDP as wp } from 'react-native-responsive-screen' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is why I don't really like route specific component folders, once it is used in multiple routes it has to be moved/renamed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes i see, but the need to move and rename a file, just happend for the first time and will maybe occur once in a few weeks/months, whereas I am looking for files every day and finding them in a folder with ~100 files is a really a pain. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah there are different opinions about this which is definitely fine. I personally find it worse that I have to look in multiple folders to find the right file than to find the file in a large folder. No need to change this though, especially if you favor the other way. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it is now merged. you can base on it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Already on it 🚀 Assuming your comment is regarding #286 and not this discussion :D |
||
import styled from 'styled-components/native' | ||
|
||
import AudioPlayer from '../../../components/AudioPlayer' | ||
import ListItem from '../../../components/ListItem' | ||
import { ContentTextLight } from '../../../components/text/Content' | ||
import { Document } from '../../../constants/endpoints' | ||
import { getArticleColor } from '../../../services/helpers' | ||
import { Document } from '../constants/endpoints' | ||
import { getArticleColor } from '../services/helpers' | ||
import AudioPlayer from './AudioPlayer' | ||
import ListItem from './ListItem' | ||
import { ContentTextLight } from './text/Content' | ||
|
||
const StyledImage = styled.Image` | ||
margin-right: ${props => props.theme.spacings.sm}; | ||
|
@@ -29,12 +29,12 @@ const Speaker = styled.View` | |
padding-top: ${props => props.theme.spacings.sm}; | ||
` | ||
|
||
export interface VocabularyListItemProp { | ||
interface VocabularyListItemProps { | ||
document: Document | ||
setIsModalVisible?: () => void | ||
onPress: () => void | ||
} | ||
|
||
const VocabularyListItem = ({ document, setIsModalVisible }: VocabularyListItemProp): ReactElement => { | ||
const VocabularyListItem = ({ document, onPress }: VocabularyListItemProps): ReactElement => { | ||
const { article, word, document_image: documentImage } = document | ||
|
||
const title = <StyledTitle articleColor={getArticleColor(article)}>{article.value}</StyledTitle> | ||
|
@@ -43,13 +43,11 @@ const VocabularyListItem = ({ document, setIsModalVisible }: VocabularyListItemP | |
<StyledImage testID='image' source={{ uri: documentImage[0].image }} width={24} height={24} /> | ||
) : undefined | ||
|
||
const noop = () => undefined | ||
|
||
return ( | ||
<ListItem | ||
title={title} | ||
description={word} | ||
onPress={setIsModalVisible ?? noop} | ||
onPress={onPress} | ||
icon={icon} | ||
rightChildren={ | ||
<Speaker> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { fireEvent } from '@testing-library/react-native' | ||
import React from 'react' | ||
|
||
import labels from '../../constants/labels.json' | ||
import DocumentBuilder from '../../testing/DocumentBuilder' | ||
import { mockUseLoadAsyncWithData } from '../../testing/mockUseLoadFromEndpoint' | ||
import render from '../../testing/render' | ||
import VocabularyList from '../VocabularyList' | ||
|
||
jest.mock('../AudioPlayer', () => { | ||
const Text = require('react-native').Text | ||
return () => <Text>AudioPlayer</Text> | ||
}) | ||
|
||
describe('VocabularyList', () => { | ||
beforeEach(() => { | ||
jest.clearAllMocks() | ||
}) | ||
|
||
const onItemPress = jest.fn() | ||
const documents = new DocumentBuilder(2).build() | ||
|
||
it('should display vocabulary list', () => { | ||
mockUseLoadAsyncWithData(documents) | ||
|
||
const { getByText, getAllByText, getAllByTestId } = render( | ||
<VocabularyList documents={documents} onItemPress={onItemPress} /> | ||
) | ||
|
||
expect(getByText(labels.exercises.vocabularyList.title)).toBeTruthy() | ||
expect(getByText(`2 ${labels.general.words}`)).toBeTruthy() | ||
expect(getByText('Der')).toBeTruthy() | ||
expect(getByText('Spachtel')).toBeTruthy() | ||
expect(getByText('Das')).toBeTruthy() | ||
expect(getByText('Auto')).toBeTruthy() | ||
expect(getAllByText('AudioPlayer')).toHaveLength(2) | ||
expect(getAllByTestId('image')).toHaveLength(2) | ||
}) | ||
|
||
it('should call onItemPress with correct index', () => { | ||
const { getByText } = render(<VocabularyList documents={documents} onItemPress={onItemPress} />) | ||
|
||
expect(onItemPress).toHaveBeenCalledTimes(0) | ||
|
||
fireEvent.press(getByText('Auto')) | ||
|
||
expect(onItemPress).toHaveBeenCalledTimes(1) | ||
expect(onItemPress).toHaveBeenCalledWith(1) | ||
|
||
fireEvent.press(getByText('Spachtel')) | ||
|
||
expect(onItemPress).toHaveBeenCalledTimes(2) | ||
expect(onItemPress).toHaveBeenCalledWith(0) | ||
}) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just moved from
VocabularyListScreen