Skip to content

Commit f2200ed

Browse files
collins-selfcollins-self
authored andcommitted
refactor: replace LocationDrawingsModal with LocationDrawingsButton in multiple components
1 parent ae995ba commit f2200ed

6 files changed

Lines changed: 181 additions & 202 deletions

File tree

Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx

Lines changed: 5 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ import * as React from 'react';
2525
import _ from 'lodash';
2626
import { ReactTable } from '@gpa-gemstone/react-table';
2727
import { useHistory } from "react-router-dom";
28-
import { BtnDropdown, LoadingIcon, Modal, Search, ServerErrorIcon, ToolTip } from '@gpa-gemstone/react-interactive';
29-
import { CrossMark, TrashCan } from '@gpa-gemstone/gpa-symbols'
28+
import { LoadingIcon, Modal, Search, ServerErrorIcon, ToolTip } from '@gpa-gemstone/react-interactive';
29+
import { TrashCan } from '@gpa-gemstone/gpa-symbols'
3030
import { OpenXDA } from '@gpa-gemstone/application-typings';
3131
import { useAppSelector, useAppDispatch } from '../hooks';
3232
import { AssetConnectionTypeSlice } from '../Store/Store';
3333
import { SelectRoles } from '../Store/UserSettings';
34-
import LocationDrawingsModal from '../CommonComponents/LocationDrawingsModal'
34+
import LocationDrawingsButton from '../CommonComponents/LocationDrawingsButton';
3535

