-
Notifications
You must be signed in to change notification settings - Fork 0
/
todo-list.tsx
109 lines (102 loc) · 4.45 KB
/
todo-list.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import { createState, NimbusJSX, If, Then, Else, ForEach, State, contains, lowercase, or, eq, not, and } from '@zup-it/nimbus-backend-core'
import { sendRequest, log } from '@zup-it/nimbus-backend-core/actions'
import { Screen } from '@zup-it/nimbus-backend-express'
import { Lifecycle, Text, Column, Row, ScreenComponent, ScrollView, Stack, Positioned } from '@zup-it/nimbus-backend-layout'
import { NoteCard } from '../fragments/NoteCard'
import { Icon } from '../components/Icon'
import { SelectionGroup } from '../components/SelectionGroup'
import { TextInput } from '../components/TextInput'
import { Note, NoteSection } from '../types'
import { Separator } from '../fragments/Separator'
import { formatDate } from '../operations/format-date'
import { EditNote } from '../screens/edit-note'
import { CircularButton } from '../components/CircularButton'
function shouldRender(note: State<Note>, searchTerm: State<string>, doneFilter: State<'All' | 'To do' | 'Done'>) {
const lowerSearchTerm = lowercase(searchTerm)
const lowerTitle = lowercase(note.get('title'))
const lowerDescription = lowercase(note.get('description'))
const titleMatches = contains(lowerTitle, lowerSearchTerm)
const descriptionMatches = contains(lowerDescription, lowerSearchTerm)
const matchesText = or(titleMatches, descriptionMatches)
const matchesDone = and(eq(doneFilter, 'Done'), note.get('isDone'))
const matchesToDo = and(eq(doneFilter, 'To do'), not(note.get('isDone')))
const matchesDoneFilter = or(eq(doneFilter, 'All'), matchesDone, matchesToDo)
return and(matchesDoneFilter, matchesText)
}
function emptyNote(): Note {
return {
id: 0,
date: new Date().setUTCHours(0, 0, 0, 0),
title: '',
description: '',
isDone: false,
}
}
export const ToDoList: Screen = ({ navigator }) => {
const searchTerm = createState('searchTerm', '')
const doneFilter = createState<'All' | 'To do' | 'Done'>('doneFilter', 'All')
const isLoading = createState('isLoading', true)
const notes = createState<NoteSection[]>('notes', [])
const loadItems = sendRequest<NoteSection[]>({
url: "https://gist.githubusercontent.com/Tiagoperes/3888902b98494708202fa05569444451/raw/dbc705192e2f87233da2f1eec35936aef8125545/todo.json",
onSuccess: response => notes.set(response.get('data')),
onError: response => log({ level: 'error', message: response.get('message') }),
onFinish: isLoading.set(false),
})
const header = (
<Row backgroundColor="#5F72C0" crossAxisAlignment="center" paddingHorizontal={20} height={65}>
<Icon name="search" color="#FFFFFF" size={28} />
<Row width="expand">
<TextInput header color="#FFFFFF" label="Search" value={searchTerm} onChange={value => searchTerm.set(value)} />
</Row>
<SelectionGroup options={["All", "To do", "Done"]} value={doneFilter} onChange={value => doneFilter.set(value)} />
</Row>
)
const body = (
<ScrollView>
<ForEach items={notes} key="date">
{(section) => (
<Column marginTop={5}>
<Column paddingVertical={12} paddingHorizontal={20}>
<Text size={16} color="#616B76">{formatDate(section.get('date'))}</Text>
</Column>
<Separator />
<ForEach items={section.get('items')} key="id">
{(item) => (
<If condition={shouldRender(item, searchTerm, doneFilter)}>
<Then>
<NoteCard value={item} onShowEditModal={navigator.present(EditNote, { state: { note: item } })} />
<Separator />
</Then>
</If>
)}
</ForEach>
</Column>
)}
</ForEach>
</ScrollView>
)
return (
<ScreenComponent safeAreaTopBackground="#5F72C0" statusBarColorScheme="dark">
<Lifecycle onInit={loadItems} state={[isLoading, notes, searchTerm, doneFilter]}>
<If condition={isLoading}>
<Then><Text>Loading</Text></Then>
<Else>
<Stack height="expand" width="expand" backgroundColor="#F1F3F5">
<Positioned>
{header}
{body}
</Positioned>
<Positioned alignment="bottomEnd" margin={28}>
<CircularButton
icon="plus"
onPress={navigator.present(EditNote, { state: { note: emptyNote() } })}
/>
</Positioned>
</Stack>
</Else>
</If>
</Lifecycle>
</ScreenComponent>
)
}