1
1
import { ChevronDownIcon } from '@sanity/icons'
2
- import { Box , Flex , Stack , Text } from '@sanity/ui'
3
- import { useCallback , useMemo } from 'react'
2
+ import { Box , Flex , MenuDivider , Stack , Text } from '@sanity/ui'
3
+ import { Fragment , useMemo } from 'react'
4
4
import styled from 'styled-components'
5
5
6
+ import { TASK_STATUS } from '../../constants/TaskStatus'
6
7
import { type TaskDocument } from '../../types'
7
8
import { TasksListItem } from './TasksListItem'
8
9
9
- interface TasksListProps {
10
- onTaskSelect : ( id : string ) => void
11
- items : TaskDocument [ ]
12
- }
13
-
14
- const checkboxValues = [
15
- { name : 'open' , label : 'To Do' } ,
16
- { name : 'closed' , label : 'Done' } ,
17
- ]
10
+ const EMPTY_ARRAY : [ ] = [ ]
18
11
19
12
const getLabelForStatus = ( status : string ) => {
20
- const statusConfig = checkboxValues . find ( ( item ) => item . name === status )
21
- return statusConfig ?. label
13
+ const statusConfig = TASK_STATUS . find ( ( item ) => item . value === status )
14
+ return statusConfig ?. title
22
15
}
23
16
24
- const TasksListRoot = styled ( Box ) `
25
- max-height: calc(100% - 140px);
26
- overflow-y: auto;
27
- // Hide scrollbar
28
- scrollbar-width: none;
29
- `
30
-
31
- const Details = styled . details `
17
+ const DetailsFlex = styled ( Flex ) `
32
18
[data-ui='summary-icon'] {
33
19
transition: transform 0.2s;
34
20
transform: rotate(-90deg);
@@ -40,17 +26,70 @@ const Details = styled.details`
40
26
display: none;
41
27
}
42
28
`
43
- const Summary = styled . summary `
29
+ const SummaryBox = styled ( Box ) `
44
30
list-style: none;
45
31
`
46
32
33
+ interface TaskListProps {
34
+ status : string
35
+ tasks : TaskDocument [ ]
36
+ onTaskSelect : ( id : string ) => void
37
+ }
38
+
39
+ function TaskList ( props : TaskListProps ) {
40
+ const { status, tasks, onTaskSelect} = props
41
+
42
+ return (
43
+ < DetailsFlex forwardedAs = "details" direction = "column" open = { status === 'open' } >
44
+ < SummaryBox forwardedAs = "summary" >
45
+ < Flex align = "center" gap = { 1 } paddingY = { 1 } >
46
+ < Text size = { 1 } weight = "medium" muted >
47
+ { getLabelForStatus ( status ) }
48
+ </ Text >
49
+
50
+ < Text muted size = { 1 } >
51
+ < ChevronDownIcon data-ui = "summary-icon" />
52
+ </ Text >
53
+ </ Flex >
54
+ </ SummaryBox >
55
+
56
+ < Stack space = { 4 } marginTop = { 4 } paddingBottom = { 5 } >
57
+ { tasks . map ( ( task , index ) => {
58
+ const showDivider = index < tasks . length - 1
59
+
60
+ return (
61
+ < Fragment key = { task . _id } >
62
+ < TasksListItem
63
+ documentId = { task . _id }
64
+ title = { task . title }
65
+ dueBy = { task . dueBy }
66
+ assignedTo = { task . assignedTo }
67
+ target = { task . target }
68
+ // eslint-disable-next-line react/jsx-no-bind
69
+ onSelect = { ( ) => onTaskSelect ( task . _id ) }
70
+ status = { task . status }
71
+ />
72
+
73
+ { showDivider && < MenuDivider /> }
74
+ </ Fragment >
75
+ )
76
+ } ) }
77
+ </ Stack >
78
+ </ DetailsFlex >
79
+ )
80
+ }
81
+
82
+ interface TasksListProps {
83
+ onTaskSelect : ( id : string ) => void
84
+ items : TaskDocument [ ]
85
+ }
86
+
47
87
/**
48
88
* @internal
49
89
*/
50
90
export function TasksList ( props : TasksListProps ) {
51
- const { items, onTaskSelect} = props
91
+ const { items = EMPTY_ARRAY , onTaskSelect} = props
52
92
53
- // Filter tasks by status to render them in separate lists
54
93
const tasksByStatus = useMemo (
55
94
( ) =>
56
95
items . reduce ( ( acc : Record < string , TaskDocument [ ] > , task ) => {
@@ -63,62 +102,26 @@ export function TasksList(props: TasksListProps) {
63
102
[ items ] ,
64
103
)
65
104
66
- const renderTasksList = useCallback (
67
- ( status : string ) => {
68
- const tasks = tasksByStatus [ status ] || [ ]
69
- if ( tasks . length === 0 ) {
70
- return null
71
- }
72
- return (
73
- < Details open = { status === 'open' } >
74
- < Summary >
75
- < Flex align = "center" gap = { 1 } paddingY = { 1 } >
76
- < Text size = { 1 } weight = "medium" muted >
77
- { getLabelForStatus ( status ) }
78
- </ Text >
79
- < Text muted size = { 1 } >
80
- < ChevronDownIcon data-ui = "summary-icon" />
81
- </ Text >
82
- </ Flex >
83
- </ Summary >
84
- < Stack space = { 3 } marginTop = { 3 } paddingBottom = { 5 } >
85
- { tasks . map ( ( task ) => (
86
- < TasksListItem
87
- key = { task . _id }
88
- documentId = { task . _id }
89
- title = { task . title }
90
- dueBy = { task . dueBy }
91
- assignedTo = { task . assignedTo }
92
- target = { task . target }
93
- onSelect = { ( ) => onTaskSelect ( task . _id ) }
94
- status = { task . status }
95
- />
96
- ) ) }
97
- </ Stack >
98
- </ Details >
99
- )
100
- } ,
101
- [ onTaskSelect , tasksByStatus ] ,
102
- )
103
-
104
105
const hasOpenTasks = tasksByStatus . open ?. length > 0
105
106
const hasClosedTasks = tasksByStatus . closed ?. length > 0
107
+
106
108
return (
107
- < TasksListRoot paddingX = { 3 } paddingY = { 4 } >
108
- < Stack space = { 4 } paddingTop = { 2 } paddingX = { 1 } >
109
- { ! hasOpenTasks && ! hasClosedTasks ? (
110
- < Box paddingX = { 2 } >
111
- < Text as = "p" size = { 1 } muted >
112
- No tasks
113
- </ Text >
114
- </ Box >
115
- ) : (
116
- < >
117
- { renderTasksList ( 'open' ) }
118
- { renderTasksList ( 'closed' ) }
119
- </ >
120
- ) }
121
- </ Stack >
122
- </ TasksListRoot >
109
+ < Stack space = { 4 } >
110
+ { ! hasOpenTasks && ! hasClosedTasks ? (
111
+ < Text as = "p" size = { 1 } muted >
112
+ No tasks
113
+ </ Text >
114
+ ) : (
115
+ < >
116
+ { hasOpenTasks && (
117
+ < TaskList status = "open" tasks = { tasksByStatus . open } onTaskSelect = { onTaskSelect } />
118
+ ) }
119
+
120
+ { hasClosedTasks && (
121
+ < TaskList status = "closed" tasks = { tasksByStatus . closed } onTaskSelect = { onTaskSelect } />
122
+ ) }
123
+ </ >
124
+ ) }
125
+ </ Stack >
123
126
)
124
127
}
0 commit comments