1+ import { useParams } from "react-router" ;
2+ import { useNavigate } from "react-router-dom" ;
3+ import { priorities , projectManagers , projectsData , tasksData , taskTags } from "./data" ;
4+ import { Button } from "@progress/kendo-react-buttons" ;
5+ import { Avatar , Breadcrumb , BreadcrumbLinkMouseEvent , ExpansionPanel , ExpansionPanelContent } from "@progress/kendo-react-layout" ;
6+ import { homeIcon , folderIcon , trashIcon , checkIcon } from "@progress/kendo-svg-icons" ;
7+ import { SvgIcon } from "@progress/kendo-react-common" ;
8+ import { Reveal } from '@progress/kendo-react-animation' ;
9+ import React , { ReactElement } from "react" ;
10+ import { TextArea } from "@progress/kendo-react-inputs" ;
11+ import { DropDownList , ListItemProps , MultiSelect , TagData } from "@progress/kendo-react-dropdowns" ;
12+ import { DateInput } from "@progress/kendo-react-dateinputs" ;
13+ import { FloatingLabel } from "@progress/kendo-react-labels" ;
14+ import { Badge } from "@progress/kendo-react-indicators" ;
15+
16+ interface DataModel {
17+ id : string ;
18+ text ?: string ;
19+ icon ?: React . ReactNode ;
20+ }
21+
22+ export default function Task ( ) {
23+ let params = useParams ( ) ;
24+ const navigate = useNavigate ( ) ;
25+ const [ projExpanded , setProjExpanded ] = React . useState ( true ) ;
26+ const [ dateExpanded , setDateExpanded ] = React . useState ( true ) ;
27+ const [ assigneeExpanded , setAssigneeExpanded ] = React . useState ( true ) ;
28+ const [ priorityExpanded , setPriorityExpanded ] = React . useState ( true ) ;
29+ const [ statusExpanded , setStatusExpanded ] = React . useState ( true ) ;
30+ const [ tagsExpanded , setTagsExpanded ] = React . useState ( true ) ;
31+ const [ project , setProject ] = React . useState < string > ( ) ;
32+ const [ assignee , setAssignee ] = React . useState < string [ ] > ( ) ;
33+ const [ dueDate , setDueDate ] = React . useState < Date > ( ) ;
34+ const [ priority , setPriority ] = React . useState < string > ( ) ;
35+ const [ status , setStatus ] = React . useState < string > ( ) ;
36+ const [ tag , setTag ] = React . useState < string [ ] > ( ) ;
37+ const projects = projectsData . map ( proj => { return proj . ProjectName } ) . slice ( 0 , 10 ) ;
38+ const assignees = tasksData . map ( task => { return task . assignedTo } ) ;
39+ const statuses = tasksData . map ( task => { return task . status } ) ;
40+
41+ const breadcrumbItems : DataModel [ ] = [
42+ {
43+ id : "home" ,
44+ icon : < SvgIcon icon = { homeIcon } /> ,
45+ } ,
46+ {
47+ id : "tasks" ,
48+ text : "Tasks" ,
49+ } ,
50+ {
51+ id : `${ params . taskId } ` ,
52+ text : `New Task` ,
53+ }
54+ ] ;
55+
56+ const handleItemSelect = ( e : BreadcrumbLinkMouseEvent ) => {
57+ if ( e . id === 'home' ) {
58+ navigate ( '/' ) ;
59+ } else if ( e . id === 'tasks' ) {
60+ navigate ( '/tasks' ) ;
61+ }
62+ }
63+
64+ const tagRender = ( tagData : TagData , li : ReactElement < any > ) => React . cloneElement ( li , li . props , [
65+ < span key = { assignees . indexOf ( tagData . data [ 0 ] ) } className = "k-chip-label" >
66+ < Avatar rounded = "full" type = "image" size = "small" className = "k-chip-avatar mr-1" >
67+ < img src = { projectManagers . map ( manager => manager . name === tagData . data [ 0 ] ? manager . avatarSrc : "" ) . filter ( src => src !== "" ) [ 0 ] } alt = "user-image" />
68+ </ Avatar >
69+ { tagData . data [ 0 ] }
70+ </ span > , li . props . children ] ) ;
71+
72+ const itemRender = ( li : React . ReactElement < HTMLLIElement > , itemProps : ListItemProps ) => {
73+ const index = itemProps . index ;
74+ console . log ( itemProps ) ;
75+ const itemChildren = (
76+ < span key = { index } >
77+ < Avatar rounded = "full" type = "image" size = "small" className = "mr-1" >
78+ < img src = { projectManagers . map ( manager => manager . name === itemProps . dataItem ? manager . avatarSrc : "" ) . filter ( src => src !== "" ) [ 0 ] } alt = "user-image" />
79+ </ Avatar >
80+ { li . props . children as any } { index }
81+ </ span >
82+ ) ;
83+
84+ return React . cloneElement ( li , li . props , itemChildren ) ;
85+ } ;
86+
87+ const priorityValueRender = ( element : React . ReactElement < HTMLSpanElement > , value : any ) => {
88+ if ( ! value ) {
89+ return element ;
90+ }
91+
92+ const children = [
93+ < Badge
94+ key = { value }
95+ rounded = "full"
96+ position = "inside"
97+ className = "!relative !z-0"
98+ themeColor = {
99+ value === "Urgent"
100+ ? "error"
101+ : value === "Medium priority"
102+ ? "warning"
103+ : value === "Low priority"
104+ ? "success"
105+ : value === "Routine"
106+ ? "tertiary"
107+ : "primary"
108+ }
109+ >
110+ { element . props . children as any }
111+ </ Badge >
112+ ] ;
113+
114+ return React . cloneElement ( element , { ...element . props } , children ) ;
115+ } ;
116+
117+ const priorityItemRender = ( li : React . ReactElement < HTMLLIElement > , itemProps : ListItemProps ) => {
118+ const itemChildren = (
119+ < Badge
120+ rounded = "full"
121+ position = "inside"
122+ className = "!relative !z-0"
123+ themeColor = {
124+ itemProps . dataItem === "Urgent"
125+ ? "error"
126+ : itemProps . dataItem === "Medium priority"
127+ ? "warning"
128+ : itemProps . dataItem === "Low priority"
129+ ? "success"
130+ : itemProps . dataItem === "Routine"
131+ ? "tertiary"
132+ : "primary"
133+ }
134+ >
135+ { li . props . children as any }
136+ </ Badge >
137+ ) ;
138+
139+ return React . cloneElement ( li , li . props , itemChildren ) ;
140+ } ;
141+
142+ return (
143+ < >
144+ < div style = { { minHeight : 'calc(100vh - 106px)' } } className = "flex flex-col p-10 gap-6" >
145+ < Breadcrumb data = { breadcrumbItems } onItemSelect = { handleItemSelect } className = "!bg-app-surface" />
146+
147+ < h1 className = "text-4xl" > New Task</ h1 >
148+
149+ < div className = "grid grid-cols-12 gap-6" >
150+ < div className = "col-span-6 lg:col-span-8" >
151+ < TextArea rows = { 30 } className = "rounded-t-2xl" />
152+ < div className = "bg-surface-alt border-1 border-t-0 border-border rounded-b-2xl px-4 py-2" >
153+ < div className = "hidden lg:flex gap-1" >
154+ < Button svgIcon = { checkIcon } themeColor = "primary" size = "large" > Save changes</ Button >
155+ < Button svgIcon = { folderIcon } fillMode = "flat" size = "large" className = "ml-auto" > Archive Task</ Button >
156+ < Button svgIcon = { trashIcon } fillMode = "flat" themeColor = "error" size = "large" > Delete task</ Button >
157+ </ div >
158+ < div className = "flex lg:hidden gap-1" >
159+ < Button svgIcon = { checkIcon } themeColor = "primary" size = "large" > Save changes</ Button >
160+ < Button svgIcon = { folderIcon } fillMode = "flat" size = "large" className = "ml-auto" > Archive Task</ Button >
161+ < Button svgIcon = { trashIcon } fillMode = "flat" themeColor = "error" size = "large" > Delete task</ Button >
162+ </ div >
163+ </ div >
164+ </ div >
165+
166+ < div className = "col-span-6 lg:col-span-4 flex flex-col gap-2" >
167+ < ExpansionPanel title = "Project" expanded = { projExpanded } onAction = { ( ) => setProjExpanded ( ! projExpanded ) } className = "rounded-2xl" >
168+ < Reveal >
169+ { projExpanded && < ExpansionPanelContent >
170+ < FloatingLabel label = "Choose project" editorId = { 'project' } editorValue = { project } className = "flex" >
171+ < DropDownList size = "large" value = { project } onChange = { e => setProject ( e . value as string ) } data = { projects } />
172+ </ FloatingLabel >
173+ </ ExpansionPanelContent > }
174+ </ Reveal >
175+ </ ExpansionPanel >
176+ < ExpansionPanel title = "Assigned to" expanded = { assigneeExpanded } onAction = { ( ) => setAssigneeExpanded ( ! assigneeExpanded ) } className = "rounded-2xl" >
177+ < Reveal >
178+ { assigneeExpanded && < ExpansionPanelContent >
179+ < FloatingLabel label = "Select assignee(s)" editorId = { 'assignee' } editorValue = { assigneeExpanded } className = "flex" >
180+ < MultiSelect size = "large" data = { assignees } value = { assignee } onChange = { e => setAssignee ( [ ...e . value ] as string [ ] ) } tagRender = { tagRender } itemRender = { itemRender } />
181+ </ FloatingLabel >
182+ </ ExpansionPanelContent > }
183+ </ Reveal >
184+ </ ExpansionPanel >
185+ < ExpansionPanel title = "Due Date" expanded = { dateExpanded } onAction = { ( ) => setDateExpanded ( ! dateExpanded ) } className = "rounded-2xl" >
186+ < Reveal >
187+ { dateExpanded && < ExpansionPanelContent >
188+ < FloatingLabel label = "Set due date" editorId = { 'due-date' } editorValue = { dateExpanded } className = "flex" >
189+ < DateInput size = "large" value = { dueDate } onChange = { e => setDueDate ( e . value as Date ) } />
190+ </ FloatingLabel >
191+ </ ExpansionPanelContent > }
192+ </ Reveal >
193+ </ ExpansionPanel >
194+ < ExpansionPanel title = "Priority" expanded = { priorityExpanded } onAction = { ( ) => setPriorityExpanded ( ! priorityExpanded ) } className = "rounded-2xl" >
195+ < Reveal >
196+ { priorityExpanded && < ExpansionPanelContent >
197+ < FloatingLabel label = "Choose project" editorId = { 'priority' } editorValue = { priority } className = "flex" >
198+ < DropDownList size = "large" value = { priority } onChange = { e => setPriority ( e . value as string ) } data = { priorities } valueRender = { priorityValueRender } itemRender = { priorityItemRender } />
199+ </ FloatingLabel >
200+ </ ExpansionPanelContent > }
201+ </ Reveal >
202+ </ ExpansionPanel >
203+ < ExpansionPanel title = "Status" expanded = { statusExpanded } onAction = { ( ) => setStatusExpanded ( ! statusExpanded ) } className = "rounded-2xl" >
204+ < Reveal >
205+ { statusExpanded && < ExpansionPanelContent >
206+ < FloatingLabel label = "Select status" editorId = { 'status' } editorValue = { statusExpanded } className = "flex" >
207+ < DropDownList size = "large" data = { statuses } value = { status } onChange = { e => setStatus ( e . value as string ) } />
208+ </ FloatingLabel >
209+ </ ExpansionPanelContent > }
210+ </ Reveal >
211+ </ ExpansionPanel >
212+ < ExpansionPanel title = "Tags" expanded = { tagsExpanded } onAction = { ( ) => setTagsExpanded ( ! tagsExpanded ) } className = "rounded-2xl" >
213+ < Reveal >
214+ { tagsExpanded && < ExpansionPanelContent >
215+ < FloatingLabel label = "Select tags" editorId = { 'tags' } editorValue = { tagsExpanded } className = "flex" >
216+ < MultiSelect size = "large" data = { taskTags } value = { tag } onChange = { e => setTag ( [ ...e . value ] as string [ ] ) } />
217+ </ FloatingLabel >
218+ </ ExpansionPanelContent > }
219+ </ Reveal >
220+ </ ExpansionPanel >
221+ </ div >
222+ </ div >
223+
224+ </ div >
225+ < div className = "bg-surface-alt color-subtle p-2 text-center" >
226+ < span > Copyright © 2025 Progress Software. All rights reserved.</ span >
227+ </ div >
228+ </ >
229+ )
230+ }
0 commit comments