Skip to content

Commit af1bdc8

Browse files
authored
fix(Forms): ensure city in PostalCodeAndCity accepts non-Norwegian characters when using other country (#4569)
1 parent 4d962df commit af1bdc8

File tree

2 files changed

+129
-86
lines changed

2 files changed

+129
-86
lines changed

packages/dnb-eufemia/src/extensions/forms/Field/PostalCodeAndCity/PostalCodeAndCity.tsx

+22-5
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,33 @@ function PostalCodeAndCity(props: Props) {
3737
...fieldBlockProps
3838
} = props
3939

40+
const countryValue = getSourceValue(country)
41+
42+
const handleCityDefaults = useCallback(
43+
(city: StringFieldProps) => {
44+
const props: StringFieldProps = {}
45+
46+
switch (countryValue) {
47+
case defaultCountry: {
48+
props.pattern = '^[A-Za-zÆØÅæøå -]+$'
49+
break
50+
}
51+
}
52+
53+
return { ...props, ...city }
54+
},
55+
[countryValue]
56+
)
57+
4058
const {
4159
pattern: cityPattern,
4260
className: cityClassName,
4361
label: cityLabel,
4462
width: cityWidth,
4563
errorMessages: cityErrorMessages,
46-
} = city
64+
} = handleCityDefaults(city)
4765

