@popsure/dirty-swan 0.66.30 → 0.67.0

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.
Files changed (28) hide show
  1. package/dist/cjs/index.js +357 -346
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/cjs/lib/components/autocompleteAddress/index.d.ts +3 -1
  4. package/dist/cjs/lib/components/autocompleteAddress/index.stories.d.ts +14 -0
  5. package/dist/cjs/lib/components/table/components/TableCell/ButtonCell/ButtonCell.test.d.ts +1 -0
  6. package/dist/esm/components/autocompleteAddress/index.js +35 -20
  7. package/dist/esm/components/autocompleteAddress/index.js.map +1 -1
  8. package/dist/esm/components/autocompleteAddress/index.stories.js +25 -4
  9. package/dist/esm/components/autocompleteAddress/index.stories.js.map +1 -1
  10. package/dist/esm/components/autocompleteAddress/index.test.js +85 -4
  11. package/dist/esm/components/autocompleteAddress/index.test.js.map +1 -1
  12. package/dist/esm/components/table/components/TableCell/ButtonCell/ButtonCell.js +2 -2
  13. package/dist/esm/components/table/components/TableCell/ButtonCell/ButtonCell.js.map +1 -1
  14. package/dist/esm/components/table/components/TableCell/ButtonCell/ButtonCell.test.js +35 -0
  15. package/dist/esm/components/table/components/TableCell/ButtonCell/ButtonCell.test.js.map +1 -0
  16. package/dist/esm/{index-BYyiyH6K.js → index-DbXDuiSV.js} +2 -2
  17. package/dist/esm/{index-BYyiyH6K.js.map → index-DbXDuiSV.js.map} +1 -1
  18. package/dist/esm/index.js +1 -1
  19. package/dist/esm/lib/components/autocompleteAddress/index.d.ts +3 -1
  20. package/dist/esm/lib/components/autocompleteAddress/index.stories.d.ts +14 -0
  21. package/dist/esm/lib/components/table/components/TableCell/ButtonCell/ButtonCell.test.d.ts +1 -0
  22. package/dist/esm/util/images/index.stories.js +1 -1
  23. package/package.json +1 -1
  24. package/src/lib/components/autocompleteAddress/index.stories.tsx +24 -2
  25. package/src/lib/components/autocompleteAddress/index.test.tsx +59 -1
  26. package/src/lib/components/autocompleteAddress/index.tsx +58 -16
  27. package/src/lib/components/table/components/TableCell/ButtonCell/ButtonCell.test.tsx +22 -0
  28. package/src/lib/components/table/components/TableCell/ButtonCell/ButtonCell.tsx +1 -1
package/dist/esm/index.js CHANGED
@@ -448,7 +448,7 @@ import './_commonjsHelpers-BFTU3MAI.js';
448
448
  import './style-inject.es-tgCJW-Cu.js';
449
449
  import './index-DLQEsiym.js';
450
450
  import './index-BClARCFl.js';
451
- import './index-BYyiyH6K.js';
451
+ import './index-DbXDuiSV.js';
452
452
  import './index-CNcEE5dn.js';
453
453
  import './index-hWqCLhoS.js';
454
454
  import './index-DZVEBgCf.js';
@@ -27,12 +27,14 @@ export interface AutocompleteAddressProps {
27
27
  additionalInformation?: string;
28
28
  postcode?: string;
29
29
  city?: string;
30
+ country?: string;
31
+ countrySearch?: string;
30
32
  };
31
33
  manualAddressEntryTexts?: {
32
34
  preText?: string;
33
35
  cta?: string;
34
36
  };
35
- countryCode?: string;
37
+ countryCode?: string | null;
36
38
  }
37
39
  declare const AutocompleteAddress: ({ apiKey, address: initialAddress, onAddressChange, placeholders, manualAddressEntryTexts, inputProps, countryCode }: AutocompleteAddressProps) => JSX.Element;
38
40
  export { AutocompleteAddress };
@@ -42,6 +42,17 @@ declare const story: {
42
42
  };
43
43
  };
44
44
  };
45
+ countryCode: {
46
+ description: string;
47
+ table: {
48
+ type: {
49
+ summary: string;
50
+ };
51
+ defaultValue: {
52
+ summary: string;
53
+ };
54
+ };
55
+ };
45
56
  };
