Skip to content

Commit f2effab

Browse files
committed
Correct error handling behaviour for DateInput
1 parent a6e3fba commit f2effab

File tree

3 files changed

+59
-8
lines changed

3 files changed

+59
-8
lines changed

src/components/checkboxes/Checkboxes.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,12 @@ class Checkboxes extends PureComponent<CheckboxesProps, CheckboxesState> {
8080
hintProps={hintProps}
8181
/>
8282
<CheckboxContext.Provider value={{ isCheckbox: true, name, getBoxId: this.getBoxId }}>
83-
<div className={classNames('nhsuk-checkboxes', className)} id={id} {...rest}>
83+
<div
84+
className={classNames('nhsuk-checkboxes', className)}
85+
id={id}
86+
aria-describedby={hint ? `${id}--hint` : undefined}
87+
{...rest}
88+
>
8489
{children}
8590
</div>
8691
</CheckboxContext.Provider>

src/components/date-input/DateInput.tsx

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ import classNames from 'classnames';
1111
import { FormElementProps } from '../../util/types/FormTypes';
1212
import { generateRandomName } from '../../util/RandomName';
1313
import LabelBlock from '../../util/LabelBlock';
14+
import FormContext, { IFormContext } from '../form/FormContext';
1415

1516
interface IDateInputContext {
1617
isDateInput: boolean;
1718
registerRef: (type: DateInputType, ref: HTMLInputElement | null) => void;
19+
registerError: (type: DateInputType, error: boolean | undefined) => void;
1820
name: string;
1921
autoCompletePrefix: string | undefined;
2022
error?: string | boolean;
@@ -23,6 +25,7 @@ interface IDateInputContext {
2325
const DateInputContext = createContext<IDateInputContext>({
2426
isDateInput: false,
2527
registerRef: () => undefined,
28+
registerError: () => undefined,
2629
name: '',
2730
autoCompletePrefix: '',
2831
error: '',
@@ -41,7 +44,7 @@ const DateInputInput: React.FC<DateInputInputProps> = ({
4144
autoComplete,
4245
...rest
4346
}) => {
44-
const { isDateInput, registerRef, name, autoCompletePrefix, error } = useContext<
47+
const { isDateInput, registerRef, name, autoCompletePrefix, registerError, error } = useContext<
4548
IDateInputContext
4649
>(DateInputContext);
4750
const inputRef = useRef<HTMLInputElement>(null);
@@ -52,6 +55,12 @@ const DateInputInput: React.FC<DateInputInputProps> = ({
5255
}
5356
}, [inputRef.current]);
5457

58+
useEffect(() => {
59+
if (isDateInput) {
60+
registerError(dateInputType, rest.error);
61+
}
62+
}, [rest.error]);
63+
5564
return (
5665
<div className="nhsuk-date-input__item">
5766
<div className="nhsuk-form-group">
@@ -123,6 +132,12 @@ type DateInputValue = {
123132
year: string;
124133
};
125134

135+
type DateInputErrors = {
136+
day: boolean | undefined;
137+
month: boolean | undefined;
138+
year: boolean | undefined;
139+
};
140+
126141
interface DateInputProps
127142
extends Omit<HTMLProps<HTMLDivElement>, 'onChange' | 'value' | 'defaultValue'>,
128143
FormElementProps {
@@ -133,11 +148,16 @@ interface DateInputProps
133148
defaultValue?: DateInputValue;
134149
}
135150

136-
type DateInputState = {
151+
export type DateInputState = {
137152
name: string;
138153
value: DateInputValue;
154+
errors: DateInputErrors;
139155
};
140156

157+
interface DateInput extends PureComponent<DateInputProps, DateInputState> {
158+
context: IFormContext;
159+
}
160+
141161
interface DateInput extends PureComponent<DateInputProps, DateInputState> {
142162
monthRef: HTMLInputElement | null;
143163
yearRef: HTMLInputElement | null;
@@ -149,11 +169,33 @@ class DateInput extends PureComponent<DateInputProps, DateInputState> {
149169
this.state = {
150170
name: props.name || generateRandomName('dateinput'),
151171
value: { day: '', month: '', year: '' },
172+
errors: { day: undefined, month: undefined, year: undefined },
152173
};
153174
this.monthRef = null;
154175
this.yearRef = null;
155176
}
156177

178+
componentDidUpdate() {
179+
if (!this.context.isForm) return;
180+
if (this.props.error !== undefined) {
181+
this.context.setError(this.state.name, Boolean(this.props.error));
182+
} else {
183+
const { day, month, year } = this.state.errors;
184+
const errorInChild = day || month || year;
185+
this.context.setError(this.state.name, Boolean(errorInChild));
186+
}
187+
}
188+
189+
registerError = (type: DateInputType, error: boolean | undefined) => {
190+
this.setState(state => ({
191+
...state,
192+
errors: {
193+
...state.errors,
194+
[type]: error,
195+
},
196+
}));
197+
};
198+
157199
registerRef = (type: DateInputType, ref: HTMLInputElement | null) => {
158200
if (ref !== null) {
159201
if (type === 'Month') {
@@ -166,7 +208,6 @@ class DateInput extends PureComponent<DateInputProps, DateInputState> {
166208

167209
onChange = (e: SyntheticEvent<HTMLInputElement>) => {
168210
e.stopPropagation();
169-
170211
const target = e.target as HTMLInputElement;
171212
const { value, name } = this.state;
172213
if (target && target.name) {
@@ -188,6 +229,7 @@ class DateInput extends PureComponent<DateInputProps, DateInputState> {
188229
currentTarget: { ...target, name, value },
189230
};
190231

232+
this.setState({ value });
191233
if (this.props.onChange) {
192234
this.props.onChange(newEvent);
193235
}
@@ -202,6 +244,8 @@ class DateInput extends PureComponent<DateInputProps, DateInputState> {
202244
}
203245
};
204246

247+
static contextType = FormContext;
248+
205249
static Day = DateInputDay;
206250

207251
static Month = DateInputMonth;
@@ -227,8 +271,10 @@ class DateInput extends PureComponent<DateInputProps, DateInputState> {
227271
...rest
228272
} = this.props;
229273
const { name } = this.state;
274+
230275
const contextValue = {
231276
isDateInput: true,
277+
registerError: this.registerError,
232278
registerRef: this.registerRef,
233279
name,
234280
autoCompletePrefix,

src/components/header/components/NHSLogo.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ const NHSLogo: React.FC<HTMLProps<HTMLAnchorElement>> = ({ className, alt, ...re
2727
aria-labelledby="nhsuk-logo_title"
2828
>
2929
<title id="nhsuk-logo_title">{alt}</title>
30-
<path className="nhsuk-logo__background" d="M0 0h40v16H0z"></path>
30+
<path className="nhsuk-logo__background" d="M0 0h40v16H0z" />
3131
<path
3232
className="nhsuk-logo__text"
3333
d="M3.9 1.5h4.4l2.6 9h.1l1.8-9h3.3l-2.8 13H9l-2.7-9h-.1l-1.8 9H1.1M17.3 1.5h3.6l-1 4.9h4L25 1.5h3.5l-2.7 13h-3.5l1.1-5.6h-4.1l-1.2 5.6h-3.4M37.7 4.4c-.7-.3-1.6-.6-2.9-.6-1.4 0-2.5.2-2.5 1.3 0 1.8 5.1 1.2 5.1 5.1 0 3.6-3.3 4.5-6.4 4.5-1.3 0-2.9-.3-4-.7l.8-2.7c.7.4 2.1.7 3.2.7s2.8-.2 2.8-1.5c0-2.1-5.1-1.3-5.1-5 0-3.4 2.9-4.4 5.8-4.4 1.6 0 3.1.2 4 .6"
34-
></path>
35-
<img src="https://assets.nhs.uk/images/nhs-logo.png" alt={alt}/>
34+
/>
35+
<img src="https://assets.nhs.uk/images/nhs-logo.png" alt={alt} />
3636
</svg>
3737
{serviceName ? <span className="nhsuk-header__service-name">{serviceName}</span> : null}
3838
</a>
@@ -42,7 +42,7 @@ const NHSLogo: React.FC<HTMLProps<HTMLAnchorElement>> = ({ className, alt, ...re
4242

4343
NHSLogo.defaultProps = {
4444
'aria-label': 'NHS homepage',
45-
'alt': 'NHS Logo',
45+
alt: 'NHS Logo',
4646
};
4747

4848
export default NHSLogo;

0 commit comments

Comments
 (0)