48-
const countryValue = getSourceValue(country)
49-
const handleDefaults = useCallback(
66+
const handlePostalCodeDefaults = useCallback(
5067
(postalCode: StringFieldProps) => {
5168
const props: StringFieldProps = {}
5269

@@ -77,7 +94,7 @@ function PostalCodeAndCity(props: Props) {
7794
label: postalCodeLabel,
7895
width: postalCodeWidth,
7996
errorMessages: postalCodeErrorMessages,
80-
} = handleDefaults(postalCode)
97+
} = handlePostalCodeDefaults(postalCode)
8198

8299
return (
83100
<CompositionField
@@ -136,7 +153,7 @@ function PostalCodeAndCity(props: Props) {
136153
translations.City.errorRequired,
137154
]
138155
)}
139-
pattern={cityPattern ?? '^[A-Za-zÆØÅæøå -]+$'}
156+
pattern={cityPattern}
140157
trim
141158
width={cityWidth ?? 'stretch'}
142159
autoComplete="address-level2"

packages/dnb-eufemia/src/extensions/forms/Field/PostalCodeAndCity/__tests__/PostalCodeAndCity.test.tsx

+107-81
Original file line numberDiff line numberDiff line change
@@ -164,108 +164,134 @@ describe('Field.PostalCodeAndCity', () => {
164164
expect(city2).toHaveValue('Bergen')
165165
})
166166

167-
it('should not use Norwegian postal code validation rules if `country` is set to something other than `NO`', async () => {
168-
render(<Field.PostalCodeAndCity country="DE" />)
167+
describe('country', () => {
168+
it('should not use Norwegian postal code validation rules if `country` is set to something other than `NO`', async () => {
169+
render(<Field.PostalCodeAndCity country="DE" />)
169170

170-
const postalCodeInput = document.querySelector(
171-
'.dnb-forms-field-postal-code-and-city__postal-code .dnb-input__input'
172-
) as HTMLInputElement
171+
const postalCodeInput = document.querySelector(
172+
'.dnb-forms-field-postal-code-and-city__postal-code .dnb-input__input'
173+
) as HTMLInputElement
173174

174-
expect(postalCodeInput).not.toHaveAttribute('placeholder')
175+
expect(postalCodeInput).not.toHaveAttribute('placeholder')
175176

176-
await userEvent.type(postalCodeInput, '123456')
177+
await userEvent.type(postalCodeInput, '123456')
177178

178-
expect(postalCodeInput).toHaveValue('123456')
179-
})
179+
expect(postalCodeInput).toHaveValue('123456')
180+
})
180181

181-
it('should support custom postal code validation', async () => {
182-
render(
183-
<Field.PostalCodeAndCity
184-
country="DE"
185-
postalCode={{
186-
pattern: '^[0-9]{5}$',
187-
mask: [/\d/, /\d/, /\d/, /\d/, /\d/],
188-
placeholder: '00000',
189-
validateInitially: true,
190-
}}
191-
city={{
192-
validateInitially: true,
193-
pattern: '^[a-zA-ZäöüÄÖÜß -]+$',
194-
}}
195-
/>
196-
)
182+
it('should not use Norwegian city validation rules if `country` is set to something other than `NO`', async () => {
183+
const { rerender } = render(<Field.PostalCodeAndCity />)
197184

198-
const [postalCode, city] = Array.from(
199-
document.querySelectorAll('input')
200-
)
185+
const city = document.querySelector(
186+
'.dnb-forms-field-postal-code-and-city__city .dnb-input__input'
187+
) as HTMLInputElement
201188

202-
expect(postalCode).toHaveAttribute('aria-placeholder', '00000')
203-
await userEvent.type(postalCode, 'abcs123456')
189+
expect(city).not.toHaveAttribute('placeholder')
204190

205-
expect(postalCode).toHaveValue('12345')
191+
await userEvent.type(city, 'äöü')
192+
fireEvent.blur(city)
206193

207-
await userEvent.type(city, 'München')
194+
expect(city).toHaveValue('äöü')
195+
expect(screen.queryByRole('alert')).toBeInTheDocument()
208196

209-
expect(city).toHaveValue('München')
210-
expect(screen.queryByRole('alert')).not.toBeInTheDocument()
211-
})
197+
rerender(<Field.PostalCodeAndCity country="DE" />)
212198

213-
it('should be able to use a path to set the country value', async () => {
214-
const { rerender } = render(
215-
<Form.Handler data={{ country: 'DE' }}>
216-
<Field.PostalCodeAndCity country="/country" />
217-
</Form.Handler>
218-
)
199+
await userEvent.type(city, 'äöü')
200+
fireEvent.blur(city)
219201

220-
const postalCodeDe = document.querySelector(
221-
'.dnb-forms-field-postal-code-and-city input'
222-
)
202+
expect(city).toHaveValue('äöüäöü')
203+
expect(screen.queryByRole('alert')).not.toBeInTheDocument()
204+
})
223205

224-
await userEvent.type(postalCodeDe, '123456')
225-
expect(postalCodeDe).toHaveValue('123456')
226-
expect(postalCodeDe).not.toHaveAttribute('aria-placeholder')
206+
it('should support custom postal code validation', async () => {
207+
render(
208+
<Field.PostalCodeAndCity
209+
country="DE"
210+
postalCode={{
211+
pattern: '^[0-9]{5}$',
212+
mask: [/\d/, /\d/, /\d/, /\d/, /\d/],
213+
placeholder: '00000',
214+
validateInitially: true,
215+
}}
216+
city={{
217+
validateInitially: true,
218+
pattern: '^[a-zA-ZäöüÄÖÜß -]+$',
219+
}}
220+
/>
221+
)
227222

228-
rerender(
229-
<Form.Handler data={{ country: 'NO' }}>
230-
<Field.PostalCodeAndCity country="/country" />
231-
</Form.Handler>
232-
)
223+
const [postalCode, city] = Array.from(
224+
document.querySelectorAll('input')
225+
)
233226

234-
const postalCodeNo = document.querySelector(
235-
'.dnb-forms-field-postal-code-and-city input'
236-
)
227+
expect(postalCode).toHaveAttribute('aria-placeholder', '00000')
228+
await userEvent.type(postalCode, 'abcs123456')
237229

238-
await userEvent.type(postalCodeNo, '{Backspace>4}987654')
239-
expect(postalCodeNo).toHaveValue('9876')
240-
expect(postalCodeNo).toHaveAttribute('aria-placeholder', '0000')
241-
})
230+
expect(postalCode).toHaveValue('12345')
242231

243-
it('should use value from country inside iterate', async () => {
244-
render(
245-
<Form.Handler
246-
defaultData={{ items: [{ country: 'NO' }, { country: 'DE' }] }}
247-
>
248-
<Iterate.Array path="/items">
232+
await userEvent.type(city, 'München')
233+
234+
expect(city).toHaveValue('München')
235+
expect(screen.queryByRole('alert')).not.toBeInTheDocument()
236+
})
237+
238+
it('should be able to use a path to set the country value', async () => {
239+
const { rerender } = render(
240+
<Form.Handler data={{ country: 'DE' }}>
249241
<Field.PostalCodeAndCity country="/country" />
250-
</Iterate.Array>
251-
</Form.Handler>
252-
)
242+
</Form.Handler>
243+
)
253244

254-
const [norway, germany] = Array.from(
255-
document.querySelectorAll('.dnb-forms-field-postal-code-and-city')
256-
)
245+
const postalCodeDe = document.querySelector(
246+
'.dnb-forms-field-postal-code-and-city input'
247+
)
257248

258-
await userEvent.type(
259-
norway.querySelector('input'),
260-
'{Backspace>4}987654'
261-
)
262-
expect(norway.querySelector('input').value).toBe('9876')
249+
await userEvent.type(postalCodeDe, '123456')
250+
expect(postalCodeDe).toHaveValue('123456')
251+
expect(postalCodeDe).not.toHaveAttribute('aria-placeholder')
263252

264-
await userEvent.type(
265-
germany.querySelector('input'),
266-
'{Backspace>4}987654'
267-
)
268-
expect(germany.querySelector('input').value).toBe('987654')
253+
rerender(
254+
<Form.Handler data={{ country: 'NO' }}>
255+
<Field.PostalCodeAndCity country="/country" />
256+
</Form.Handler>
257+
)
258+
259+
const postalCodeNo = document.querySelector(
260+
'.dnb-forms-field-postal-code-and-city input'
261+
)
262+
263+
await userEvent.type(postalCodeNo, '{Backspace>4}987654')
264+
expect(postalCodeNo).toHaveValue('9876')
265+
expect(postalCodeNo).toHaveAttribute('aria-placeholder', '0000')
266+
})
267+
268+
it('should use value from country inside iterate', async () => {
269+
render(
270+
<Form.Handler
271+
defaultData={{ items: [{ country: 'NO' }, { country: 'DE' }] }}
272+
>
273+
<Iterate.Array path="/items">
274+
<Field.PostalCodeAndCity country="/country" />
275+
</Iterate.Array>
276+
</Form.Handler>
277+
)
278+
279+
const [norway, germany] = Array.from(
280+
document.querySelectorAll('.dnb-forms-field-postal-code-and-city')
281+
)
282+
283+
await userEvent.type(
284+
norway.querySelector('input'),
285+
'{Backspace>4}987654'
286+
)
287+
expect(norway.querySelector('input').value).toBe('9876')
288+
289+
await userEvent.type(
290+
germany.querySelector('input'),
291+
'{Backspace>4}987654'
292+
)
293+
expect(germany.querySelector('input').value).toBe('987654')
294+
})
269295
})
270296

271297
describe('ARIA', () => {

0 commit comments

Comments
 (0)