3636
interface AssetConnection {
3737
AssetRelationShipTypeID: number,
@@ -53,17 +53,14 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number
5353
const [localAssets, setLocalAssets] = React.useState<Array<OpenXDA.Types.Asset>>([]);
5454

5555
const [locations, setLocations] = React.useState<OpenXDA.Types.Location[]>([]);
56-
const [showDrawingsModal, setShowDrawingsModal] = React.useState<boolean>(false);
57-
const [selectedLocation, setSelectedLocation] = React.useState<OpenXDA.Types.Location>();
58-
const [locationsWithErrors, setLocationsWithErrors] = React.useState<Map<OpenXDA.Types.Location, string[]>>(new Map())
5956

6057
const [sortKey, setSortKey] = React.useState<string>('AssetKey');
6158
const [ascending, setAscending] = React.useState<boolean>(true);
6259
const [showModal, setShowModal] = React.useState<boolean>(false);
6360

6461
const [status, setStatus] = React.useState<'idle' | 'loading' | 'error'>('idle');
65-
const actStatus = useAppSelector(AssetConnectionTypeSlice.SearchStatus);
6662
const [trigger, setTrigger] = React.useState<number>(0);
63+
const actStatus = useAppSelector(AssetConnectionTypeSlice.SearchStatus);
6764

6865
const [hover, setHover] = React.useState<('Update' | 'Reset' | 'None' | 'Drawings')>('None');
6966
const roles = useAppSelector(SelectRoles);
@@ -251,20 +248,6 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number
251248
</div>
252249

253250
const connectionsAvailable = !(assetConnectionTypes == undefined) && (assetConnectionTypes.length > 0);
254-
const handleShowDrawingsModal = (loc: OpenXDA.Types.Location) => {
255-
setSelectedLocation(loc);
256-
setShowDrawingsModal(true);
257-
}
258-
const handleAddLocationError = (locMap: Map<OpenXDA.Types.Location, string[]>) => {
259-
setLocationsWithErrors(prev => new Map([...prev, ...locMap]));
260-
}
261-
const handleRemoveLocationError = (loc: OpenXDA.Types.Location) => {
262-
setLocationsWithErrors(prev => {
263-
const newMap = new Map(prev);
264-
newMap.delete(loc);
265-
return newMap;
266-
});
267-
}
268251
return (
269252
<div className="card" style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
270253
<div className="card-header">
@@ -273,35 +256,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number
273256
<h4>Connections:</h4>
274257
</div>
275258
<div className="pr-4">
276-
<BtnDropdown
277-
Label={'Open ' + locations[0]?.Name + ' Drawings'}
278-
Callback={() => handleShowDrawingsModal(locations[0])}
279-
TooltipContent={<>{
280-
locationsWithErrors.get(locations[0])?.map((e, i) => <p key={i}>{CrossMark} {e}</p>)
281-
}</>}
282-
ShowToolTip={locationsWithErrors.has(locations[0])}
283-
Disabled={locationsWithErrors.has(locations[0])}
284-
BtnClass={'btn-primary'}
285-
Options={locations.slice(1).map((loc, i) => ({
286-
Label: 'Open ' + loc?.Name + ' Drawings',
287-
Callback: () => handleShowDrawingsModal(loc),
288-
Disabled: locationsWithErrors.has(loc),
289-
ToolTipContent: <>{
290-
locationsWithErrors.get(loc)?.map((e, i) => <p key={i}>{CrossMark} {e}</p>)
291-
}</>,
292-
ShowToolTip: locationsWithErrors.has(loc),
293-
ToolTipLocation: "left",
294-
Key: i
295-
}))}
296-
/>
297-
<LocationDrawingsModal
298-
Location={selectedLocation}
299-
Show={showDrawingsModal}
300-
SetShow={setShowDrawingsModal}
301-
Errors={() => {}}
302-
AddLocationWithErrors={handleAddLocationError}
303-
RemoveLocationWithErrors={handleRemoveLocationError}
304-
/>
259+
<LocationDrawingsButton Locations={locations} />
305260
</div>
306261
</div>
307262
</div>
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import React from 'react';
2+
import { BtnDropdown, GenericController, LoadingScreen, ServerErrorIcon, ToolTip } from '@gpa-gemstone/react-interactive';
3+
import LocationDrawingsModal from './LocationDrawingsModal';
4+
import { OpenXDA } from '@gpa-gemstone/application-typings';
5+
import { CrossMark } from '@gpa-gemstone/gpa-symbols';
6+
7+
interface LocationDrawingsButtonProps {
8+
Locations: OpenXDA.Types.Location[];
9+
}
10+
11+
const LocationDrawingsButton: React.FC<LocationDrawingsButtonProps> = (props) => {
12+
const [hover, setHover] = React.useState<'none' | 'drawings'>('none');
13+
const [pageState, setPageState] = React.useState<"loading" | "error" | "idle">("idle");
14+
const [selectedLocation, setSelectedLocation] = React.useState<OpenXDA.Types.Location>();
15+
const [multipleLocations, setMultipleLocations] = React.useState<boolean>(false);
16+
const [showDrawingsModal, setShowDrawingsModal] = React.useState<boolean>(false);
17+
const [locationsWithErrors, setLocationsWithErrors] = React.useState<Map<OpenXDA.Types.Location, string[]>>(new Map())
18+
const LocationDrawingController = new GenericController(`${homePath}api/LocationDrawing`, "Name", true);
19+
20+
const isValid = (location, drawingData) => {
21+
let e = [];
22+
23+
if (location == undefined
24+
|| (location.Alias == ""
25+
&& location.Description == ""
26+
&& location.ID == 0
27+
&& location.Latitude == null
28+
&& location.LocationKey == ""
29+
&& location.Longitude == null
30+
&& location.Name == ""))
31+
e.push('No locations have been set.');
32+
else if (drawingData.TotalRecords == 0)
33+
e.push('No drawings associated with location.');
34+
return e;
35+
}
36+
37+
React.useEffect(() => { // Generates the map of errors for each location
38+
if (props.Locations.length > 1) setMultipleLocations(true);
39+
else setMultipleLocations(false); // TODO: check for undefined location isValid is not doing it
40+
for (const location of props.Locations) {
41+
if (location?.ID) {
42+
setPageState('loading');
43+
LocationDrawingController.PagedSearch([], 'Name', true, 1, location.ID)
44+
.done((result) => {
45+
const errors = isValid(location, result);
46+
updateLocationErrors(location, errors);
47+
setPageState('idle')
48+
})
49+
.fail(() => setPageState('error'));
50+
}
51+
}
52+
}, [props.Locations]);
53+
54+
const handleAddLocationError = (locMap: Map<OpenXDA.Types.Location, string[]>) => {
55+
setLocationsWithErrors(prev => {
56+
const newMap = new Map(prev);
57+
locMap.forEach((errors, loc) => {
58+
if (newMap.has(loc)) {
59+
const existingErrors = newMap.get(loc);
60+
newMap.set(loc, Array.from(new Set([...existingErrors, ...errors])));
61+
} else {
62+
newMap.set(loc, errors);
63+
}
64+
});
65+
return newMap;
66+
});
67+
}
68+
69+
const handleRemoveLocationError = (loc: OpenXDA.Types.Location) => {
70+
setLocationsWithErrors(prev => {
71+
const newMap = new Map(prev);
72+
newMap.delete(loc);
73+
return newMap;
74+
});
75+
}
76+
77+
const updateLocationErrors = (loc: OpenXDA.Types.Location, errors: string[]) => {
78+
if (errors.length > 0 && loc != undefined) {
79+
const locationErrorsMap = new Map<OpenXDA.Types.Location, string[]>();
80+
locationErrorsMap.set(loc, errors);
81+
handleAddLocationError(locationErrorsMap);
82+
} else {
83+
handleRemoveLocationError(loc);
84+
}
85+
}
86+
87+
const handleShowDrawingsModal = (loc) => {
88+
if (loc == undefined) return;
89+
setSelectedLocation(loc);
90+
setShowDrawingsModal(true);
91+
};
92+
93+
return (
94+
<div>
95+
<LoadingScreen Show={pageState == 'loading'} />
96+
<ServerErrorIcon Show={pageState == 'error'} Size={40} Label={'A Server Error Occurred. Please Reload the Application.'} />
97+
{!multipleLocations
98+
? <>
99+
<button
100+
className={locationsWithErrors.size > 0 ? "btn btn-primary disabled" : "btn btn-primary"}
101+
onClick={() => locationsWithErrors.size > 0 ? null : setShowDrawingsModal(true)}
102+
data-tooltip={"DrawingsModal"}
103+
onMouseEnter={() => setHover('drawings')}
104+
onMouseLeave={() => setHover('none')}
105+
>Open {props.Locations[0]?.Name} Drawings
106+
</button>
107+
<ToolTip
108+
Show={locationsWithErrors.size > 0 && hover === 'drawings'}
109+
Theme={'dark'}
110+
Position={'top'}
111+
Target={"DrawingsModal"}
112+
Zindex={9999}
113+
> {locationsWithErrors.get(props.Locations[0])?.map((e, i) => <p key={i}>{CrossMark} {e}</p>)}
114+
</ToolTip>
115+
</>
116+
: <BtnDropdown
117+
Label={'Open ' + props.Locations[0]?.Name + ' Drawings'}
118+
Callback={() => handleShowDrawingsModal(props.Locations[0])}
119+
TooltipContent={
120+
<>{locationsWithErrors.get(props.Locations[0])?.map((e, i) => <p key={i}>{CrossMark} {e}</p>)}</>
121+
}
122+
ShowToolTip={locationsWithErrors.has(props.Locations[0])}
123+
Disabled={locationsWithErrors.has(props.Locations[0])}
124+
BtnClass={'btn-primary'}
125+
Options={props.Locations.slice(1).map((loc, i) => ({
126+
Label: 'Open ' + loc?.Name + ' Drawings',
127+
Callback: () => handleShowDrawingsModal(loc),
128+
Disabled: locationsWithErrors.has(loc),
129+
ToolTipContent: <>{
130+
locationsWithErrors.get(loc)?.map((e, i) => <p key={i}>{CrossMark} {e}</p>)
131+
}</>,
132+
ShowToolTip: locationsWithErrors.has(loc),
133+
ToolTipLocation: "left",
134+
Key: i
135+
}))}
136+
/>
137+
}
138+
<LocationDrawingsModal
139+
LocationID={selectedLocation?.ID}
140+
Show={showDrawingsModal}
141+
SetShow={setShowDrawingsModal}
142+
/>
143+
</div>
144+
);
145+
};
146+
147+
export default LocationDrawingsButton;

Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx

Lines changed: 17 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -21,86 +21,33 @@
2121
//
2222
//******************************************************************************************************
2323
import React from 'react';
24-
import { OpenXDA, SystemCenter } from '@gpa-gemstone/application-typings'
25-
import { GenericController, LoadingScreen, Modal, ServerErrorIcon } from '@gpa-gemstone/react-interactive';
24+
import { Modal } from '@gpa-gemstone/react-interactive';
2625
import LocationDrawingsTable from '../Location/LocationDrawingsTable';
2726

2827
interface IProps {
29-
Location: OpenXDA.Types.Location;
28+
LocationID: number;
3029
Show: boolean;
3130
SetShow: (b: boolean) => void;
32-
/** For use when keeping track of a single Location's error to display */
33-
Errors: (e: string[]) => void;
34-
/** For use with multiple locations with multiple LocationDrawingsModal's */
35-
AddLocationWithErrors?: (locationErrorsMap: Map<OpenXDA.Types.Location, string[]>) => void;
36-
/** For use with multiple locations with multiple LocationDrawingsModal's */
37-
RemoveLocationWithErrors?: (locationErrorsMap: OpenXDA.Types.Location) => void;
3831
}
3932

4033
const LocationDrawingsModal = (props: IProps) => {
41-
const [errors, setErrors] = React.useState<string[]>([]);
42-
const [pageState, setPageState] = React.useState<"loading" | "error" | "idle">("idle");
43-
const LocationDrawingController = new GenericController<SystemCenter.Types.LocationDrawing>(`${homePath}api/LocationDrawing`, "Name", true);
44-
45-
const isValid = (drawingData) => {
46-
let e = [];
47-
48-
if (props.Location == undefined
49-
|| (props.Location.Alias == ""
50-
&& props.Location.Description == ""
51-
&& props.Location.ID == 0
52-
&& props.Location.Latitude == null
53-
&& props.Location.LocationKey == ""
54-
&& props.Location.Longitude == null
55-
&& props.Location.Name == ""))
56-
e.push('No locations have been set.');
57-
else if (drawingData.TotalRecords == 0)
58-
e.push('No drawings associated with location.');
59-
return e;
60-
}
61-
62-
React.useEffect(() => {
63-
setPageState('loading');
64-
LocationDrawingController.PagedSearch([], 'Name', true, 1, props.Location?.ID)
65-
.done((result) => {
66-
const validationErrors = isValid(result);
67-
setErrors(validationErrors);
68-
setPageState('idle');
69-
})
70-
.fail(() => setPageState('error'));
71-
}, [props.Location?.ID])
72-
73-
React.useEffect(() => {
74-
props.Errors(errors);
75-
const locationErrorsMap = new Map<OpenXDA.Types.Location, string[]>();
76-
locationErrorsMap.set(props.Location, errors);
77-
78-
if (errors.length > 0 && props.Location != undefined)
79-
props.AddLocationWithErrors?.(locationErrorsMap);
80-
else props.RemoveLocationWithErrors?.(props.Location);
81-
}, [errors]);
82-
8334
return (
84-
<div>
85-
<LoadingScreen Show={pageState == 'loading'} />
86-
<ServerErrorIcon Show={pageState == 'error'} Size={40} Label={'A Server Error Occurred. Please Reload the Application.'} />
87-
<Modal
88-
Show={props.Show}
89-
Title={'Drawings'}
90-
ShowX={true} Size={'lg'}
91-
CallBack={() => props.SetShow(false)}
92-
ShowCancel={false}
93-
ConfirmText={'Done'}>
94-
<div className="row">
95-
<div className="col" style={{ width: '100%' }}>
96-
<LocationDrawingsTable
97-
LocationID={props.Location?.ID}
98-
UpdateTable={0}
99-
/>
100-
</div>
35+
<Modal
36+
Show={props.Show}
37+
Title={'Drawings'}
38+
ShowX={true} Size={'lg'}
39+
CallBack={() => props.SetShow(false)}
40+
ShowCancel={false}
41+
ConfirmText={'Done'}>
42+
<div className="row">
43+
<div className="col" style={{ width: '100%' }}>
44+
<LocationDrawingsTable
45+
LocationID={props.LocationID}
46+
UpdateTable={0}
47+
/>
10148
</div>
102-
</Modal>
103-
</div>
49+
</div>
50+
</Modal>
10451
)
10552
}
10653
export default LocationDrawingsModal;

0 commit comments

Comments
 (0)