-
Notifications
You must be signed in to change notification settings - Fork 18
adding scenarios and adding screen #19
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
base: master
Are you sure you want to change the base?
Changes from all commits
b5cd8d9
b758f13
f983349
b205869
0a58355
f9064ab
ed2c7b3
767783d
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 |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| export default { | ||
| useReactotron: __DEV__, | ||
| useFixtures: false, | ||
| useStorybook: false | ||
| useFixtures: false, | ||
| useStorybook: false, | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import moment, { months } from 'moment' | ||
| import 'moment/locale/pt-br' | ||
|
|
||
| const setLanguage = () => { | ||
| moment.locale('pt-br', { | ||
| weekdays: 'Domingo_Segunda_Terça_Quarta_Quinta_Sexta_Sábado'.split('_'), | ||
| months: 'janeiro_fevereiro_março_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro'.split('_') | ||
| }) | ||
| } | ||
|
|
||
| export default { setLanguage } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| // @flow | ||
|
|
||
| import { values } from 'lodash' | ||
|
|
||
| export const FILTERS = { | ||
| ALL: 'Todos', | ||
| TODAY: 'Hoje', | ||
| THIS_WEEK : 'Esta Semana', | ||
| LATE: 'Atrasados' | ||
| } | ||
| export const Filters = values(FILTERS) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,103 +1,192 @@ | ||
| // @flow | ||
| import React, { useCallback, useState, useEffect } from 'react' | ||
| import { View, Text, ImageBackground, Image, TouchableOpacity, FlatList } from 'react-native' | ||
| import React, { useState, useEffect } from 'react' | ||
| import { View, Text, TextInput, ImageBackground, Image, TouchableOpacity, FlatList, ActivityIndicator, Modal, Picker } from 'react-native' | ||
| import { useDispatch, useSelector } from 'react-redux' | ||
|
|
||
| import ToDo from '../Components/ToDo' | ||
| import TogglableText from '../Components/TogglableText' | ||
|
|
||
| import { actions as ToDosUIActions } from '../Redux/Ui' | ||
| import ToDoEntitySelectors from '../Selectors/Entity' | ||
| import ToDoUISelections from '../Selectors/Ui' | ||
| import { actions as UIActions } from '../Redux/Ui' | ||
| import { actions as EntityActions} from '../Redux/Entity' | ||
|
|
||
| import ToDoEntitySelectors from '../Selectors/Entity' //obs | ||
| import ToDoUISelections from '../Selectors/Ui' //obs | ||
|
|
||
| import styles from './ToDoScreen.style' | ||
| import { Images } from '../../../Themes' | ||
|
|
||
| import { Filters } from '../Constants' | ||
|
|
||
| import type { StackNavigationProp } from '@react-navigation/stack' | ||
|
|
||
| import MomentConfig from '../../../Config/MomentConfig' | ||
| import moment from 'moment' | ||
| import colors from '../../../Themes/Colors' | ||
|
|
||
| type Props = { | ||
| navigation: StackNavigationProp | ||
| } | ||
|
|
||
| //Tranlate Moment | ||
| MomentConfig.setLanguage() | ||
|
|
||
| const ToDoScreen = ({ navigation }: Props) => { | ||
| // Redux Actions | ||
| const dispatch = useDispatch() | ||
| const getToDos = useCallback(() => dispatch(ToDosUIActions.request())) | ||
| //const getToDos = useCallback(() => dispatch(ToDosUIActions.request())) | ||
|
|
||
| // State | ||
| const [selectedFilterIndex, setFilterIndex] = useState(0) | ||
| const [add, setAdd] = useState(false) | ||
| const [isOpenScreenAdd, setIsOpenScreenAdd] = useState(false) | ||
|
|
||
| // Selectors | ||
| const sortedToDos = useSelector(ToDoEntitySelectors.sortedToDos) | ||
| const filteredToDos = useSelector(ToDoEntitySelectors.filteredToDos) | ||
| const isEmpty = useSelector(ToDoEntitySelectors.isEmpty) | ||
| const selectedFilterIndex = useSelector(ToDoUISelections.selectedFilterIndex) | ||
| const fetching = useSelector(ToDoUISelections.fetching) | ||
| const error = useSelector(ToDoUISelections.error) | ||
|
|
||
| // Lifecycle Methods | ||
| useEffect(() => { | ||
| getToDos() | ||
| }, []) | ||
|
|
||
| // Consts | ||
| const filterList = ['All', 'Today', 'This week', 'This month'] | ||
| dispatch(UIActions.request()) | ||
| }, [dispatch]) | ||
|
|
||
| return ( | ||
| <ImageBackground source={Images.appBackground} style={styles.background}> | ||
| <HeaderContainer onPressSearch={() => {}} /> | ||
| <View style={styles.tasksContainer}> | ||
| <FilterListContainer | ||
| filterList={filterList} | ||
| selectedFilter={selectedFilterIndex} | ||
| onPressFilter={setFilterIndex} | ||
| filterList={Filters} | ||
| selectedFilter={selectedFilterIndex} //-- | ||
| onPressFilter={index => dispatch(UIActions.setSelectedFilterIndex({index}))} | ||
| /> | ||
| {!fetching && !error && !!sortedToDos && ( | ||
| <FlatList | ||
| style={{ marginLeft: 12 }} | ||
| data={sortedToDos} | ||
| keyExtractor={(item, index) => `${item.id}-${index}-${item.title}`} | ||
| renderItem={({ item }) => ( | ||
| <ToDo onPressText={() => {}} toggleToDo={() => {}} text={item.title} toggled={item.isDone} /> | ||
| )} | ||
| /> | ||
| )} | ||
| <ListContainer | ||
|
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. Gostei dessa decisão de extrair o componente de lista. Isso limpa o código dessa tela, e deixa o propósito do componente bem evidente. |
||
| filteredToDos = {filteredToDos} | ||
| fetching = {fetching} | ||
| error = {error} | ||
| dispatch = {dispatch} | ||
| /> | ||
| </View> | ||
| <FloatingButton onPress={() => {}} /> | ||
| <FloatingButton onPress={() => setIsOpenScreenAdd(true)} /> | ||
| <Modal transparent={true} visible ={isOpenScreenAdd} animationType="slide"> | ||
| <View style={styles.container}> | ||
| <View style={styles.flexModalContainer}> | ||
| <CloseButton onPress = {() => setIsOpenScreenAdd(false)}/> | ||
| <TextInput style={styles.textInput} placeholder='Novo Lembrete' placeholderTextColor ={colors.c600}/> | ||
| <AddDate/> | ||
| <PriorityList/> | ||
| <FloatingButtonAdd onPress = {() => setAdd(true)}/> | ||
| </View> | ||
| </View> | ||
| </Modal> | ||
| </ImageBackground> | ||
| ) | ||
| } | ||
|
|
||
| const FloatingButton = ({ onPress }) => ( | ||
| <TouchableOpacity onPress={onPress} style={styles.floatingButton}> | ||
| <Image source={Images.add['36px']} /> | ||
| </TouchableOpacity> | ||
| ) | ||
|
|
||
| const FilterListContainer = ({ filterList, selectedFilter, onPressFilter }) => ( | ||
| <View style={styles.filterContainer}> | ||
| <FlatList | ||
| bounces={false} | ||
| keyboardShouldPersistTaps='handled' | ||
| showsHorizontalScrollIndicator={false} | ||
| horizontal | ||
| data={filterList} | ||
| keyExtractor={(item, index) => `${index}-${item}`} | ||
| renderItem={({ item, index }) => ( | ||
| <TogglableText toggled={selectedFilter === index} text={item} onPressText={() => onPressFilter(index)} /> | ||
| )} | ||
| /> | ||
| </View> | ||
| ) | ||
|
|
||
| const HeaderContainer = ({ onPressSearch }) => ( | ||
| <View style={styles.headerContainer}> | ||
| <View> | ||
| <Text style={styles.displayDateName}>Today</Text> | ||
| <Text style={styles.displayDateName}>Hoje</Text> | ||
| <Text style={styles.date}>{moment().format('dddd, DD MMMM')}</Text> | ||
| </View> | ||
| <TouchableOpacity activeOpacity={0.7} onPress={onPressSearch} style={styles.searchContainer}> | ||
| <Image source={Images.search['24px']} /> | ||
| </TouchableOpacity> | ||
| </View> | ||
| ) | ||
|
|
||
| const FilterListContainer = ({ filterList, selectedFilter, onPressFilter }) => ( | ||
| <View style={styles.filterContainer}> | ||
| <FlatList | ||
| bounces={false} | ||
| keyboardShouldPersistTaps='handled' | ||
| showsHorizontalScrollIndicator={false} | ||
| horizontal | ||
| data={filterList} | ||
| keyExtractor={(item, index) => `${index}-${item}`} | ||
| renderItem={({ item, index }) => ( | ||
| <TogglableText | ||
| toggled={selectedFilter === index} text={item} onPressText={() => onPressFilter(index)} | ||
| /> | ||
| )} | ||
| /> | ||
| </View> | ||
| ) | ||
|
|
||
| const ListContainer = ({filteredToDos,fetching,error,dispatch}) => ( | ||
| <> | ||
| {!!fetching && | ||
| <View style = {styles.fetchingCircle}> | ||
| <ActivityIndicator size="large" color = "#000"/> | ||
| </View> | ||
| } | ||
| {Object.entries(filteredToDos).length == 0 ? <EmptyContainer/> : | ||
| <> | ||
| <FlatList | ||
| style={{ marginLeft: 12 }} | ||
| data={filteredToDos} | ||
| keyExtractor={(item, index) => `${item.id}-${index}-${item.title}`} | ||
| renderItem={({ item }) => ( | ||
| <ToDo onPressText={() => {}} toggleToDo={() => { | ||
| dispatch(EntityActions.toggleToDo({id: item.id}))}} | ||
| text={item.title} toggled={item.isDone} /> | ||
| )} | ||
| /> | ||
| </> | ||
| } | ||
| </> | ||
| ) | ||
|
|
||
| const EmptyContainer = () => ( | ||
| <View style={styles.emptyContainer}> | ||
| <Image source={Images.sol['36px']} /> | ||
| <Text style = {styles.displayEmptyName}>Tudo Limpo!</Text> | ||
| <Text style = {styles.displayEmptyText}>Adicione um novo lembrete tocando no '+'.</Text> | ||
| </View> | ||
| ) | ||
|
|
||
| const FloatingButton = ({ onPress }) => ( | ||
|
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. Esses componentes dentro desse arquivo são bem pequenos, mas ainda assim, merecem seu próprio arquivo, seu próprio arquivo de estilos, seu próprio registro no Storybook, etc. Inclusive, são esses componentes pequenos que são super reutilizáveis e não podem estar perdidos dentro de um arquivo de tela. |
||
| <TouchableOpacity onPress={onPress} style={styles.floatingButton}> | ||
| <Image source={Images.add['36px']} /> | ||
| </TouchableOpacity> | ||
| ) | ||
|
|
||
| const FloatingButtonAdd = ({ onPress }) => ( | ||
| <TouchableOpacity style ={styles.floatingButtonAdd} onPressText={onPress}> | ||
| <Text style={styles.textAdd}>Adicionar</Text> | ||
| </TouchableOpacity> | ||
| ) | ||
|
|
||
| const CloseButton = ({ onPress }) => ( | ||
| <TouchableOpacity onPress={onPress}> | ||
| <Image source={Images.close['24px']} /> | ||
| </TouchableOpacity> | ||
| ) | ||
|
|
||
| const AddDate = ({}) => ( | ||
| <View> | ||
| <TouchableOpacity onPress={() => {}} style={styles.addDateTouch}> | ||
| <Image style={styles.addDateImage} source={Images.bell['24px']} /> | ||
| <Text style = {styles.addDateText}>Lembrar-me</Text> | ||
| </TouchableOpacity> | ||
| </View> | ||
| ) | ||
|
|
||
| const PriorityList = () =>{ | ||
|
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. Um erro bastante comum é guardar informações de estado de dados dentro do componente e não da tela. Por exemplo, a tela de "Novo Lembrete" precisa da prioridade, mas esse informação á perdida aqui dentro desse componente. Para isso, a gente geralmente usa o padrão controlled-component, onde a tela controla o componente. Ficaria algo assim: |
||
| const [priorityList, setPriorityList] = useState('Selecionar') | ||
| return ( | ||
| <View style ={styles.container}> | ||
| <Image style={styles.addDateImage} source ={Images.flag['24px']}/> | ||
| <Text style={styles.textPicker}>Prioridade</Text> | ||
| <Picker style = {styles.picker} priorityList = {priorityList} onValueChange = {(value, index) => setPriorityList(index)}> | ||
| <Picker.Item label='Selecionar' value='0'/> | ||
| <Picker.Item label='Baixa' value='1'/> | ||
| <Picker.Item label='Media' value='2'/> | ||
| <Picker.Item label='Alta' value='3'/> | ||
| </Picker> | ||
| </View> | ||
| ) | ||
| } | ||
|
|
||
|
|
||
| export default ToDoScreen | ||
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.
Com propriedades booleanas, é recomendado seguir o padrão de adicionar um
isouareno início da frase. Por exemplo:ou se você preferir (com tipagem do Typescipt):
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.
E seria interessante também deixar mais claro o que está sendo adicionado, aberto ou o que a data representa, por exemplo: