/
TasksList.tsx
124 lines (114 loc) · 3.15 KB
/
TasksList.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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import {ChevronDownIcon} from '@sanity/icons'
import {Box, Flex, Stack, Text} from '@sanity/ui'
import {useCallback, useMemo} from 'react'
import styled from 'styled-components'
import {type TaskDocument} from '../../types'
import {TasksListItem} from './TasksListItem'
interface TasksListProps {
onTaskSelect: (id: string) => void
items: TaskDocument[]
}
const checkboxValues = [
{name: 'open', label: 'To Do'},
{name: 'closed', label: 'Done'},
]
const getLabelForStatus = (status: string) => {
const statusConfig = checkboxValues.find((item) => item.name === status)
return statusConfig?.label
}
const TasksListRoot = styled(Box)`
max-height: calc(100% - 140px);
overflow-y: auto;
// Hide scrollbar
scrollbar-width: none;
`
const Details = styled.details`
[data-ui='summary-icon'] {
transition: transform 0.2s;
transform: rotate(-90deg);
}
&[open] [data-ui='summary-icon'] {
transform: rotate(0);
}
> summary::-webkit-details-marker {
display: none;
}
`
const Summary = styled.summary`
list-style: none;
`
/**
* @internal
*/
export function TasksList(props: TasksListProps) {
const {items, onTaskSelect} = props
// Filter tasks by status to render them in separate lists
const tasksByStatus = useMemo(
() =>
items.reduce((acc: Record<string, TaskDocument[]>, task) => {
if (!acc[task.status]) {
acc[task.status] = []
}
acc[task.status].push(task)
return acc
}, {}),
[items],
)
const renderTasksList = useCallback(
(status: string) => {
const tasks = tasksByStatus[status] || []
if (tasks.length === 0) {
return null
}
return (
<Details open={status === 'open'}>
<Summary>
<Flex align="center" gap={1} paddingY={1}>
<Text size={1} weight="medium" muted>
{getLabelForStatus(status)}
</Text>
<Text muted size={1}>
<ChevronDownIcon data-ui="summary-icon" />
</Text>
</Flex>
</Summary>
<Stack space={3} marginTop={3} paddingBottom={5}>
{tasks.map((task) => (
<TasksListItem
key={task._id}
documentId={task._id}
title={task.title}
dueBy={task.dueBy}
assignedTo={task.assignedTo}
target={task.target}
onSelect={() => onTaskSelect(task._id)}
status={task.status}
/>
))}
</Stack>
</Details>
)
},
[onTaskSelect, tasksByStatus],
)
const hasOpenTasks = tasksByStatus.open?.length > 0
const hasClosedTasks = tasksByStatus.closed?.length > 0
return (
<TasksListRoot paddingX={3} paddingY={4}>
<Stack space={4} paddingTop={2} paddingX={1}>
{!hasOpenTasks && !hasClosedTasks ? (
<Box paddingX={2}>
<Text as="p" size={1} muted>
No tasks
</Text>
</Box>
) : (
<>
{renderTasksList('open')}
{renderTasksList('closed')}
</>
)}
</Stack>
</TasksListRoot>
)
}