1+ import React , { useEffect , useContext , useState } from "react" ;
2+ import { useSelector , useDispatch } from "react-redux" ;
3+ import FOI_COMPONENT_CONSTANTS from "../../../constants/FOI/foiComponentConstants" ;
4+ import { makeStyles } from "@material-ui/styles" ;
5+ import Accordion from "@material-ui/core/Accordion" ;
6+ import AccordionSummary from "@material-ui/core/AccordionSummary" ;
7+ import AccordionDetails from "@material-ui/core/AccordionDetails" ;
8+ import Typography from "@material-ui/core/Typography" ;
9+ import ExpandMoreIcon from "@material-ui/icons/ExpandMore" ;
10+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" ;
11+ import { faCirclePlus } from '@fortawesome/free-solid-svg-icons' ;
12+ import SearchIcon from "@material-ui/icons/Search" ;
13+ import CloseIcon from '@mui/icons-material/Close' ;
14+ import {
15+ Grid ,
16+ TextField ,
17+ InputAdornment ,
18+ IconButton ,
19+ Autocomplete ,
20+ CircularProgress
21+ } from "@mui/material" ;
22+ import { getFOIMinistryLinkedRequestInfo , linkedRequestsLists } from "../../../apiManager/services/FOI/foiRequestServices" ;
23+ import { LinkedRequestsTable } from "./LinkedRequestsTable" ;
24+
25+ const LinkedRequests = React . memo (
26+ ( {
27+ requestDetails,
28+ createSaveRequestObject,
29+ isMinistry
30+ } ) => {
31+ const useStyles = makeStyles ( {
32+ heading : {
33+ color : "#FFF" ,
34+ fontSize : "16px !important" ,
35+ fontWeight : "bold !important" ,
36+ } ,
37+ accordionSummary : {
38+ flexDirection : "row-reverse" ,
39+ } ,
40+ linkedRequests :{
41+ float : "left" ,
42+ }
43+ } ) ;
44+ const classes = useStyles ( ) ;
45+ const [ linkedRequests , setLinkedRequests ] = useState ( requestDetails ?. linkedRequests )
46+ const [ linkedRequestsInfo , setLinkedRequestsInfo ] = useState ( requestDetails ?. linkedRequestsInfo )
47+ const [ loading , setLoading ] = useState ( false ) ;
48+
49+ const dispatch = useDispatch ( ) ;
50+
51+ const [ showSearch , setShowSearch ] = useState ( false ) ;
52+ const [ searchQuery , setSearchQuery ] = useState ( "" ) ;
53+ const [ options , setOptions ] = useState ( [ ] ) ;
54+
55+ const getAxisRequestId = ( item ) => {
56+ const axisRequestId = Object . keys ( item ) [ 0 ] ;
57+ if ( typeof axisRequestId === "string" ) return axisRequestId ;
58+ return null ;
59+ } ;
60+
61+ const handleSearch = ( value ) => {
62+ if ( ! value || value ?. trim ( ) === "" ) {
63+ setOptions ( [ ] ) ;
64+ setSearchQuery ( "" ) ;
65+ return ;
66+ }
67+ setSearchQuery ( value ) ;
68+ fetchSuggestions ( value ) ;
69+ } ;
70+
71+ const handleClearSearch = ( ) => {
72+ setShowSearch ( false ) ;
73+ setSearchQuery ( "" ) ;
74+ setOptions ( [ ] ) ;
75+ }
76+
77+ const removeLinkedRequest = ( reqItem ) => {
78+ const reqId = reqItem . axisrequestid ;
79+ const updatedLinkedRequests = linkedRequests ?. filter ( item => getAxisRequestId ( item ) !== reqId ) ;
80+ const updatedLinkedInfoRequests = linkedRequestsInfo ?. filter ( item => item . axisrequestid !== reqId ) ;
81+ setLinkedRequests ( updatedLinkedRequests ) ;
82+ setLinkedRequestsInfo ( updatedLinkedInfoRequests ) ;
83+ createSaveRequestObject ( FOI_COMPONENT_CONSTANTS . LINKED_REQUESTS , updatedLinkedRequests ) ;
84+ }
85+
86+ const renderReviewRequest = ( e , reqItem ) => {
87+ e . preventDefault ( ) ;
88+ const reqId = reqItem . axisrequestid ;
89+ const item = linkedRequestsInfo . find (
90+ obj => obj . axisrequestid === reqId
91+ ) ;
92+ const rawrequestId = item ?. rawrequestid ;
93+ const ministryId = item ?. foiministryrequestid ;
94+ let url = '' ;
95+ if ( ministryId ) {
96+ url = `/foi/foirequests/${ ministryId } /ministryrequest/${ ministryId } `
97+ } else {
98+ url = `/foi/reviewrequest/${ rawrequestId } ` ;
99+ }
100+ window . open ( url , "_blank" , "noopener,noreferrer" ) ;
101+ } ;
102+
103+ const fetchSuggestions = ( value ) => {
104+ const ministryCode = requestDetails ?. selectedMinistries ?. length > 0
105+ ? requestDetails . selectedMinistries [ 0 ] . code
106+ : "" ;
107+ const queryParams = { q : value } ;
108+ try {
109+ dispatch (
110+ linkedRequestsLists (
111+ queryParams ,
112+ requestDetails ?. axisRequestId ,
113+ ministryCode ,
114+ ( err , _res ) => {
115+ if ( err ) {
116+ } else {
117+ setOptions ( _res ) ;
118+ console . log ( _res ) ;
119+ }
120+ }
121+ )
122+ ) ;
123+ } catch ( error ) {
124+ console . log ( error ) ;
125+ }
126+ } ;
127+
128+ const linkRequest = async ( selectedValue ) => {
129+ // linkedrequestinfo = {"axisrequestid": str, requeststatus: str, bcgovcode: str}
130+ // linkedrequests = {"axisrequestid": bcgovcode}
131+ if ( ! selectedValue ) {
132+ return ;
133+ }
134+ // Create a new array to avoid mutation issues
135+ const updatedLinkedRequests = [ ...( linkedRequests || [ ] ) ] ;
136+
137+ // Get the axis request ID from the selected value
138+ const newRequestId = selectedValue . axisrequestid ;
139+
140+ // Check if this request ID already exists in the array
141+ const alreadyExists = updatedLinkedRequests . some (
142+ item => getAxisRequestId ( item ) === newRequestId
143+ ) ;
144+
145+ // Get FOIMinistryRequest Status and MinistryId if FOIRawRequest Status is Archived
146+ if ( selectedValue . requeststatus === "Archived" && ! alreadyExists ) {
147+ const res = await dispatch ( getFOIMinistryLinkedRequestInfo ( selectedValue . axisrequestid ) ) ;
148+ selectedValue . requeststatus = res . requeststatus ;
149+ selectedValue . foiministryrequestid = res . foiministryrequestid ;
150+ }
151+
152+ // Add the new linkedrequest object to linkedrequest and linkedrequstinfo
153+ if ( ! alreadyExists && newRequestId ) {
154+ const axisRequestId = selectedValue . axisrequestid ;
155+ const govCode = selectedValue . govcode ;
156+ const linkedReqObj = {
157+ [ selectedValue . axisrequestid ] : govCode ,
158+ } ;
159+ const linkedReqInfoObj = {
160+ "axisrequestid" : axisRequestId ,
161+ "requeststatus" : selectedValue . requeststatus ,
162+ "foiministryrequestid" : selectedValue . foiministryrequestid || null ,
163+ "rawrequestid" : selectedValue . rawrequestid ,
164+ "govcode" : govCode
165+ } ;
166+ updatedLinkedRequests . push ( linkedReqObj ) ;
167+ setLinkedRequests ( updatedLinkedRequests ) ;
168+ setLinkedRequestsInfo ( prev => ( [ ...prev , linkedReqInfoObj ] ) ) ;
169+ createSaveRequestObject ( FOI_COMPONENT_CONSTANTS . LINKED_REQUESTS , updatedLinkedRequests ) ;
170+ }
171+
172+ // Clear the search after selection
173+ handleClearSearch ( ) ;
174+ }
175+
176+ return (
177+ < div className = "request-accordian" >
178+ < Accordion defaultExpanded = { true } >
179+ < AccordionSummary
180+ className = { classes . accordionSummary }
181+ expandIcon = { < ExpandMoreIcon /> }
182+ id = "requestDetails-header"
183+ >
184+ < Typography className = { classes . heading } > LINKED REQUESTS</ Typography >
185+ </ AccordionSummary >
186+ < AccordionDetails >
187+ < div className = "linked-requests" >
188+ < LinkedRequestsTable
189+ linkedRequestsInfo = { linkedRequestsInfo }
190+ linkedRequests = { linkedRequests }
191+ renderReviewRequest = { renderReviewRequest }
192+ removeLinkedRequest = { removeLinkedRequest }
193+ isMinistry = { isMinistry }
194+ />
195+ { ! showSearch && (
196+ < div style = { { display : "flex" , flexDirection : "row" , alignItems : "center" , margin : "7px 0px 7px 0px" } } >
197+ < button onClick = { ( ) => setShowSearch ( true ) } style = { { border : "none" , background : "none" } } >
198+ < FontAwesomeIcon icon = { faCirclePlus } size = "lg" color = "#38598A" />
199+ </ button >
200+ < p onClick = { ( ) => setShowSearch ( true ) } style = { { fontWeight : "bold" , color : "#38598A" , cursor : "pointer" } } > Add Linked Request</ p >
201+ </ div >
202+ ) }
203+ { showSearch && (
204+ < Grid
205+ item
206+ xs = { 12 }
207+ sx = { {
208+ p : 1 ,
209+ width : "35%"
210+ } }
211+ >
212+ < Autocomplete
213+ freeSolo
214+ disableClearable
215+ loading = { loading }
216+ options = { options || [ ] }
217+ getOptionLabel = { ( option ) => {
218+ const axisrequestid = option . axisrequestid
219+ if ( ! option ) return "" ;
220+ return axisrequestid ;
221+ } }
222+ inputValue = { searchQuery }
223+ onInputChange = { ( e , newValue ) => {
224+ if ( e ?. type === "change" ) {
225+ handleSearch ( newValue ) ;
226+ }
227+ } }
228+ onChange = { ( e , selectedValue ) => {
229+ if ( selectedValue ) {
230+ linkRequest ( selectedValue ) ;
231+ }
232+ } }
233+ sx = { {
234+ "& .MuiOutlinedInput-root" : {
235+ borderRadius : "6px" ,
236+ height : 40 ,
237+ border : "1px solid #ccc" ,
238+ "& fieldset" : { border : "none" } ,
239+ "&:hover fieldset" : { border : "none" } ,
240+ "&.Mui-focused fieldset" : { border : "1px solid #38598A" } ,
241+ } ,
242+ "& .MuiInputBase-input" : {
243+ padding : "6px 8px" ,
244+ fontSize : "0.9rem" ,
245+ } ,
246+ } }
247+ renderInput = { ( params ) => (
248+ < TextField
249+ { ...params }
250+ placeholder = "Search RequestID"
251+ InputProps = { {
252+ ...params . InputProps ,
253+ startAdornment : (
254+ < InputAdornment position = "start" >
255+ < IconButton sx = { { color : "#003388" } } >
256+ < SearchIcon sx = { { color : "#038" , "& path" : { fill : "#038" } } } />
257+ </ IconButton >
258+ </ InputAdornment >
259+ ) ,
260+ endAdornment : (
261+ < InputAdornment position = "end" >
262+ { loading ? (
263+ < CircularProgress size = { 18 } />
264+ ) :
265+ < IconButton
266+ size = "small"
267+ onClick = { handleClearSearch }
268+ aria-label = "Clear search"
269+ sx = { { p : 0.5 , color : "#038" } }
270+ >
271+ < CloseIcon fontSize = "small" />
272+ </ IconButton >
273+ }
274+ </ InputAdornment >
275+ ) ,
276+ } }
277+ />
278+ ) }
279+ />
280+ </ Grid >
281+ ) }
282+ </ div >
283+ < div className = "row foi-details-row foi-details-row-break" > </ div >
284+ </ AccordionDetails >
285+ </ Accordion >
286+ </ div >
287+ ) ;
288+ }
289+ ) ;
290+
291+ export default LinkedRequests ;
0 commit comments