goobs-frontend 0.9.16 → 0.9.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -4
- package/src/components/DataGrid/index.tsx +14 -5
- package/src/components/DataGrid/types/index.ts +3 -0
- package/src/components/Field/Dropdown/Regular/index.tsx +21 -1
- package/src/components/Field/Dropdown/Searchable/index.tsx +24 -4
- package/src/components/ProjectBoard/forms/AddTask/administrator/companyDropdown/index.tsx +233 -97
- package/src/components/ProjectBoard/forms/AddTask/administrator/companyProvided/index.tsx +218 -92
- package/src/components/ProjectBoard/forms/AddTask/company/customerDropdown/index.tsx +226 -99
- package/src/components/ProjectBoard/forms/AddTask/company/customerProvided/index.tsx +215 -83
- package/src/components/ProjectBoard/forms/AddTask/customer/index.tsx +44 -17
- package/src/components/ProjectBoard/forms/AddTask/noUser/index.tsx +9 -16
- package/src/components/ProjectBoard/index.tsx +12 -5
- package/src/components/ProjectBoard/types/index.tsx +5 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "goobs-frontend",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.18",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A comprehensive React-based libary that extends the functionality of Material-UI",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,11 +35,11 @@
|
|
|
35
35
|
"lodash": "^4",
|
|
36
36
|
"next": "15",
|
|
37
37
|
"otplib": "^12",
|
|
38
|
-
"react-datepicker": "^
|
|
39
|
-
"react-native": "^0.78
|
|
38
|
+
"react-datepicker": "^8",
|
|
39
|
+
"react-native": "^0.78",
|
|
40
40
|
"react-qr-code": "^2",
|
|
41
41
|
"slate": "^0.112",
|
|
42
|
-
"slate-dom": "^0.
|
|
42
|
+
"slate-dom": "^0.112",
|
|
43
43
|
"slate-history": "^0.110",
|
|
44
44
|
"slate-react": "^0.112",
|
|
45
45
|
"storybook": "^8",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import React, { useState } from 'react'
|
|
3
|
+
import React, { useState, useMemo } from 'react'
|
|
4
4
|
import { Box, Alert } from '@mui/material'
|
|
5
5
|
import CustomToolbar from '../Toolbar'
|
|
6
6
|
import Table from './Table'
|
|
@@ -24,7 +24,16 @@ function DataGrid({
|
|
|
24
24
|
onManage,
|
|
25
25
|
onShow,
|
|
26
26
|
onSelectionChange,
|
|
27
|
+
showIdColumns = false,
|
|
27
28
|
}: DatagridProps) {
|
|
29
|
+
// Filter columns to hide ID columns based on showIdColumns prop
|
|
30
|
+
const filteredColumns = useMemo(() => {
|
|
31
|
+
if (showIdColumns) {
|
|
32
|
+
return columns
|
|
33
|
+
}
|
|
34
|
+
return columns.filter(col => col.field !== 'id' && col.field !== '_id')
|
|
35
|
+
}, [columns, showIdColumns])
|
|
36
|
+
|
|
28
37
|
// Local state
|
|
29
38
|
const [rows, setRows] = useState<RowData[]>(providedRows || [])
|
|
30
39
|
const [selectedRows, setSelectedRows] = useState<string[]>([])
|
|
@@ -32,7 +41,7 @@ function DataGrid({
|
|
|
32
41
|
const [pageSize, setPageSize] = useState(10)
|
|
33
42
|
|
|
34
43
|
// Initialize columns/rows if needed
|
|
35
|
-
useInitializeGrid({ columns, providedRows, setRows })
|
|
44
|
+
useInitializeGrid({ columns: filteredColumns, providedRows, setRows })
|
|
36
45
|
|
|
37
46
|
// 1) When row selection changes
|
|
38
47
|
const handleSelectionChange = (newSelectedIds: string[]) => {
|
|
@@ -60,7 +69,7 @@ function DataGrid({
|
|
|
60
69
|
|
|
61
70
|
// 2) Search logic
|
|
62
71
|
const { filteredRows, updatedSearchbarProps } = useSearchbar({
|
|
63
|
-
columns,
|
|
72
|
+
columns: filteredColumns,
|
|
64
73
|
rows,
|
|
65
74
|
searchbarProps,
|
|
66
75
|
})
|
|
@@ -138,7 +147,7 @@ function DataGrid({
|
|
|
138
147
|
>
|
|
139
148
|
{/* Table component */}
|
|
140
149
|
<Table
|
|
141
|
-
columns={
|
|
150
|
+
columns={filteredColumns}
|
|
142
151
|
rows={visibleRows}
|
|
143
152
|
selectedRowIds={selectedRows}
|
|
144
153
|
onRowClick={handleRowClick}
|
|
@@ -154,7 +163,7 @@ function DataGrid({
|
|
|
154
163
|
rowCount={filteredRows.length}
|
|
155
164
|
onPageChange={setPage}
|
|
156
165
|
onPageSizeChange={setPageSize}
|
|
157
|
-
columns={
|
|
166
|
+
columns={filteredColumns}
|
|
158
167
|
/>
|
|
159
168
|
</Box>
|
|
160
169
|
</Box>
|
|
@@ -48,6 +48,9 @@ export interface DatagridProps {
|
|
|
48
48
|
searchbarProps?: SearchbarProps
|
|
49
49
|
error?: Error | null
|
|
50
50
|
|
|
51
|
+
// Controls whether ID columns (id/_id) are visible
|
|
52
|
+
showIdColumns?: boolean
|
|
53
|
+
|
|
51
54
|
// Single or multi selection callbacks:
|
|
52
55
|
onManage?: () => void
|
|
53
56
|
onShow?: () => void
|
|
@@ -53,6 +53,8 @@ export interface DropdownProps extends Omit<FormControlProps, 'onChange'> {
|
|
|
53
53
|
value?: string
|
|
54
54
|
width?: string
|
|
55
55
|
disabled?: boolean
|
|
56
|
+
// Controls whether ID columns (containing 'id' or '_id') are visible by default
|
|
57
|
+
showIdColumns?: boolean
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
const StyledFormControl = styled(FormControl)<{ width?: string }>(
|
|
@@ -173,10 +175,28 @@ const Dropdown: React.FC<DropdownProps> = ({
|
|
|
173
175
|
value: externalValue,
|
|
174
176
|
width,
|
|
175
177
|
disabled = false,
|
|
178
|
+
showIdColumns = false, // Default to hiding ID columns for security
|
|
176
179
|
}) => {
|
|
177
180
|
const [selectedValue, setSelectedValue] = useState<string>('')
|
|
178
181
|
const [focused, setFocused] = useState(false)
|
|
179
182
|
|
|
183
|
+
// Filter out options with id values if showIdColumns is false
|
|
184
|
+
const filteredOptions = React.useMemo(() => {
|
|
185
|
+
if (showIdColumns) {
|
|
186
|
+
return options
|
|
187
|
+
}
|
|
188
|
+
// Hide options where the value is exactly 'id' or '_id', or looks like a database ID
|
|
189
|
+
return options.filter(opt => {
|
|
190
|
+
const value = opt.value.toLowerCase()
|
|
191
|
+
// Check if value is an ID field or looks like an ObjectId
|
|
192
|
+
return !(
|
|
193
|
+
value === 'id' ||
|
|
194
|
+
value === '_id' ||
|
|
195
|
+
/^[0-9a-f]{24}$/.test(value) // MongoDB ObjectId format
|
|
196
|
+
)
|
|
197
|
+
})
|
|
198
|
+
}, [options, showIdColumns])
|
|
199
|
+
|
|
180
200
|
useEffect(() => {
|
|
181
201
|
if (externalValue !== undefined) {
|
|
182
202
|
setSelectedValue(externalValue)
|
|
@@ -351,7 +371,7 @@ const Dropdown: React.FC<DropdownProps> = ({
|
|
|
351
371
|
fontcolor={fontcolor}
|
|
352
372
|
disabled={disabled}
|
|
353
373
|
>
|
|
354
|
-
{
|
|
374
|
+
{filteredOptions.map(renderMenuItem)}
|
|
355
375
|
</StyledSelect>
|
|
356
376
|
{helperText && (
|
|
357
377
|
<FormHelperText error={error}>{helperText}</FormHelperText>
|
|
@@ -66,6 +66,8 @@ export interface SearchableDropdownProps {
|
|
|
66
66
|
searchHistory?: HistoryItem[] | string[]
|
|
67
67
|
onSearch?: (searchTerm: string, timestamp?: Date) => void
|
|
68
68
|
maxHistoryItems?: number
|
|
69
|
+
// Controls whether ID columns (containing 'id' or '_id') are visible by default
|
|
70
|
+
showIdColumns?: boolean
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
const StyledFormControl = styled(FormControl)<{ width?: string }>(
|
|
@@ -277,6 +279,7 @@ const SearchableDropdown: React.FC<SearchableDropdownProps> = ({
|
|
|
277
279
|
searchHistory = [], // Default to empty array
|
|
278
280
|
onSearch,
|
|
279
281
|
maxHistoryItems = 5, // Default to showing 5 history items
|
|
282
|
+
showIdColumns = false, // Default to hiding ID columns for security
|
|
280
283
|
}) => {
|
|
281
284
|
const [value, setValue] = useState<DropdownOption | string | null>(null)
|
|
282
285
|
const [inputValue, setInputValue] = useState('')
|
|
@@ -561,6 +564,23 @@ const SearchableDropdown: React.FC<SearchableDropdownProps> = ({
|
|
|
561
564
|
return localHistory
|
|
562
565
|
}, [searchHistory, localHistory])
|
|
563
566
|
|
|
567
|
+
// Filter out options with id values if showIdColumns is false
|
|
568
|
+
const filteredBaseOptions = React.useMemo(() => {
|
|
569
|
+
if (showIdColumns) {
|
|
570
|
+
return options
|
|
571
|
+
}
|
|
572
|
+
// Hide options where the value is exactly 'id' or '_id', or looks like a database ID
|
|
573
|
+
return options.filter(opt => {
|
|
574
|
+
const value = opt.value.toLowerCase()
|
|
575
|
+
// Check if value is an ID field or looks like an ObjectId (MongoDB ID format)
|
|
576
|
+
return !(
|
|
577
|
+
value === 'id' ||
|
|
578
|
+
value === '_id' ||
|
|
579
|
+
/^[0-9a-f]{24}$/.test(value)
|
|
580
|
+
)
|
|
581
|
+
})
|
|
582
|
+
}, [options, showIdColumns])
|
|
583
|
+
|
|
564
584
|
// Create a combined options array based on active tab and input value
|
|
565
585
|
const getFilteredOptions = React.useCallback(() => {
|
|
566
586
|
const currentInputVal = inputValue.trim()
|
|
@@ -581,7 +601,7 @@ const SearchableDropdown: React.FC<SearchableDropdownProps> = ({
|
|
|
581
601
|
// Map history items to dropdown options
|
|
582
602
|
return combinedHistory.map(item => {
|
|
583
603
|
// Check if this history item matches any of the original options
|
|
584
|
-
const matchingOption =
|
|
604
|
+
const matchingOption = filteredBaseOptions.find(
|
|
585
605
|
opt =>
|
|
586
606
|
opt.value.toLowerCase() === item.text.toLowerCase() ||
|
|
587
607
|
(
|
|
@@ -617,11 +637,11 @@ const SearchableDropdown: React.FC<SearchableDropdownProps> = ({
|
|
|
617
637
|
// ALL OPTIONS TAB (activeTab === 0)
|
|
618
638
|
// If input is empty, return all options
|
|
619
639
|
if (!currentInputVal) {
|
|
620
|
-
return
|
|
640
|
+
return filteredBaseOptions
|
|
621
641
|
}
|
|
622
642
|
|
|
623
643
|
// Filter options based on current input
|
|
624
|
-
const filteredOpts =
|
|
644
|
+
const filteredOpts = filteredBaseOptions.filter(opt =>
|
|
625
645
|
opt.value.toLowerCase().includes(currentInputVal.toLowerCase())
|
|
626
646
|
)
|
|
627
647
|
|
|
@@ -654,7 +674,7 @@ const SearchableDropdown: React.FC<SearchableDropdownProps> = ({
|
|
|
654
674
|
}
|
|
655
675
|
|
|
656
676
|
return filteredOpts
|
|
657
|
-
}, [inputValue, combinedHistory,
|
|
677
|
+
}, [inputValue, combinedHistory, filteredBaseOptions, activeTab, variant])
|
|
658
678
|
|
|
659
679
|
// Create the footer component for the dropdown with tabs
|
|
660
680
|
const ListboxFooter = React.forwardRef<HTMLDivElement>((_, ref) => (
|
|
@@ -4,7 +4,7 @@ import React, { useState, useCallback } from 'react'
|
|
|
4
4
|
import { Close } from '@mui/icons-material'
|
|
5
5
|
import { Dialog, IconButton, Box, useMediaQuery, useTheme } from '@mui/material'
|
|
6
6
|
import Typography from '../../../../../Typography'
|
|
7
|
-
import
|
|
7
|
+
import SearchableDropdown from '../../../../../Field/Dropdown/Searchable'
|
|
8
8
|
import MultiSelect from '../../../../../Field/Dropdown/MultiSelect'
|
|
9
9
|
import ComplexTextEditor from '../../../../../ComplexTextEditor'
|
|
10
10
|
import CustomButton from '../../../../../Button'
|
|
@@ -64,39 +64,116 @@ const AdministratorAddTaskCompanyDropdown: React.FC<
|
|
|
64
64
|
const [taskTitle, setTaskTitle] = useState('')
|
|
65
65
|
const [taskDescription, setTaskDescription] = useState('')
|
|
66
66
|
|
|
67
|
+
// Debug logging for incoming props
|
|
68
|
+
console.log('AdministratorAddTaskCompanyDropdown - Props received:', {
|
|
69
|
+
statusesCount: statuses?.length || 0,
|
|
70
|
+
subStatusesCount: subStatuses?.length || 0,
|
|
71
|
+
statusesData: statuses,
|
|
72
|
+
topicsData: topics,
|
|
73
|
+
})
|
|
74
|
+
|
|
67
75
|
// ------------------ DROPDOWN OPTIONS ------------------
|
|
68
76
|
const companyOptions = rawCompanies.map(c => ({
|
|
69
|
-
value: c.
|
|
70
|
-
label: c.companyName,
|
|
77
|
+
value: c.companyName,
|
|
71
78
|
}))
|
|
79
|
+
|
|
72
80
|
const severityOptions = severityLevels.map(sl => ({
|
|
73
81
|
value: String(sl.severityLevel),
|
|
74
|
-
attribute1: sl.
|
|
82
|
+
attribute1: sl.description || '',
|
|
75
83
|
}))
|
|
84
|
+
|
|
76
85
|
const statusOptions = statuses.map(s => ({
|
|
77
86
|
value: s.status,
|
|
78
|
-
attribute1: s._id,
|
|
79
|
-
}))
|
|
80
|
-
const subStatusOptions = subStatuses.map(s => ({
|
|
81
|
-
value: s.subStatus,
|
|
82
|
-
attribute1: s._id,
|
|
83
87
|
}))
|
|
88
|
+
|
|
89
|
+
// Filter substatuses based on the selected status
|
|
90
|
+
const filteredSubStatusOptions = subStatuses
|
|
91
|
+
.filter(s => {
|
|
92
|
+
// If no status is selected, hide all substatuses
|
|
93
|
+
if (!selectedStatus) return false
|
|
94
|
+
|
|
95
|
+
// Get the ID of the selected status
|
|
96
|
+
const selectedStatusId = statuses.find(
|
|
97
|
+
status => status.status === selectedStatus
|
|
98
|
+
)?._id
|
|
99
|
+
console.log('Filtering substatuses by status:', {
|
|
100
|
+
selectedStatus,
|
|
101
|
+
selectedStatusId,
|
|
102
|
+
substatus: s.subStatus,
|
|
103
|
+
substatusStatusId: s.statusId,
|
|
104
|
+
isMatch: s.statusId === selectedStatusId,
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
// Only include substatuses with the matching statusId
|
|
108
|
+
return s.statusId === selectedStatusId
|
|
109
|
+
})
|
|
110
|
+
.map(s => {
|
|
111
|
+
const associatedStatus =
|
|
112
|
+
statuses.find(status => status._id === s.statusId)?.status || ''
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
value: s.subStatus,
|
|
116
|
+
attribute1: associatedStatus,
|
|
117
|
+
}
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
// Add a "no substatuses" option if none are available for the selected status
|
|
121
|
+
const finalSubStatusOptions =
|
|
122
|
+
filteredSubStatusOptions.length > 0
|
|
123
|
+
? filteredSubStatusOptions
|
|
124
|
+
: selectedStatus
|
|
125
|
+
? [
|
|
126
|
+
{
|
|
127
|
+
value: 'No substatuses available for this status',
|
|
128
|
+
attribute1: '',
|
|
129
|
+
},
|
|
130
|
+
]
|
|
131
|
+
: []
|
|
132
|
+
|
|
133
|
+
console.log('Filtered substatus options:', finalSubStatusOptions)
|
|
134
|
+
|
|
84
135
|
const queueOptions = schedulingQueues.map(q => ({
|
|
85
136
|
value: q.queueName,
|
|
86
|
-
attribute1: q._id,
|
|
87
137
|
}))
|
|
88
138
|
|
|
139
|
+
// Effect to reset substatus when status changes
|
|
140
|
+
React.useEffect(() => {
|
|
141
|
+
// Clear the selected substatus when the status changes
|
|
142
|
+
setSelectedSubStatus('')
|
|
143
|
+
}, [selectedStatus])
|
|
144
|
+
|
|
89
145
|
// ------------------ SUBMIT HANDLER ------------------
|
|
90
146
|
const handleSubmit = useCallback(() => {
|
|
147
|
+
// Find the IDs from the selected values
|
|
148
|
+
const selectedStatusId =
|
|
149
|
+
statuses.find(s => s.status === selectedStatus)?._id || ''
|
|
150
|
+
const selectedSubStatusId =
|
|
151
|
+
subStatuses.find(s => s.subStatus === selectedSubStatus)?._id || ''
|
|
152
|
+
const selectedQueueId =
|
|
153
|
+
schedulingQueues.find(q => q.queueName === selectedQueue)?._id || ''
|
|
154
|
+
const selectedCompanyId =
|
|
155
|
+
rawCompanies.find(c => c.companyName === selectedCompany)?._id || ''
|
|
156
|
+
|
|
157
|
+
console.log('Submitting task with mapped IDs:', {
|
|
158
|
+
statusValue: selectedStatus,
|
|
159
|
+
statusId: selectedStatusId,
|
|
160
|
+
subStatusValue: selectedSubStatus,
|
|
161
|
+
subStatusId: selectedSubStatusId,
|
|
162
|
+
queueValue: selectedQueue,
|
|
163
|
+
queueId: selectedQueueId,
|
|
164
|
+
companyValue: selectedCompany,
|
|
165
|
+
companyId: selectedCompanyId,
|
|
166
|
+
})
|
|
167
|
+
|
|
91
168
|
const newTaskData: Omit<Task, '_id'> = {
|
|
92
169
|
title: taskTitle,
|
|
93
170
|
description: taskDescription,
|
|
94
171
|
topicIds: selectedTopicIds,
|
|
95
172
|
articleIds: selectedArticleIds,
|
|
96
173
|
severityId: selectedSeverity || '',
|
|
97
|
-
schedulingQueueId:
|
|
98
|
-
statusId:
|
|
99
|
-
substatusId:
|
|
174
|
+
schedulingQueueId: selectedQueueId,
|
|
175
|
+
statusId: selectedStatusId,
|
|
176
|
+
substatusId: selectedSubStatusId,
|
|
100
177
|
employeeIds: [],
|
|
101
178
|
createdAt: new Date(),
|
|
102
179
|
updatedAt: new Date(),
|
|
@@ -113,14 +190,10 @@ const AdministratorAddTaskCompanyDropdown: React.FC<
|
|
|
113
190
|
kbArticles: [],
|
|
114
191
|
teamMember: '',
|
|
115
192
|
nextActionDate: '',
|
|
116
|
-
companyId:
|
|
193
|
+
companyId: selectedCompanyId,
|
|
117
194
|
customerId: '',
|
|
118
195
|
}
|
|
119
196
|
|
|
120
|
-
newTaskData.companyId = selectedCompany
|
|
121
|
-
newTaskData.customerId = ''
|
|
122
|
-
newTaskData.employeeIds = []
|
|
123
|
-
|
|
124
197
|
onAdd(newTaskData)
|
|
125
198
|
}, [
|
|
126
199
|
taskTitle,
|
|
@@ -134,6 +207,10 @@ const AdministratorAddTaskCompanyDropdown: React.FC<
|
|
|
134
207
|
selectedCompany,
|
|
135
208
|
createdUserId,
|
|
136
209
|
onAdd,
|
|
210
|
+
statuses,
|
|
211
|
+
subStatuses,
|
|
212
|
+
schedulingQueues,
|
|
213
|
+
rawCompanies,
|
|
137
214
|
])
|
|
138
215
|
|
|
139
216
|
// ------------------ RENDER ------------------
|
|
@@ -158,12 +235,10 @@ const AdministratorAddTaskCompanyDropdown: React.FC<
|
|
|
158
235
|
position: 'absolute',
|
|
159
236
|
right: 8,
|
|
160
237
|
top: 8,
|
|
161
|
-
color: theme
|
|
162
|
-
zIndex: theme
|
|
238
|
+
color: theme.palette.grey[500],
|
|
239
|
+
zIndex: theme.zIndex.modal + 1,
|
|
163
240
|
cursor: 'pointer',
|
|
164
|
-
'&:hover': {
|
|
165
|
-
color: theme => theme.palette.grey[700],
|
|
166
|
-
},
|
|
241
|
+
'&:hover': { color: theme.palette.grey[700] },
|
|
167
242
|
}}
|
|
168
243
|
>
|
|
169
244
|
<Close />
|
|
@@ -192,11 +267,16 @@ const AdministratorAddTaskCompanyDropdown: React.FC<
|
|
|
192
267
|
/>
|
|
193
268
|
|
|
194
269
|
{/* Company Dropdown */}
|
|
195
|
-
<
|
|
270
|
+
<SearchableDropdown
|
|
196
271
|
label="Company"
|
|
197
272
|
options={companyOptions}
|
|
198
|
-
|
|
199
|
-
|
|
273
|
+
defaultValue={
|
|
274
|
+
companyOptions.find(opt => opt.value === selectedCompany)?.value
|
|
275
|
+
}
|
|
276
|
+
onChange={option => {
|
|
277
|
+
setSelectedCompany(option?.value || '')
|
|
278
|
+
}}
|
|
279
|
+
placeholder="Select a company"
|
|
200
280
|
/>
|
|
201
281
|
|
|
202
282
|
{/* Top row of fields */}
|
|
@@ -216,44 +296,36 @@ const AdministratorAddTaskCompanyDropdown: React.FC<
|
|
|
216
296
|
gap: 1,
|
|
217
297
|
}}
|
|
218
298
|
>
|
|
219
|
-
<
|
|
299
|
+
<SearchableDropdown
|
|
220
300
|
label="Severity Level"
|
|
221
301
|
options={severityOptions}
|
|
222
|
-
|
|
302
|
+
defaultValue={
|
|
223
303
|
severityOptions.find(
|
|
224
304
|
opt => opt.attribute1 === selectedSeverity
|
|
225
|
-
)?.value
|
|
305
|
+
)?.value
|
|
226
306
|
}
|
|
227
|
-
onChange={
|
|
228
|
-
|
|
229
|
-
const option = severityOptions.find(
|
|
230
|
-
opt => opt.value === selectedValue
|
|
231
|
-
)
|
|
232
|
-
if (option) {
|
|
233
|
-
setSelectedSeverity(option.attribute1)
|
|
234
|
-
} else {
|
|
235
|
-
setSelectedSeverity('')
|
|
236
|
-
}
|
|
307
|
+
onChange={option => {
|
|
308
|
+
setSelectedSeverity(option?.attribute1 || '')
|
|
237
309
|
}}
|
|
310
|
+
placeholder="Select severity level"
|
|
238
311
|
/>
|
|
239
|
-
<
|
|
312
|
+
<SearchableDropdown
|
|
240
313
|
label="Status"
|
|
241
314
|
options={statusOptions}
|
|
242
|
-
|
|
243
|
-
statusOptions.find(opt => opt.
|
|
244
|
-
?.value || ''
|
|
315
|
+
defaultValue={
|
|
316
|
+
statusOptions.find(opt => opt.value === selectedStatus)?.value
|
|
245
317
|
}
|
|
246
|
-
onChange={
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
}
|
|
318
|
+
onChange={option => {
|
|
319
|
+
const newStatus = option?.value || ''
|
|
320
|
+
console.log('Status selected:', newStatus)
|
|
321
|
+
|
|
322
|
+
// Find the status ID for the selected status
|
|
323
|
+
const statusObj = statuses.find(s => s.status === newStatus)
|
|
324
|
+
console.log('Selected status object:', statusObj)
|
|
325
|
+
|
|
326
|
+
setSelectedStatus(newStatus)
|
|
256
327
|
}}
|
|
328
|
+
placeholder="Select status"
|
|
257
329
|
/>
|
|
258
330
|
</Box>
|
|
259
331
|
|
|
@@ -266,63 +338,127 @@ const AdministratorAddTaskCompanyDropdown: React.FC<
|
|
|
266
338
|
gap: 1,
|
|
267
339
|
}}
|
|
268
340
|
>
|
|
269
|
-
<
|
|
341
|
+
<SearchableDropdown
|
|
270
342
|
label="Associated Product (Queue)"
|
|
271
343
|
options={queueOptions}
|
|
272
|
-
|
|
273
|
-
queueOptions.find(opt => opt.
|
|
274
|
-
?.value || ''
|
|
344
|
+
defaultValue={
|
|
345
|
+
queueOptions.find(opt => opt.value === selectedQueue)?.value
|
|
275
346
|
}
|
|
276
|
-
onChange={
|
|
277
|
-
|
|
278
|
-
const option = queueOptions.find(
|
|
279
|
-
opt => opt.value === selectedValue
|
|
280
|
-
)
|
|
281
|
-
if (option) {
|
|
282
|
-
setSelectedQueue(option.attribute1)
|
|
283
|
-
} else {
|
|
284
|
-
setSelectedQueue('')
|
|
285
|
-
}
|
|
347
|
+
onChange={option => {
|
|
348
|
+
setSelectedQueue(option?.value || '')
|
|
286
349
|
}}
|
|
350
|
+
placeholder="Select product queue"
|
|
287
351
|
/>
|
|
288
|
-
<
|
|
352
|
+
<SearchableDropdown
|
|
289
353
|
label="Substatus"
|
|
290
|
-
options={
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
opt => opt.
|
|
294
|
-
)?.value
|
|
354
|
+
options={finalSubStatusOptions}
|
|
355
|
+
defaultValue={
|
|
356
|
+
finalSubStatusOptions.find(
|
|
357
|
+
opt => opt.value === selectedSubStatus
|
|
358
|
+
)?.value
|
|
295
359
|
}
|
|
296
|
-
onChange={
|
|
297
|
-
|
|
298
|
-
const option = subStatusOptions.find(
|
|
299
|
-
opt => opt.value === selectedValue
|
|
300
|
-
)
|
|
301
|
-
if (option) {
|
|
302
|
-
setSelectedSubStatus(option.attribute1)
|
|
303
|
-
} else {
|
|
304
|
-
setSelectedSubStatus('')
|
|
305
|
-
}
|
|
360
|
+
onChange={option => {
|
|
361
|
+
setSelectedSubStatus(option?.value || '')
|
|
306
362
|
}}
|
|
363
|
+
placeholder={
|
|
364
|
+
selectedStatus
|
|
365
|
+
? 'Select substatus'
|
|
366
|
+
: 'Please select a status first'
|
|
367
|
+
}
|
|
368
|
+
disabled={!selectedStatus}
|
|
307
369
|
/>
|
|
308
370
|
</Box>
|
|
309
371
|
</Box>
|
|
310
372
|
|
|
311
|
-
{/*
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
defaultSelected={selectedTopicIds}
|
|
316
|
-
onChange={setSelectedTopicIds}
|
|
317
|
-
/>
|
|
373
|
+
{/* Create a mapping from topic name to ID for lookup when submitting */}
|
|
374
|
+
{/* Also create a reverse mapping from ID to name for displaying selected values */}
|
|
375
|
+
{React.useMemo(() => {
|
|
376
|
+
console.log('Topics being mapped for dropdown:', topics)
|
|
318
377
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
378
|
+
// Create mappings for topic names to IDs and back
|
|
379
|
+
const topicNameToId: Record<string, string> = {}
|
|
380
|
+
const topicIdToName: Record<string, string> = {}
|
|
381
|
+
|
|
382
|
+
topics.forEach(t => {
|
|
383
|
+
const displayName = t.topic || `Topic ${t._id}`
|
|
384
|
+
topicNameToId[displayName] = t._id
|
|
385
|
+
topicIdToName[t._id] = displayName
|
|
386
|
+
})
|
|
387
|
+
|
|
388
|
+
console.log('Topic mappings created:', {
|
|
389
|
+
topicNameToId,
|
|
390
|
+
topicIdToName,
|
|
391
|
+
})
|
|
392
|
+
|
|
393
|
+
// Create user-friendly display options for topics
|
|
394
|
+
const topicOptions = topics.map(t => t.topic || `Topic ${t._id}`)
|
|
395
|
+
|
|
396
|
+
// Translate selected IDs to names for display
|
|
397
|
+
const selectedTopicNames = selectedTopicIds.map(
|
|
398
|
+
id => topicIdToName[id] || id
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
return (
|
|
402
|
+
<>
|
|
403
|
+
{/* Topics multi-select – using topic names with ID mapping */}
|
|
404
|
+
<MultiSelect
|
|
405
|
+
label="Topics"
|
|
406
|
+
options={topicOptions}
|
|
407
|
+
defaultSelected={selectedTopicNames}
|
|
408
|
+
onChange={selectedNames => {
|
|
409
|
+
console.log('Selected topic names:', selectedNames)
|
|
410
|
+
|
|
411
|
+
// Map the selected names back to IDs
|
|
412
|
+
const newSelectedIds = selectedNames.map(
|
|
413
|
+
name => topicNameToId[name] || name // Fallback to name if mapping not found
|
|
414
|
+
)
|
|
415
|
+
console.log('Mapped to topic IDs:', newSelectedIds)
|
|
416
|
+
|
|
417
|
+
setSelectedTopicIds(newSelectedIds)
|
|
418
|
+
}}
|
|
419
|
+
/>
|
|
420
|
+
</>
|
|
421
|
+
)
|
|
422
|
+
}, [topics, selectedTopicIds])}
|
|
423
|
+
|
|
424
|
+
{/* Knowledgebase Articles multi-select – using article titles now instead of IDs */}
|
|
425
|
+
{React.useMemo(() => {
|
|
426
|
+
// Create mappings for article titles to IDs and back
|
|
427
|
+
const articleTitleToId: Record<string, string> = {}
|
|
428
|
+
const articleIdToTitle: Record<string, string> = {}
|
|
429
|
+
|
|
430
|
+
knowledgebaseArticles.forEach(a => {
|
|
431
|
+
const title = a.articleTitle || `Article ${a._id}`
|
|
432
|
+
articleTitleToId[title] = a._id
|
|
433
|
+
articleIdToTitle[a._id] = title
|
|
434
|
+
})
|
|
435
|
+
|
|
436
|
+
// Create user-friendly display options for articles
|
|
437
|
+
const articleOptions = knowledgebaseArticles.map(
|
|
438
|
+
a => a.articleTitle || `Article ${a._id}`
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
// Translate selected IDs to titles for display
|
|
442
|
+
const selectedArticleTitles = selectedArticleIds.map(
|
|
443
|
+
id => articleIdToTitle[id] || id
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
return (
|
|
447
|
+
<MultiSelect
|
|
448
|
+
label="Knowledgebase Articles"
|
|
449
|
+
options={articleOptions}
|
|
450
|
+
defaultSelected={selectedArticleTitles}
|
|
451
|
+
onChange={selectedTitles => {
|
|
452
|
+
// Map the selected titles back to IDs
|
|
453
|
+
const newSelectedIds = selectedTitles.map(
|
|
454
|
+
title => articleTitleToId[title] || title // Fallback to title if mapping not found
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
setSelectedArticleIds(newSelectedIds)
|
|
458
|
+
}}
|
|
459
|
+
/>
|
|
460
|
+
)
|
|
461
|
+
}, [knowledgebaseArticles, selectedArticleIds])}
|
|
326
462
|
|
|
327
463
|
{/* Action Buttons */}
|
|
328
464
|
<Box
|