pcm-shared-components 2.1.406 → 2.1.408
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.
|
@@ -22,6 +22,22 @@ const isFullWidthField = field => ['select', 'textarea', 'select_multiple', 'not
|
|
|
22
22
|
// through unflattened still works.
|
|
23
23
|
const readFieldProp = (field, key) => field[key] !== undefined ? field[key] : field.meta?.[key];
|
|
24
24
|
|
|
25
|
+
// Same type-aware required-field wording as AnimalVehicleDetailsEditor's tab-per-animal grid
|
|
26
|
+
// (index.jsx, this directory) -- duplicated rather than shared, matching the small amount of
|
|
27
|
+
// tolerated duplication already elsewhere in this feature (e.g. each host app keeps its own copy
|
|
28
|
+
// for its live-preview sandbox). Falls back to animal.required_error for text/textarea. 'notice'
|
|
29
|
+
// gets its own message rather than the generic one -- its required-satisfying condition is
|
|
30
|
+
// stricter than every other type (see isFieldAnswered below): only a CHECKED "I have read this"
|
|
31
|
+
// box counts, so "please fill this in" would read wrong for what's actually a checkbox.
|
|
32
|
+
const REQUIRED_ERROR_KEY_BY_TYPE = {
|
|
33
|
+
select: 'animal.required_error_select',
|
|
34
|
+
select_multiple: 'animal.required_error_select_multiple',
|
|
35
|
+
number: 'animal.required_error_number',
|
|
36
|
+
date: 'animal.required_error_date',
|
|
37
|
+
yes_no: 'animal.required_error_yes_no',
|
|
38
|
+
notice: 'animal.required_error_notice'
|
|
39
|
+
};
|
|
40
|
+
|
|
25
41
|
/**
|
|
26
42
|
* Flat, non-tabbed block for a lot's "once per reservation" animal fields: no tabs, no per-animal
|
|
27
43
|
* chrome, no add/remove -- these are single shared values/notices for the whole reservation, not
|
|
@@ -59,12 +75,14 @@ export const AnimalFieldsOnceBlock = props => {
|
|
|
59
75
|
fields,
|
|
60
76
|
values,
|
|
61
77
|
onChange,
|
|
78
|
+
isFieldAnswered,
|
|
62
79
|
className,
|
|
63
80
|
theme,
|
|
64
81
|
i18next
|
|
65
82
|
} = props;
|
|
66
83
|
const compTheme = theme || useTheme();
|
|
67
84
|
const defaultTheme = createTheme(compTheme);
|
|
85
|
+
const requiredErrorText = fieldType => i18next.t(REQUIRED_ERROR_KEY_BY_TYPE[fieldType] || 'animal.required_error');
|
|
68
86
|
const relevantFields = fields.filter(field => readFieldProp(field, 'once_per_reservation') === true);
|
|
69
87
|
if (relevantFields.length === 0) return null;
|
|
70
88
|
return /*#__PURE__*/React.createElement(ThemeProvider, {
|
|
@@ -80,6 +98,14 @@ export const AnimalFieldsOnceBlock = props => {
|
|
|
80
98
|
}
|
|
81
99
|
}, relevantFields.map(field => {
|
|
82
100
|
const rawValue = values?.[field.key] ?? (field.type === 'select_multiple' ? [] : '');
|
|
101
|
+
// Required-and-not-yet-answered gets the same red label + control error state the
|
|
102
|
+
// per-animal grid already shows (index.jsx, this directory) -- this block previously
|
|
103
|
+
// hardcoded error: false/helperText: '' unconditionally, so a required once-per-
|
|
104
|
+
// reservation field (e.g. a mandatory "I have read this" notice, or a required yes_no
|
|
105
|
+
// asked once) never visibly indicated it was outstanding. isFieldAnswered is supplied
|
|
106
|
+
// by the caller (same prop AnimalVehicleDetailsEditor already requires), since it's
|
|
107
|
+
// app-specific logic this shared package doesn't own.
|
|
108
|
+
const showError = field.required && !isFieldAnswered(field.type, rawValue);
|
|
83
109
|
const labelText = field.required ? `${field.label} *` : field.label;
|
|
84
110
|
return /*#__PURE__*/React.createElement("div", {
|
|
85
111
|
key: field.key,
|
|
@@ -88,7 +114,8 @@ export const AnimalFieldsOnceBlock = props => {
|
|
|
88
114
|
variant: "body2",
|
|
89
115
|
sx: {
|
|
90
116
|
fontWeight: 500,
|
|
91
|
-
mb: 0.5
|
|
117
|
+
mb: 0.5,
|
|
118
|
+
color: showError ? 'error.main' : 'text.primary'
|
|
92
119
|
}
|
|
93
120
|
}, labelText), renderFieldTypeControl({
|
|
94
121
|
field,
|
|
@@ -98,8 +125,8 @@ export const AnimalFieldsOnceBlock = props => {
|
|
|
98
125
|
// consumer's own event wiring calls it directly in a test.
|
|
99
126
|
onChange: onChange ? newValue => onChange(field.key, newValue) : () => {},
|
|
100
127
|
disabled: !onChange,
|
|
101
|
-
error:
|
|
102
|
-
helperText: '',
|
|
128
|
+
error: showError,
|
|
129
|
+
helperText: showError ? requiredErrorText(field.type) : '',
|
|
103
130
|
i18next
|
|
104
131
|
}));
|
|
105
132
|
}))));
|
|
@@ -138,6 +165,10 @@ AnimalFieldsOnceBlock.propTypes = {
|
|
|
138
165
|
/** (fieldKey, value) => void. Omit entirely to render every input control disabled/read-only
|
|
139
166
|
* (review-screen usage) -- see the component doc above. */
|
|
140
167
|
onChange: PropTypes.func,
|
|
168
|
+
/** (fieldType, value) => boolean. Same function each host app already passes into
|
|
169
|
+
* AnimalVehicleDetailsEditor's isFieldAnswered prop -- required so a required-but-unanswered
|
|
170
|
+
* once-per-reservation field can show the same red label/error state the per-animal grid does. */
|
|
171
|
+
isFieldAnswered: PropTypes.func.isRequired,
|
|
141
172
|
/** Classes applied to the component's own wrapper div. */
|
|
142
173
|
className: PropTypes.string,
|
|
143
174
|
/** Theme object to use on this component, if none provided then the MUI5 theme provider theme is used. */
|
|
@@ -119,6 +119,17 @@ const NoticeFieldControl = ({
|
|
|
119
119
|
color: error ? 'error' : 'primary'
|
|
120
120
|
}),
|
|
121
121
|
label: i18next.t('animal.read_notice_confirmation')
|
|
122
|
+
// The checkbox icon already goes red via `color` above when unchecked-and-required, but
|
|
123
|
+
// the label text next to it (the actual "I have read this" wording someone needs to read
|
|
124
|
+
// and act on) stayed the default color regardless -- targeting FormControlLabel's own
|
|
125
|
+
// label class is the supported way to color just that text, matching every other field's
|
|
126
|
+
// red label treatment above the control.
|
|
127
|
+
,
|
|
128
|
+
sx: {
|
|
129
|
+
'& .MuiFormControlLabel-label': {
|
|
130
|
+
color: error ? 'error.main' : 'text.primary'
|
|
131
|
+
}
|
|
132
|
+
}
|
|
122
133
|
}), helperText && /*#__PURE__*/React.createElement(FormHelperText, {
|
|
123
134
|
error: error
|
|
124
135
|
}, helperText));
|
|
@@ -92,12 +92,29 @@ export const AnimalVehicleDetailsEditor = props => {
|
|
|
92
92
|
canAddMore,
|
|
93
93
|
maxItems,
|
|
94
94
|
showHistoricalAnswers,
|
|
95
|
+
bare,
|
|
95
96
|
className,
|
|
96
97
|
theme,
|
|
97
98
|
i18next
|
|
98
99
|
} = props;
|
|
99
100
|
const compTheme = theme || useTheme();
|
|
100
101
|
const defaultTheme = createTheme(compTheme);
|
|
102
|
+
|
|
103
|
+
// `bare`: skip this component's own outer card (background/border/rounding) and render its
|
|
104
|
+
// content as a plain fragment instead -- for a caller that wants to place this editor and
|
|
105
|
+
// AnimalFieldsOnceBlock's once-per-reservation fields inside ONE shared outer card (a Divider
|
|
106
|
+
// between them, not two separate adjacent cards), rather than this component supplying its own
|
|
107
|
+
// competing card around just the per-item half. Off by default so every existing usage keeps
|
|
108
|
+
// its current self-contained card look unchanged.
|
|
109
|
+
const OuterWrapper = bare ? React.Fragment : Paper;
|
|
110
|
+
const outerWrapperProps = bare ? {} : {
|
|
111
|
+
variant: 'outlined',
|
|
112
|
+
sx: {
|
|
113
|
+
p: 1.5,
|
|
114
|
+
borderRadius: 2,
|
|
115
|
+
bgcolor: 'action.hover'
|
|
116
|
+
}
|
|
117
|
+
};
|
|
101
118
|
const keys = KEYS[itemType] || KEYS.animal;
|
|
102
119
|
const requiredErrorText = fieldType => i18next.t(REQUIRED_ERROR_KEY_BY_TYPE[fieldType] || 'animal.required_error');
|
|
103
120
|
const missingRequiredFields = item => fieldConfig.filter(f => f.required).filter(f => !isFieldAnswered(f.type, item.values?.[f.key] ?? (f.type === 'select_multiple' ? [] : '')));
|
|
@@ -234,14 +251,7 @@ export const AnimalVehicleDetailsEditor = props => {
|
|
|
234
251
|
theme: defaultTheme
|
|
235
252
|
}, /*#__PURE__*/React.createElement("div", {
|
|
236
253
|
className: className
|
|
237
|
-
}, /*#__PURE__*/React.createElement(
|
|
238
|
-
variant: "outlined",
|
|
239
|
-
sx: {
|
|
240
|
-
p: 1.5,
|
|
241
|
-
borderRadius: 2,
|
|
242
|
-
bgcolor: 'action.hover'
|
|
243
|
-
}
|
|
244
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
254
|
+
}, /*#__PURE__*/React.createElement(OuterWrapper, outerWrapperProps, /*#__PURE__*/React.createElement("div", {
|
|
245
255
|
className: "flex items-center justify-between mb-8"
|
|
246
256
|
}, /*#__PURE__*/React.createElement("div", {
|
|
247
257
|
className: "flex items-center",
|
|
@@ -605,6 +615,7 @@ AnimalVehicleDetailsEditor.defaultProps = {
|
|
|
605
615
|
canAddMore: true,
|
|
606
616
|
maxItems: 0,
|
|
607
617
|
showHistoricalAnswers: true,
|
|
618
|
+
bare: false,
|
|
608
619
|
className: 'w-full',
|
|
609
620
|
theme: undefined,
|
|
610
621
|
i18next: i18nextLocal
|
|
@@ -654,6 +665,10 @@ AnimalVehicleDetailsEditor.propTypes = {
|
|
|
654
665
|
* since-retired answer on an EXISTING reservation is legitimate. A guest-facing booking widget
|
|
655
666
|
* creating a brand-new reservation has no history to show and should pass false. */
|
|
656
667
|
showHistoricalAnswers: PropTypes.bool,
|
|
668
|
+
/** Skip this component's own outer card (background/border/rounding) and render a plain
|
|
669
|
+
* fragment instead -- for a caller placing this editor and AnimalFieldsOnceBlock's fields inside
|
|
670
|
+
* one shared outer card. Defaults to false so every existing usage keeps its current look. */
|
|
671
|
+
bare: PropTypes.bool,
|
|
657
672
|
/** Classes applied to the component's own wrapper div. */
|
|
658
673
|
className: PropTypes.string,
|
|
659
674
|
/** Theme object to use on this component, if none provided then the MUI5 theme provider theme is used. */
|