@@ -8,6 +8,9 @@ import StepModal from "components/StepModal";
8
8
import { Search , TacoButton } from "lowcoder-design" ;
9
9
import { Table } from "../../components/Table" ;
10
10
import { timestampToHumanReadable } from "../../util/dateTimeUtils" ;
11
+ import { Avatar , Flex , Tooltip } from "antd" ;
12
+ import { buildSupportTicketLink } from "constants/routesURL" ;
13
+ import history from "util/history" ;
11
14
12
15
const SupportWrapper = styled . div `
13
16
display: flex;
@@ -45,6 +48,16 @@ const AddBtn = styled(TacoButton)`
45
48
height: 32px;
46
49
` ;
47
50
51
+ const ReloadBtn = styled ( TacoButton ) `
52
+ min-width: 96px;
53
+ width: fit-content;
54
+ height: 32px;
55
+ ` ;
56
+
57
+ const EditBtn = styled ( TacoButton ) `
58
+
59
+ ` ;
60
+
48
61
const BodyWrapper = styled . div `
49
62
width: 100%;
50
63
flex-grow: 1;
@@ -61,6 +74,15 @@ const SubColumnCell = styled.div`
61
74
color: #8b8fa3;
62
75
` ;
63
76
77
+ const StatusDot = styled . span < { active : boolean } > `
78
+ display: inline-block;
79
+ margin-left: 14px;
80
+ width: 8px;
81
+ height: 8px;
82
+ border-radius: 50%;
83
+ background-color: ${ ( props ) => ( props . active ? "green" : "gray" ) } ;
84
+ ` ;
85
+
64
86
function formatDateToMinute ( dateString : string ) : string {
65
87
// Create a Date object from the string
66
88
const date = new Date ( dateString ) ;
@@ -76,6 +98,11 @@ function formatDateToMinute(dateString: string): string {
76
98
return `${ year } -${ month } -${ day } ${ hour } :${ minute } ` ;
77
99
}
78
100
101
+ // Function to handle edit button click
102
+ const handleEditClick = ( ticketId : string ) => {
103
+ history . push ( buildSupportTicketLink ( ticketId ) ) ;
104
+ } ;
105
+
79
106
export function SupportOverview ( ) {
80
107
const { orgID, currentUser, domain } = useUserDetails ( ) ;
81
108
const [ supportTickets , setSupportTickets ] = useState < any > ( [ ] ) ;
@@ -84,19 +111,21 @@ export function SupportOverview() {
84
111
const [ searchValue , setSearchValue ] = useState ( "" ) ;
85
112
const [ isCreateFormShow , showCreateForm ] = useState ( false ) ;
86
113
87
- useEffect ( ( ) => {
88
- const fetchSupportTickets = async ( ) => {
89
- try {
90
- const ticketData = await searchCustomerTickets ( orgID , currentUser . id , domain ) ;
91
- setSupportTickets ( ticketData ) ;
92
- } catch ( err ) {
93
- setError ( "Failed to fetch support tickets." ) ;
94
- console . error ( err ) ;
95
- } finally {
96
- setLoading ( false ) ;
97
- }
98
- } ;
114
+ // Function to fetch support tickets
115
+ const fetchSupportTickets = async ( ) => {
116
+ setLoading ( true ) ; // Set loading to true while fetching data
117
+ try {
118
+ const ticketData = await searchCustomerTickets ( orgID , currentUser . id , domain ) ;
119
+ setSupportTickets ( ticketData ) ;
120
+ } catch ( err ) {
121
+ setError ( "Failed to fetch support tickets." ) ;
122
+ console . error ( err ) ;
123
+ } finally {
124
+ setLoading ( false ) ; // Set loading to false after fetching data
125
+ }
126
+ } ;
99
127
128
+ useEffect ( ( ) => {
100
129
fetchSupportTickets ( ) ;
101
130
} , [ orgID , currentUser . id , domain ] ) ;
102
131
@@ -112,7 +141,7 @@ export function SupportOverview() {
112
141
113
142
return (
114
143
< >
115
- < Helmet > < title > { trans ( "home .supportTitle" ) } </ title > </ Helmet >
144
+ < Helmet > < title > { trans ( "support .supportTitle" ) } </ title > </ Helmet >
116
145
< SupportWrapper >
117
146
118
147
< StepModal
@@ -135,56 +164,70 @@ export function SupportOverview() {
135
164
] } />
136
165
137
166
< HeaderWrapper >
138
- < Title > { trans ( "home.supportTickets" ) } </ Title >
139
- < Search
140
- placeholder = { trans ( "search" ) }
141
- value = { searchValue }
142
- onChange = { ( e ) => setSearchValue ( e . target . value ) }
143
- style = { { width : "192px" , height : "32px" , margin : "0 12px 0 0" } } />
144
- < AddBtn buttonType = { "primary" } onClick = { ( ) => showCreateForm ( true ) } >
145
- { trans ( "home.newSupportTicket" ) }
146
- </ AddBtn >
167
+ < Title > { trans ( "support.supportTitle" ) } </ Title >
168
+ < Flex gap = "12px" >
169
+ < Search
170
+ placeholder = { trans ( "search" ) }
171
+ value = { searchValue }
172
+ onChange = { ( e ) => setSearchValue ( e . target . value ) }
173
+ style = { { width : "192px" , height : "32px" , margin : "0 12px 0 0" } } />
174
+ < AddBtn buttonType = { "primary" } onClick = { ( ) => showCreateForm ( true ) } >
175
+ { trans ( "support.newSupportTicket" ) }
176
+ </ AddBtn >
177
+ < ReloadBtn buttonType = { "normal" } onClick = { ( ) => fetchSupportTickets ( ) } >
178
+ { trans ( "support.reloadTickets" ) }
179
+ </ ReloadBtn >
180
+ </ Flex >
147
181
</ HeaderWrapper >
148
182
< BodyWrapper >
149
- { ! loading ? (
150
183
< StyledTable
184
+ loading = { loading }
151
185
rowClassName = "datasource-can-not-edit"
152
186
tableLayout = { "auto" }
153
187
scroll = { { x : "100%" } }
154
188
pagination = { false }
155
189
columns = { [
156
190
{
157
- title : trans ( "home .ticketTitle" ) ,
191
+ title : trans ( "support .ticketTitle" ) ,
158
192
dataIndex : "title" ,
159
193
ellipsis : true ,
160
194
sorter : ( a : any , b : any ) => a . title . localeCompare ( b . title ) ,
161
195
} ,
162
196
{
163
- title : trans ( "home .priority" ) ,
197
+ title : trans ( "support .priority" ) ,
164
198
dataIndex : "priority" ,
165
199
ellipsis : true ,
166
200
width : "192px" ,
167
201
sorter : ( a : any , b : any ) => a . priority . name . localeCompare ( b . priority . name ) ,
168
202
render : ( priority : any ) => < SubColumnCell > { priority . name } </ SubColumnCell > ,
169
203
} ,
170
204
{
171
- title : trans ( "home .assignee" ) ,
205
+ title : trans ( "support .assignee" ) ,
172
206
dataIndex : "assignee" ,
173
207
ellipsis : true ,
174
208
width : "192px" ,
175
- sorter : ( a : any , b : any ) => a . assignee . email . localeCompare ( b . assignee . email ) ,
176
- render : ( assignee : any ) => < SubColumnCell > { assignee . email } </ SubColumnCell > ,
209
+ render : ( assignee : any ) => (
210
+ < SubColumnCell >
211
+ < Tooltip title = { "Support Member is active in: " +
212
+ assignee . timeZone + ", " +
213
+ ( assignee . email || trans ( "support.noEmail" ) )
214
+ } >
215
+ < Avatar src = { assignee . avatar } alt = { assignee . email } />
216
+ </ Tooltip >
217
+ < StatusDot active = { assignee . active } />
218
+ </ SubColumnCell >
219
+ ) ,
177
220
} ,
178
221
{
179
- title : trans ( "home .status" ) ,
222
+ title : trans ( "support .status" ) ,
180
223
dataIndex : "status" ,
181
224
ellipsis : true ,
182
- width : "192px " ,
225
+ width : "220px " ,
183
226
sorter : ( a : any , b : any ) => a . status . name . localeCompare ( b . status . name ) ,
184
227
render : ( status : any ) => < SubColumnCell > { status . name } </ SubColumnCell > ,
185
228
} ,
186
229
{
187
- title : trans ( "home .updatedTime" ) ,
230
+ title : trans ( "support .updatedTime" ) ,
188
231
dataIndex : "updated" ,
189
232
ellipsis : true ,
190
233
width : "192px" ,
@@ -195,6 +238,19 @@ export function SupportOverview() {
195
238
</ SubColumnCell >
196
239
) ,
197
240
} ,
241
+ {
242
+ title : trans ( "support.details" ) ,
243
+ dataIndex : "actions" ,
244
+ width : "120px" ,
245
+ render : ( key : string ) => (
246
+ < EditBtn
247
+ buttonType = { "normal" }
248
+ onClick = { ( ) => handleEditClick ( key ) }
249
+ >
250
+ { trans ( "support.details" ) }
251
+ </ EditBtn >
252
+ ) ,
253
+ } ,
198
254
] }
199
255
dataSource = { filteredTickets . map ( ( ticket : any , index : number ) => ( {
200
256
key : index ,
@@ -203,11 +259,9 @@ export function SupportOverview() {
203
259
assignee : ticket . assignee ,
204
260
status : ticket . status ,
205
261
updated : ticket . updated ,
262
+ actions : ticket . key ,
206
263
} ) ) }
207
264
/>
208
- ) : (
209
- < div > Loading...</ div >
210
- ) }
211
265
{ error && < div > Error: { error } </ div > }
212
266
</ BodyWrapper >
213
267
</ SupportWrapper >
0 commit comments