swoop-common 2.2.206 → 2.2.208
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/dist/rendering/components/ComponentListItem.d.ts +2 -0
- package/dist/rendering/components/ComponentListItem.js +83 -20
- package/dist/rendering/components/ComponentPicker.d.ts +3 -1
- package/dist/rendering/components/ComponentPicker.js +2 -2
- package/dist/rendering/consts/system.d.ts +5 -0
- package/dist/rendering/consts/system.js +4 -0
- package/dist/rendering/consts/templateChipStyles.d.ts +8 -0
- package/dist/rendering/consts/templateChipStyles.js +11 -0
- package/dist/rendering/contexts/ComponentPickerContext.d.ts +2 -0
- package/dist/rendering/contexts/ComponentPickerContext.js +2 -2
- package/dist/rendering/index.d.ts +2 -0
- package/dist/rendering/index.js +2 -0
- package/dist/rendering/util/api.d.ts +1 -0
- package/dist/rendering/util/api.js +15 -0
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { DTOComponentRead, DTORegionRead, DTOTemplateRead } from "../../api/generated/core/exports";
|
|
3
3
|
import { PartnerSwoop } from "../../api/generated/swoop/exports";
|
|
4
|
+
import { ComponentSystem } from "../consts/system";
|
|
4
5
|
export interface ComponentListItemProps {
|
|
5
6
|
component: DTOComponentRead;
|
|
6
7
|
isSelected: boolean;
|
|
@@ -11,6 +12,7 @@ export interface ComponentListItemProps {
|
|
|
11
12
|
};
|
|
12
13
|
onSelect: (component: DTOComponentRead) => void;
|
|
13
14
|
showDivider: boolean;
|
|
15
|
+
system?: ComponentSystem;
|
|
14
16
|
}
|
|
15
17
|
declare const ComponentListItem: React.FC<ComponentListItemProps>;
|
|
16
18
|
export default ComponentListItem;
|
|
@@ -1,13 +1,74 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Box, Chip, Divider, ListItem, ListItemButton, ListItemText, Typography, } from "@mui/material";
|
|
3
|
-
import { PARTNER_REGION_READABLE } from "../consts/region";
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import { Box, Button, Chip, Divider, ListItem, ListItemButton, ListItemText, Typography, } from "@mui/material";
|
|
4
3
|
import { getComponentDataByTemplateName, TEMPLATE_NAMES } from "../../lib/config/templateStructure";
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import { getComponentsByIds } from "../util/api";
|
|
5
|
+
import { COMPONENT_SYSTEMS } from "../consts/system";
|
|
6
|
+
import { getTemplateChipStyle } from "../consts/templateChipStyles";
|
|
7
|
+
/*
|
|
8
|
+
Content per item type from ticket:
|
|
9
|
+
Package: Trip ID (hide on IB), Start city, Private, Guided
|
|
10
|
+
|
|
11
|
+
Transfer: Private, Guided, Transfer type, Start location (from journey), End location (from journey)
|
|
12
|
+
// lookup journey from component.componentFields.0.data.journey which contains a componentID, e.g. component_5a51acc53ab0b16da19f875c8cc148f2
|
|
13
|
+
// journey will contain a couple more componentFields which are start and end locations. These will need looking up and outputting.
|
|
14
|
+
|
|
15
|
+
Activity: Start location, End location, Type, Guided
|
|
16
|
+
|
|
17
|
+
Cruise activity: Type
|
|
18
|
+
|
|
19
|
+
Ground accommodation: City
|
|
20
|
+
|
|
21
|
+
Ship accommodation: Vessel ID (hide on IB)
|
|
22
|
+
|
|
23
|
+
Private and Guided render as a tick (✓) when true
|
|
24
|
+
|
|
25
|
+
When Private or Guided is false or unpopulated, the field is omitted entirely
|
|
26
|
+
*/
|
|
27
|
+
const INLINE_CONTENT_BY_TEMPLATE = {
|
|
28
|
+
[TEMPLATE_NAMES.SHIP_ACCOMMODATION]: {
|
|
29
|
+
render: (component, _lookups, isTemplateEditor) => {
|
|
30
|
+
var _a;
|
|
31
|
+
if (!isTemplateEditor)
|
|
32
|
+
return null;
|
|
33
|
+
const vesselId = (_a = getComponentDataByTemplateName(TEMPLATE_NAMES.SHIP_ACCOMMODATION, component.componentFields)) === null || _a === void 0 ? void 0 : _a.vesselID;
|
|
34
|
+
if (!vesselId)
|
|
35
|
+
return null;
|
|
36
|
+
return (React.createElement(Typography, { variant: "body2", color: "text.secondary" },
|
|
37
|
+
"Vessel ID: ",
|
|
38
|
+
vesselId));
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
// plus the rest in from there...
|
|
42
|
+
};
|
|
43
|
+
const getInlineContentDefinition = (templateName) => templateName ? INLINE_CONTENT_BY_TEMPLATE[templateName] : undefined;
|
|
44
|
+
const ComponentListItem = ({ component, isSelected, details, onSelect, showDivider, system, }) => {
|
|
45
|
+
var _a, _b, _c, _d, _e;
|
|
7
46
|
const activityData = (_a = getComponentDataByTemplateName(TEMPLATE_NAMES.CRUISE_ACTIVITY, component.componentFields)) !== null && _a !== void 0 ? _a : getComponentDataByTemplateName(TEMPLATE_NAMES.ACTIVITY, component.componentFields);
|
|
8
47
|
const displayName = (activityData === null || activityData === void 0 ? void 0 : activityData.type)
|
|
9
48
|
? `${activityData.type} - ${component.name}`
|
|
10
49
|
: component.name;
|
|
50
|
+
const convertToTitleCase = (str) => {
|
|
51
|
+
return str.replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase());
|
|
52
|
+
};
|
|
53
|
+
const inlineContentDefinition = getInlineContentDefinition((_b = details.template) === null || _b === void 0 ? void 0 : _b.name);
|
|
54
|
+
const requiredComponentIds = (_d = (_c = inlineContentDefinition === null || inlineContentDefinition === void 0 ? void 0 : inlineContentDefinition.getRequiredComponentIds) === null || _c === void 0 ? void 0 : _c.call(inlineContentDefinition, component)) !== null && _d !== void 0 ? _d : [];
|
|
55
|
+
const requiredComponentIdsKey = requiredComponentIds.join(",");
|
|
56
|
+
const [lookups, setLookups] = useState({});
|
|
57
|
+
const isTemplateEditor = system === COMPONENT_SYSTEMS.TEMPLATE_EDITOR;
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
const missingIds = requiredComponentIds.filter((id) => !lookups[id]);
|
|
60
|
+
if (!missingIds.length)
|
|
61
|
+
return;
|
|
62
|
+
let cancelled = false;
|
|
63
|
+
getComponentsByIds(missingIds).then((fetched) => {
|
|
64
|
+
if (cancelled)
|
|
65
|
+
return;
|
|
66
|
+
setLookups((prev) => (Object.assign(Object.assign({}, prev), Object.fromEntries(fetched.map((c) => [c.id, c])))));
|
|
67
|
+
});
|
|
68
|
+
return () => { cancelled = true; };
|
|
69
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
70
|
+
}, [requiredComponentIdsKey]);
|
|
71
|
+
const inlineContent = (_e = inlineContentDefinition === null || inlineContentDefinition === void 0 ? void 0 : inlineContentDefinition.render(component, lookups, isTemplateEditor)) !== null && _e !== void 0 ? _e : null;
|
|
11
72
|
return (React.createElement(React.Fragment, null,
|
|
12
73
|
React.createElement(ListItem, { disablePadding: true },
|
|
13
74
|
React.createElement(ListItemButton, { onClick: () => onSelect(component), selected: isSelected, sx: {
|
|
@@ -20,21 +81,23 @@ const ComponentListItem = ({ component, isSelected, details, onSelect, showDivid
|
|
|
20
81
|
borderColor: "primary.main",
|
|
21
82
|
},
|
|
22
83
|
} },
|
|
23
|
-
React.createElement(Box, { width: "100%" },
|
|
24
|
-
React.createElement(ListItemText, { primary: React.createElement(
|
|
25
|
-
details.template && (React.createElement(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
React.createElement(Typography, { variant: "body2", color: "text.secondary" },
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
React.createElement(Typography, { variant: "body2", color: "text.secondary" },
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
84
|
+
React.createElement(Box, { width: "100%", display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 2 },
|
|
85
|
+
React.createElement(ListItemText, { primary: React.createElement(Box, { display: "flex", flexDirection: "column", gap: 0.5 },
|
|
86
|
+
details.template && (React.createElement(Box, null,
|
|
87
|
+
React.createElement(Chip, { label: convertToTitleCase(details.template.name), size: "small", sx: Object.assign(Object.assign({}, getTemplateChipStyle(details.template.name)), { fontWeight: 500 }) }))),
|
|
88
|
+
React.createElement(Typography, { variant: "subtitle1", fontWeight: "medium" }, displayName)), secondary: React.createElement(Box, { display: "flex", flexDirection: "column", gap: 0.5, mt: 1 },
|
|
89
|
+
React.createElement(Box, { display: "flex", alignItems: "center", gap: 3, flexWrap: "wrap" },
|
|
90
|
+
details.partners.length > 0 && (React.createElement(Typography, { variant: "body2", color: "text.secondary" },
|
|
91
|
+
"Partner: ",
|
|
92
|
+
details.partners[0].title)),
|
|
93
|
+
(component === null || component === void 0 ? void 0 : component.destination) && (React.createElement(Typography, { variant: "body2", color: "text.secondary" },
|
|
94
|
+
"Destination: ",
|
|
95
|
+
convertToTitleCase(component.destination))),
|
|
96
|
+
details.regions.length > 0 && (React.createElement(Typography, { variant: "body2", color: "text.secondary" },
|
|
97
|
+
"Region: ",
|
|
98
|
+
details.regions[0].name))),
|
|
99
|
+
inlineContent && (React.createElement(Box, { display: "flex", alignItems: "center", gap: 3, flexWrap: "wrap" }, inlineContent))) }),
|
|
100
|
+
isTemplateEditor && (React.createElement(Button, { component: "a", href: `${window.location.origin}/components/${component.id}`, target: "_blank", rel: "noopener noreferrer", variant: "outlined", size: "small", onClick: (e) => e.stopPropagation(), sx: { flexShrink: 0 } }, "View"))))),
|
|
38
101
|
showDivider && React.createElement(Divider, null)));
|
|
39
102
|
};
|
|
40
103
|
export default ComponentListItem;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { DTOComponentRead } from "../../api/generated/core/exports";
|
|
3
|
+
import { ComponentSystem } from "../consts/system";
|
|
3
4
|
interface ComponentPickerModalProps {
|
|
4
5
|
open: boolean;
|
|
5
6
|
onClose: () => void;
|
|
6
7
|
onSelect: (component: DTOComponentRead) => void;
|
|
7
8
|
selectedComponent?: DTOComponentRead | null;
|
|
8
9
|
parentIdsFilter?: Array<string>;
|
|
10
|
+
system?: ComponentSystem;
|
|
9
11
|
}
|
|
10
|
-
export default function ComponentPickerModal({ open, onClose, onSelect, selectedComponent, parentIdsFilter, }: ComponentPickerModalProps): React.JSX.Element;
|
|
12
|
+
export default function ComponentPickerModal({ open, onClose, onSelect, selectedComponent, parentIdsFilter, system, }: ComponentPickerModalProps): React.JSX.Element;
|
|
11
13
|
export {};
|
|
@@ -15,7 +15,7 @@ import { fetchComponents, getAllPartners } from "../util/api";
|
|
|
15
15
|
import { InternalServices } from "../../api/init";
|
|
16
16
|
import ComponentListItem from "./ComponentListItem";
|
|
17
17
|
import { TEMPLATE_NAMES, templateStructure, } from "../../lib/config/templateStructure";
|
|
18
|
-
export default function ComponentPickerModal({ open, onClose, onSelect, selectedComponent, parentIdsFilter, }) {
|
|
18
|
+
export default function ComponentPickerModal({ open, onClose, onSelect, selectedComponent, parentIdsFilter, system, }) {
|
|
19
19
|
const [searchTerm, setSearchTerm] = useState("");
|
|
20
20
|
const [selectedRegion, setSelectedRegion] = useState("");
|
|
21
21
|
const [selectedPartner, setSelectedPartner] = useState("");
|
|
@@ -240,7 +240,7 @@ export default function ComponentPickerModal({ open, onClose, onSelect, selected
|
|
|
240
240
|
React.createElement(Typography, { variant: "body1", color: "text.secondary" }, "Loading components..."))) : components.length === 0 ? (React.createElement(Box, { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", py: 4 },
|
|
241
241
|
React.createElement(FilterIcon, { sx: { fontSize: 48, color: "text.secondary", mb: 2 } }),
|
|
242
242
|
React.createElement(Typography, { variant: "body1", color: "text.secondary" }, "No components match your search criteria"),
|
|
243
|
-
React.createElement(Typography, { variant: "body2", color: "text.secondary" }, "Try adjusting your filters or search term"))) : (components.map((component, index) => (React.createElement(ComponentListItem, { key: component.id, component: component, isSelected: (selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id) === component.id, details: getComponentDetails(component), onSelect: handleSelect, showDivider: index < components.length - 1 }))))),
|
|
243
|
+
React.createElement(Typography, { variant: "body2", color: "text.secondary" }, "Try adjusting your filters or search term"))) : (components.map((component, index) => (React.createElement(ComponentListItem, { key: component.id, component: component, isSelected: (selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id) === component.id, details: getComponentDetails(component), onSelect: handleSelect, showDivider: index < components.length - 1, system: system }))))),
|
|
244
244
|
components.length > 0 && (React.createElement(Box, { display: "flex", justifyContent: "center", mt: 2 },
|
|
245
245
|
React.createElement(Pagination, { count: Math.ceil(totalCount / pageSize), page: page, onChange: (_, newPage) => setPage(newPage), color: "primary" })))),
|
|
246
246
|
React.createElement(DialogActions, null,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { TEMPLATE_NAMES } from "../../lib/config/templateStructure";
|
|
2
|
+
export const TEMPLATE_CHIP_STYLES = {
|
|
3
|
+
[TEMPLATE_NAMES.PACKAGE]: { backgroundColor: "#DCEEFB", color: "#1565C0" }, // blue
|
|
4
|
+
[TEMPLATE_NAMES.PACKAGES]: { backgroundColor: "#DCEEFB", color: "#1565C0" }, // blue
|
|
5
|
+
[TEMPLATE_NAMES.TRANSFER]: { backgroundColor: "#ECE5FF", color: "#6D4AFF" }, // purple
|
|
6
|
+
[TEMPLATE_NAMES.ACTIVITY]: { backgroundColor: "#E8F0D9", color: "#5B7F3D" }, // green
|
|
7
|
+
[TEMPLATE_NAMES.CRUISE_ACTIVITY]: { backgroundColor: "#D7F5EA", color: "#1F9074" }, // different shade of green
|
|
8
|
+
[TEMPLATE_NAMES.GROUND_ACCOMMODATION]: { backgroundColor: "#F7E8C8", color: "#9C6B1F" }, // tan
|
|
9
|
+
[TEMPLATE_NAMES.SHIP_ACCOMMODATION]: { backgroundColor: "#FBDCE9", color: "#B23A6B" }, // pink
|
|
10
|
+
};
|
|
11
|
+
export const getTemplateChipStyle = (templateName) => { var _a; return (_a = TEMPLATE_CHIP_STYLES[templateName]) !== null && _a !== void 0 ? _a : { backgroundColor: "grey.200", color: "text.secondary" }; };
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { DTOComponentRead } from '../../api/generated/core/exports';
|
|
3
|
+
import { ComponentSystem } from '../consts/system';
|
|
3
4
|
interface ComponentPickerExports {
|
|
4
5
|
get: (parentIds?: Array<string>) => Promise<DTOComponentRead>;
|
|
5
6
|
}
|
|
6
7
|
interface Props {
|
|
7
8
|
children?: React.ReactNode;
|
|
9
|
+
system?: ComponentSystem;
|
|
8
10
|
}
|
|
9
11
|
export declare const useComponentPicker: () => ComponentPickerExports;
|
|
10
12
|
export declare const ComponentPickerProvider: React.FC<Props>;
|
|
@@ -16,7 +16,7 @@ export const useComponentPicker = () => {
|
|
|
16
16
|
throw new Error("useComponentPicker used from outside selector context");
|
|
17
17
|
return picker;
|
|
18
18
|
};
|
|
19
|
-
export const ComponentPickerProvider = ({ children }) => {
|
|
19
|
+
export const ComponentPickerProvider = ({ children, system }) => {
|
|
20
20
|
const [open, setOpen] = useState(false);
|
|
21
21
|
const changeProp = useRef(() => { });
|
|
22
22
|
const closeProp = useRef(() => { });
|
|
@@ -44,6 +44,6 @@ export const ComponentPickerProvider = ({ children }) => {
|
|
|
44
44
|
});
|
|
45
45
|
});
|
|
46
46
|
return (React.createElement(ComponentSelectorContext.Provider, { value: { get: getSelectedComponent } },
|
|
47
|
-
React.createElement(ComponentPickerModal, { parentIdsFilter: parentIds.length ? parentIds : undefined, open: open, onClose: closeProp.current, onSelect: changeProp.current }),
|
|
47
|
+
React.createElement(ComponentPickerModal, { parentIdsFilter: parentIds.length ? parentIds : undefined, open: open, onClose: closeProp.current, onSelect: changeProp.current, system: system }),
|
|
48
48
|
children));
|
|
49
49
|
};
|
|
@@ -10,3 +10,5 @@ export { MasterSchema, Stage } from "./schema/formSchemaTypes";
|
|
|
10
10
|
export { FORM_BUILDER_JSON_SCHEMA } from "./schema/formBuilders/formBuilderJsonSchema";
|
|
11
11
|
export { FORM_BUILDER_UI_SCHEMA } from "./schema/formBuilders/formBuilderUiSchema";
|
|
12
12
|
export * from "./contexts/ComponentPickerContext";
|
|
13
|
+
export * from "./consts/system";
|
|
14
|
+
export * from "./consts/templateChipStyles";
|
package/dist/rendering/index.js
CHANGED
|
@@ -10,3 +10,5 @@ export { Stage } from "./schema/formSchemaTypes";
|
|
|
10
10
|
export { FORM_BUILDER_JSON_SCHEMA } from "./schema/formBuilders/formBuilderJsonSchema";
|
|
11
11
|
export { FORM_BUILDER_UI_SCHEMA } from "./schema/formBuilders/formBuilderUiSchema";
|
|
12
12
|
export * from "./contexts/ComponentPickerContext";
|
|
13
|
+
export * from "./consts/system";
|
|
14
|
+
export * from "./consts/templateChipStyles";
|
|
@@ -50,3 +50,18 @@ export const fetchComponents = (filters) => __awaiter(void 0, void 0, void 0, fu
|
|
|
50
50
|
});
|
|
51
51
|
return { data: latestComponents, pagination: data.pagination };
|
|
52
52
|
});
|
|
53
|
+
export const getComponentsByIds = (componentIds) => __awaiter(void 0, void 0, void 0, function* () {
|
|
54
|
+
const uniqueIds = Array.from(new Set(componentIds.filter(Boolean)));
|
|
55
|
+
if (!uniqueIds.length)
|
|
56
|
+
return [];
|
|
57
|
+
try {
|
|
58
|
+
const response = yield InternalServices.CoreService.componentBatchGet({
|
|
59
|
+
componentIds: uniqueIds,
|
|
60
|
+
});
|
|
61
|
+
return response.data || [];
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
console.error("Failed to fetch components by id:", error);
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
});
|