46
57
  args: {
47
58
  apiKey: string;
@@ -62,6 +73,9 @@ export declare const AutocompleteAddressStory: {
62
73
  export declare const WithAddress: {
63
74
  render: ({ apiKey, onAddressChange, placeholders, }: AutocompleteAddressProps) => JSX.Element;
64
75
  };
76
+ export declare const Worldwide: {
77
+ render: ({ apiKey, onAddressChange }: AutocompleteAddressProps) => JSX.Element;
78
+ };
65
79
  export declare const WithLocalisationEntryText: {
66
80
  render: ({ apiKey, onAddressChange }: AutocompleteAddressProps) => JSX.Element;
67
81
  };
@@ -6,7 +6,7 @@ import '../../components/dateSelector/index.js';
6
6
  import '../../components/signaturePad/index.js';
7
7
  import '../../index-BClARCFl.js';
8
8
  import { Input } from '../../components/input/index.js';
9
- import '../../index-BYyiyH6K.js';
9
+ import '../../index-DbXDuiSV.js';
10
10
  import '../../index-DYcCCrfR.js';
11
11
  import { Button } from '../../components/button/index.js';
12
12
  import '../../index-DZVEBgCf.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@popsure/dirty-swan",
3
- "version": "0.66.30",
3
+ "version": "0.67.0",
4
4
  "author": "Vincent Audoire <vincent@getpopsure.com>",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -45,7 +45,19 @@ const story = {
45
45
  table: {
46
46
  type: {
47
47
  summary:
48
- '{ manualAddressEntry?: string; street: string?; houseNumber?: string; additionalInformation?: string; postcode?: string; city?: string; }',
48
+ '{ manualAddressEntry?: string; street: string?; houseNumber?: string; additionalInformation?: string; postcode?: string; city?: string; country?: string; countrySearch?: string; }',
49
+ },
50
+ },
51
+ },
52
+ countryCode: {
53
+ description:
54
+ 'Alpha-2 country code to restrict the search to. Pass `null` to search worldwide and let the user pick the country when entering the address manually.',
55
+ table: {
56
+ type: {
57
+ summary: 'string | null',
58
+ },
59
+ defaultValue: {
60
+ summary: 'DE',
49
61
  },
50
62
  },
51
63
  },
@@ -59,7 +71,7 @@ const story = {
59
71
  docs: {
60
72
  description: {
61
73
  component:
62
- 'This component is for now only restricted to "address" types and will restrict every query to Germany.',
74
+ 'This component is restricted to "address" types and restricts every query to Germany by default. Use `countryCode` to restrict it to another country, or `null` to search worldwide.',
63
75
  },
64
76
  },
65
77
  },
@@ -117,6 +129,16 @@ export const WithAddress = {
117
129
  ),
118
130
  };
119
131
 
132
+ export const Worldwide = {
133
+ render: ({ apiKey, onAddressChange }: AutocompleteAddressProps) => (
134
+ <AutocompleteAddress
135
+ apiKey={apiKey}
136
+ countryCode={null}
137
+ onAddressChange={onAddressChange}
138
+ />
139
+ ),
140
+ };
141
+
120
142
  export const WithLocalisationEntryText = {
121
143
  render: ({ apiKey, onAddressChange }: AutocompleteAddressProps) => (
122
144
  <AutocompleteAddress
@@ -13,13 +13,15 @@ const address = {
13
13
 
14
14
  const setup = (
15
15
  address: Partial<Address> | undefined = undefined,
16
- onAddressChange: (address: Partial<Address>) => void = () => {}
16
+ onAddressChange: (address: Partial<Address>) => void = () => {},
17
+ countryCode?: string | null
17
18
  ) => {
18
19
  return render(
19
20
  <AutocompleteAddress
20
21
  address={address}
21
22
  apiKey={''}
22
23
  onAddressChange={onAddressChange}
24
+ countryCode={countryCode}
23
25
  />
24
26
  );
25
27
  };
@@ -90,6 +92,62 @@ describe('AutocompleteAddress component', () => {
90
92
  expect(callback).toHaveBeenCalledWith(address);
91
93
  });
92
94
 
95
+ it('Should not show a country field when restricted to a country', async () => {
96
+ const { findByText, queryByTestId, user } = setup();
97
+
98
+ await user.click(await findByText('enter address manually'));
99
+
100
+ expect(queryByTestId('autocomplete-country')).not.toBeInTheDocument();
101
+ });
102
+
103
+ it('Should let the user pick the country when searching worldwide', async () => {
104
+ const callback = jest.fn();
105
+ const { findByText, getByRole, getByTestId, user } = setup(
106
+ undefined,
107
+ callback,
108
+ null
109
+ );
110
+
111
+ await user.click(await findByText('enter address manually'));
112
+
113
+ await user.type(getByTestId('autocomplete'), 'Calle Mayor');
114
+ await user.type(getByTestId('autocomplete-house-number'), '1');
115
+ await user.type(getByTestId('autocomplete-postcode'), '28013');
116
+ await user.type(getByTestId('autocomplete-city'), 'Madrid');
117
+
118
+ expect(callback).toHaveBeenLastCalledWith(
119
+ expect.objectContaining({ country: undefined })
120
+ );
121
+
122
+ await user.click(getByRole('button', { name: 'Country' }));
123
+ await user.type(getByRole('textbox', { name: 'Search country' }), 'Spain');
124
+ await user.click(getByRole('radio', { name: 'Spain' }));
125
+
126
+ expect(callback).toHaveBeenLastCalledWith({
127
+ street: 'Calle Mayor',
128
+ houseNumber: '1',
129
+ postcode: '28013',
130
+ city: 'Madrid',
131
+ country: 'ES',
132
+ });
133
+ });
134
+
135
+ it('Should keep the country of a worldwide address when editing it', async () => {
136
+ const callback = jest.fn();
137
+ const { getByTestId, user } = setup(
138
+ { ...address, country: 'ES' },
139
+ callback,
140
+ null
141
+ );
142
+
143
+ await user.type(getByTestId('autocomplete-house-number'), '1');
144
+
145
+ expect(callback).toHaveBeenLastCalledWith(
146
+ expect.objectContaining({ houseNumber: '40001', country: 'ES' })
147
+ );
148
+ expect(getByTestId('autocomplete-country')).toHaveTextContent('Spain');
149
+ });
150
+
93
151
  it('Should prefill fields if an address is provided', async () => {
94
152
  const { getByDisplayValue } = setup(address);
95
153
 
@@ -1,11 +1,20 @@
1
- import { ChangeEvent, useCallback, useEffect, useRef, useState } from 'react';
1
+ import {
2
+ ChangeEvent,
3
+ useCallback,
4
+ useEffect,
5
+ useMemo,
6
+ useRef,
7
+ useState,
8
+ } from 'react';
2
9
  import classNames from 'classnames';
3
10
  import debounce from 'lodash.debounce';
4
11
  import { Input } from '../input';
12
+ import { SearchableDropdown } from '../searchableDropdown';
5
13
  import {
6
14
  Address,
7
15
  Alpha2CountryCode,
8
16
  countryNameFromAlphaCode,
17
+ getAllCountries,
9
18
  } from '@popsure/public-models';
10
19
 
11
20
  import { geocoderAddressComponentToPartialAddress } from './util';
@@ -76,12 +85,14 @@ export interface AutocompleteAddressProps {
76
85
  additionalInformation?: string;
77
86
  postcode?: string;
78
87
  city?: string;
88
+ country?: string;
89
+ countrySearch?: string;
79
90
  };
80
91
  manualAddressEntryTexts?: {
81
92
  preText?: string;
82
93
  cta?: string;
83
94
  };
84
- countryCode?: string;
95
+ countryCode?: string | null;
85
96
  }
86
97
 
87
98
  const AutocompleteAddress = ({
@@ -112,6 +123,16 @@ const AutocompleteAddress = ({
112
123
  null
113
124
  );
114
125
 
126
+ const isWorldwide = countryCode === null;
127
+
128
+ const countryOptions = useMemo(
129
+ () =>
130
+ isWorldwide
131
+ ? getAllCountries().map(({ code, name }) => ({ id: code, label: name }))
132
+ : [],
133
+ [isWorldwide]
134
+ );
135
+
115
136
  useEffect(() => {
116
137
  if (address) {
117
138
  if (autocompleteElement.current && address.street) {
@@ -133,7 +154,7 @@ const AutocompleteAddress = ({
133
154
 
134
155
  autocomplete.current = new google.maps.places.Autocomplete(reference, {
135
156
  types: ['address'],
136
- componentRestrictions: { country: countryCode },
157
+ ...(countryCode && { componentRestrictions: { country: countryCode } }),
137
158
  });
138
159
 
139
160
  autocomplete.current.addListener('place_changed', onPlaceChanged);
@@ -227,21 +248,27 @@ const AutocompleteAddress = ({
227
248
  setManualAddressEntry(true);
228
249
  };
229
250
 
251
+ const updateManualAddress = (
252
+ changes: Partial<Address>,
253
+ { updatePlace } = { updatePlace: true }
254
+ ) => {
255
+ const newAddress = {
256
+ ...address,
257
+ ...changes,
258
+ country: countryCode ?? changes.country ?? address?.country,
259
+ };
260
+ setAddress(newAddress);
261
+ onAddressChange(newAddress);
262
+
263
+ if (updatePlace) {
264
+ debouncedSetPlace(newAddress);
265
+ }
266
+ };
267
+
230
268
  const onManualAddressChange =
231
269
  ({ updatePlace } = { updatePlace: true }) =>
232
- (e: ChangeEvent<HTMLInputElement>) => {
233
- const newAddress = {
234
- ...address,
235
- [e.target.name]: e.target.value,
236
- country: countryCode,
237
- };
238
- setAddress(newAddress);
239
- onAddressChange(newAddress);
240
-
241
- if (updatePlace) {
242
- debouncedSetPlace(newAddress);
243
- }
244
- };
270
+ (e: ChangeEvent<HTMLInputElement>) =>
271
+ updateManualAddress({ [e.target.name]: e.target.value }, { updatePlace });
245
272
 
246
273
  return (
247
274
  <>
@@ -341,6 +368,21 @@ const AutocompleteAddress = ({
341
368
  {...inputProps?.city}
342
369
  />
343
370
  </div>
371
+ {isWorldwide && (
372
+ <div className="mt16" data-testid="autocomplete-country">
373
+ <SearchableDropdown
374
+ options={countryOptions}
375
+ value={address?.country ?? null}
376
+ onChange={(country) => updateManualAddress({ country })}
377
+ searchable
378
+ bordered
379
+ showChevron
380
+ groupName="autocomplete-country"
381
+ triggerPlaceholder={placeholders?.country || 'Country'}
382
+ placeholder={placeholders?.countrySearch || 'Search country'}
383
+ />
384
+ </div>
385
+ )}
344
386
  </>
345
387
  )}
346
388
  </div>
@@ -0,0 +1,22 @@
1
+ import { render, screen } from '../../../../../util/testUtils';
2
+ import { ButtonCell } from './ButtonCell';
3
+
4
+ describe('ButtonCell', () => {
5
+ it('exposes its test id on the button so clicking it selects the cell', async () => {
6
+ const onClick = jest.fn();
7
+ const { user } = render(
8
+ <ButtonCell
9
+ buttonCaption="Extended"
10
+ price="€9.34/mo"
11
+ onClick={onClick}
12
+ dataTestId="plan-table-EXTENDED"
13
+ />
14
+ );
15
+
16
+ const button = screen.getByTestId('plan-table-EXTENDED');
17
+ await user.click(button);
18
+
19
+ expect(button.tagName).toBe('BUTTON');
20
+ expect(onClick).toHaveBeenCalledTimes(1);
21
+ });
22
+ });
@@ -30,7 +30,6 @@ export const ButtonCell = ({
30
30
  styles.wrapper,
31
31
  className,
32
32
  )}
33
- data-testid={dataTestId}
34
33
  >
35
34
  <button
36
35
  className={classNames('w100 wmx5', styles.buttonCell, {
@@ -40,6 +39,7 @@ export const ButtonCell = ({
40
39
  type="button"
41
40
  onClick={onClick}
42
41
  disabled={disabled}
42
+ data-testid={dataTestId}
43
43
  >
44
44
  <div className="d-flex fd-column ai-start">
45
45
  <span className="p-p fw-bold">{buttonCaption}</span>