@popsure/dirty-swan 0.26.9 → 0.26.12

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 (241) hide show
  1. package/dist/index.css +63 -1
  2. package/dist/index.css.map +1 -1
  3. package/dist/lib/scss/private/base/_border_radius.scss +15 -0
  4. package/dist/lib/scss/private/base/_grid.scss +8 -0
  5. package/dist/lib/scss/private/base/_index.scss +1 -0
  6. package/dist/lib/scss/private/base/style.module.scss +10 -0
  7. package/dist/lib/scss/private/components/_buttons.scss +1 -1
  8. package/dist/lib/scss/public/colors/default.scss +2 -0
  9. package/dist/lib/scss/public/demo.tsx +13 -1
  10. package/package.json +2 -1
  11. package/src/App.tsx +50 -0
  12. package/src/bin/index.ts +71 -0
  13. package/src/bin/tsconfig.json +13 -0
  14. package/src/bin/util/index.test.ts +85 -0
  15. package/src/bin/util/index.ts +132 -0
  16. package/src/bin/util/test/data.json +13 -0
  17. package/src/colors.scss +1 -0
  18. package/src/font-weight.scss +1 -0
  19. package/src/grid.scss +1 -0
  20. package/src/index.tsx +37 -0
  21. package/src/intro.stories.mdx +41 -0
  22. package/src/lib/components/autocompleteAddress/demo.tsx +38 -0
  23. package/src/lib/components/autocompleteAddress/index.stories.mdx +44 -0
  24. package/src/lib/components/autocompleteAddress/index.tsx +316 -0
  25. package/src/lib/components/autocompleteAddress/mapStyle.ts +187 -0
  26. package/src/lib/components/autocompleteAddress/style.module.scss +82 -0
  27. package/src/lib/components/autocompleteAddress/util/index.test.ts +51 -0
  28. package/src/lib/components/autocompleteAddress/util/index.ts +55 -0
  29. package/src/lib/components/button/icons/index.ts +14 -0
  30. package/src/lib/components/button/icons/send-purple.svg +4 -0
  31. package/src/lib/components/button/icons/send-white.svg +4 -0
  32. package/src/lib/components/button/index.stories.mdx +121 -0
  33. package/src/lib/components/button/index.tsx +64 -0
  34. package/src/lib/components/button/styles.module.scss +5 -0
  35. package/src/lib/components/cards/a.stories.mdx +44 -0
  36. package/src/lib/components/cards/cardButton/index.stories.mdx +47 -0
  37. package/src/lib/components/cards/cardButton/index.tsx +61 -0
  38. package/src/lib/components/cards/cardButton/style.module.scss +33 -0
  39. package/src/lib/components/cards/cardWithLeftIcon/index.stories.mdx +103 -0
  40. package/src/lib/components/cards/cardWithLeftIcon/index.tsx +87 -0
  41. package/src/lib/components/cards/cardWithLeftIcon/style.module.scss +23 -0
  42. package/src/lib/components/cards/cardWithTopIcon/index.stories.mdx +105 -0
  43. package/src/lib/components/cards/cardWithTopIcon/index.tsx +60 -0
  44. package/src/lib/components/cards/cardWithTopIcon/style.module.scss +10 -0
  45. package/src/lib/components/cards/cardWithTopLeftIcon/index.stories.mdx +101 -0
  46. package/src/lib/components/cards/cardWithTopLeftIcon/index.tsx +72 -0
  47. package/src/lib/components/cards/cardWithTopLeftIcon/style.module.scss +21 -0
  48. package/src/lib/components/cards/icons/arrow-right.svg +4 -0
  49. package/src/lib/components/cards/icons/chevron-right.svg +3 -0
  50. package/src/lib/components/cards/icons/feather-logo.svg +10 -0
  51. package/src/lib/components/cards/icons/index.ts +36 -0
  52. package/src/lib/components/cards/icons/info.svg +12 -0
  53. package/src/lib/components/cards/index.test.ts +37 -0
  54. package/src/lib/components/cards/index.tsx +57 -0
  55. package/src/lib/components/cards/infoCard/index.stories.mdx +61 -0
  56. package/src/lib/components/cards/infoCard/index.tsx +47 -0
  57. package/src/lib/components/cards/infoCard/style.module.scss +53 -0
  58. package/src/lib/components/chip/icons/remove-button-highlighted.svg +4 -0
  59. package/src/lib/components/chip/icons/remove-button.svg +4 -0
  60. package/src/lib/components/chip/index.stories.mdx +101 -0
  61. package/src/lib/components/chip/index.tsx +38 -0
  62. package/src/lib/components/chip/style.module.scss +54 -0
  63. package/src/lib/components/comparisonTable/components/Chevron.tsx +19 -0
  64. package/src/lib/components/comparisonTable/components/Row/index.tsx +68 -0
  65. package/src/lib/components/comparisonTable/components/Row/style.module.scss +114 -0
  66. package/src/lib/components/comparisonTable/components/TableArrows/Arrow.tsx +19 -0
  67. package/src/lib/components/comparisonTable/components/TableArrows/index.tsx +52 -0
  68. package/src/lib/components/comparisonTable/components/TableArrows/style.module.scss +53 -0
  69. package/src/lib/components/comparisonTable/components/TableInfoButton/index.tsx +37 -0
  70. package/src/lib/components/comparisonTable/components/TableInfoButton/style.module.scss +30 -0
  71. package/src/lib/components/comparisonTable/components/TableRating/StarIcon.tsx +13 -0
  72. package/src/lib/components/comparisonTable/components/TableRating/ZapIcon.tsx +17 -0
  73. package/src/lib/components/comparisonTable/components/TableRating/index.tsx +45 -0
  74. package/src/lib/components/comparisonTable/components/TableRating/style.module.scss +13 -0
  75. package/src/lib/components/comparisonTable/components/TableRowHeader/index.tsx +35 -0
  76. package/src/lib/components/comparisonTable/components/TableRowHeader/style.module.scss +3 -0
  77. package/src/lib/components/comparisonTable/components/TableTrueFalse.tsx +40 -0
  78. package/src/lib/components/comparisonTable/hooks/useActiveTableArrows.ts +63 -0
  79. package/src/lib/components/comparisonTable/index.stories.mdx +254 -0
  80. package/src/lib/components/comparisonTable/index.tsx +211 -0
  81. package/src/lib/components/comparisonTable/style.module.scss +104 -0
  82. package/src/lib/components/dateSelector/datepicker.scss +406 -0
  83. package/src/lib/components/dateSelector/icons/calendar.svg +6 -0
  84. package/src/lib/components/dateSelector/icons/chevron-left.svg +3 -0
  85. package/src/lib/components/dateSelector/icons/chevron-right.svg +3 -0
  86. package/src/lib/components/dateSelector/index.stories.mdx +62 -0
  87. package/src/lib/components/dateSelector/index.test.ts +33 -0
  88. package/src/lib/components/dateSelector/index.tsx +247 -0
  89. package/src/lib/components/dateSelector/style.module.scss +77 -0
  90. package/src/lib/components/downloadButton/icons/check.svg +3 -0
  91. package/src/lib/components/downloadButton/icons/download.svg +5 -0
  92. package/src/lib/components/downloadButton/index.stories.mdx +59 -0
  93. package/src/lib/components/downloadButton/index.tsx +67 -0
  94. package/src/lib/components/downloadButton/style.module.scss +19 -0
  95. package/src/lib/components/downloadRing/icons/check-outside-circle.tsx +26 -0
  96. package/src/lib/components/downloadRing/icons/download-cloud.tsx +18 -0
  97. package/src/lib/components/downloadRing/icons/style.module.scss +7 -0
  98. package/src/lib/components/downloadRing/index.stories.mdx +35 -0
  99. package/src/lib/components/downloadRing/index.tsx +79 -0
  100. package/src/lib/components/downloadRing/style.module.scss +66 -0
  101. package/src/lib/components/dropzone/images/error.tsx +18 -0
  102. package/src/lib/components/dropzone/images/file.tsx +26 -0
  103. package/src/lib/components/dropzone/images/style.module.scss +7 -0
  104. package/src/lib/components/dropzone/images/upload-complete.tsx +24 -0
  105. package/src/lib/components/dropzone/images/upload.tsx +18 -0
  106. package/src/lib/components/dropzone/index.stories.mdx +44 -0
  107. package/src/lib/components/dropzone/index.tsx +152 -0
  108. package/src/lib/components/dropzone/style.module.scss +90 -0
  109. package/src/lib/components/input/a.stories.mdx +28 -0
  110. package/src/lib/components/input/autoSuggestInput/index.stories.mdx +137 -0
  111. package/src/lib/components/input/autoSuggestInput/index.tsx +81 -0
  112. package/src/lib/components/input/autoSuggestInput/style.module.scss +71 -0
  113. package/src/lib/components/input/autoSuggestMultiSelect/index.stories.mdx +115 -0
  114. package/src/lib/components/input/autoSuggestMultiSelect/index.tsx +75 -0
  115. package/src/lib/components/input/autoSuggestMultiSelect/style.module.scss +4 -0
  116. package/src/lib/components/input/currency/format/index.test.ts +49 -0
  117. package/src/lib/components/input/currency/format/index.ts +15 -0
  118. package/src/lib/components/input/currency/index.stories.mdx +25 -0
  119. package/src/lib/components/input/currency/index.test.tsx +56 -0
  120. package/src/lib/components/input/currency/index.tsx +53 -0
  121. package/src/lib/components/input/iban/formatIban/index.test.ts +11 -0
  122. package/src/lib/components/input/iban/formatIban/index.ts +22 -0
  123. package/src/lib/components/input/iban/index.stories.mdx +21 -0
  124. package/src/lib/components/input/iban/index.tsx +20 -0
  125. package/src/lib/components/input/index.stories.mdx +62 -0
  126. package/src/lib/components/input/index.tsx +51 -0
  127. package/src/lib/components/input/style.module.scss +94 -0
  128. package/src/lib/components/modal/bottomModal/img/close.svg +4 -0
  129. package/src/lib/components/modal/bottomModal/index.tsx +68 -0
  130. package/src/lib/components/modal/bottomModal/style.module.scss +104 -0
  131. package/src/lib/components/modal/bottomOrRegularModal/index.tsx +43 -0
  132. package/src/lib/components/modal/bottomOrRegularModal/style.module.scss +16 -0
  133. package/src/lib/components/modal/hooks/useOnClose.ts +51 -0
  134. package/src/lib/components/modal/index.stories.mdx +316 -0
  135. package/src/lib/components/modal/index.ts +14 -0
  136. package/src/lib/components/modal/regularModal/img/close.svg +4 -0
  137. package/src/lib/components/modal/regularModal/index.tsx +55 -0
  138. package/src/lib/components/modal/regularModal/style.module.scss +106 -0
  139. package/src/lib/components/multiDropzone/UploadFileCell/index.tsx +138 -0
  140. package/src/lib/components/multiDropzone/UploadFileCell/style.module.scss +101 -0
  141. package/src/lib/components/multiDropzone/icons/bmp-complete.svg +10 -0
  142. package/src/lib/components/multiDropzone/icons/bmp.svg +10 -0
  143. package/src/lib/components/multiDropzone/icons/doc-complete.svg +11 -0
  144. package/src/lib/components/multiDropzone/icons/doc.svg +11 -0
  145. package/src/lib/components/multiDropzone/icons/docx-complete.svg +12 -0
  146. package/src/lib/components/multiDropzone/icons/docx.svg +12 -0
  147. package/src/lib/components/multiDropzone/icons/eye.svg +4 -0
  148. package/src/lib/components/multiDropzone/icons/generic-complete.svg +4 -0
  149. package/src/lib/components/multiDropzone/icons/generic-error.svg +7 -0
  150. package/src/lib/components/multiDropzone/icons/generic.svg +4 -0
  151. package/src/lib/components/multiDropzone/icons/heic-complete.svg +11 -0
  152. package/src/lib/components/multiDropzone/icons/heic.svg +11 -0
  153. package/src/lib/components/multiDropzone/icons/index.ts +51 -0
  154. package/src/lib/components/multiDropzone/icons/jpeg-complete.svg +11 -0
  155. package/src/lib/components/multiDropzone/icons/jpeg.svg +11 -0
  156. package/src/lib/components/multiDropzone/icons/jpg-complete.svg +10 -0
  157. package/src/lib/components/multiDropzone/icons/jpg.svg +10 -0
  158. package/src/lib/components/multiDropzone/icons/pdf-complete.svg +8 -0
  159. package/src/lib/components/multiDropzone/icons/pdf.svg +8 -0
  160. package/src/lib/components/multiDropzone/icons/png-complete.svg +10 -0
  161. package/src/lib/components/multiDropzone/icons/png.svg +10 -0
  162. package/src/lib/components/multiDropzone/icons/trash.svg +6 -0
  163. package/src/lib/components/multiDropzone/icons/upload.svg +5 -0
  164. package/src/lib/components/multiDropzone/index.stories.mdx +91 -0
  165. package/src/lib/components/multiDropzone/index.tsx +99 -0
  166. package/src/lib/components/multiDropzone/style.module.scss +32 -0
  167. package/src/lib/components/segmentedControl/index.stories.mdx +47 -0
  168. package/src/lib/components/segmentedControl/index.tsx +105 -0
  169. package/src/lib/components/segmentedControl/style.module.scss +36 -0
  170. package/src/lib/components/signaturePad/img/reset.svg +4 -0
  171. package/src/lib/components/signaturePad/img/sign.svg +3 -0
  172. package/src/lib/components/signaturePad/index.stories.mdx +17 -0
  173. package/src/lib/components/signaturePad/index.tsx +96 -0
  174. package/src/lib/components/signaturePad/style.module.scss +90 -0
  175. package/src/lib/index.tsx +71 -0
  176. package/src/lib/models/autoSuggestInput/index.ts +4 -0
  177. package/src/lib/models/download.ts +1 -0
  178. package/src/lib/models/downloadRing/index.ts +6 -0
  179. package/src/lib/scss/index.scss +22 -0
  180. package/src/lib/scss/private/_reset.scss +149 -0
  181. package/src/lib/scss/private/base/_border_radius.scss +15 -0
  182. package/src/lib/scss/private/base/_colors.scss +19 -0
  183. package/src/lib/scss/private/base/_cursors.scss +31 -0
  184. package/src/lib/scss/private/base/_display.scss +35 -0
  185. package/src/lib/scss/private/base/_grid.scss +60 -0
  186. package/src/lib/scss/private/base/_index.scss +10 -0
  187. package/src/lib/scss/private/base/_shadows.scss +2 -0
  188. package/src/lib/scss/private/base/_spacing.scss +89 -0
  189. package/src/lib/scss/private/base/_typography.scss +128 -0
  190. package/src/lib/scss/private/base/_width_and_height.scss +25 -0
  191. package/src/lib/scss/private/base/border_radius.stories.mdx +43 -0
  192. package/src/lib/scss/private/base/cursors.stories.mdx +18 -0
  193. package/src/lib/scss/private/base/demo.tsx +119 -0
  194. package/src/lib/scss/private/base/display.stories.mdx +19 -0
  195. package/src/lib/scss/private/base/flex/_flex.scss +63 -0
  196. package/src/lib/scss/private/base/flex/flex.stories.mdx +139 -0
  197. package/src/lib/scss/private/base/flex/style.module.scss +24 -0
  198. package/src/lib/scss/private/base/spacing.stories.mdx +185 -0
  199. package/src/lib/scss/private/base/style.module.scss +52 -0
  200. package/src/lib/scss/private/base/typography.stories.mdx +71 -0
  201. package/src/lib/scss/private/base/width_and_height.stories.mdx +172 -0
  202. package/src/lib/scss/private/components/_badge.scss +41 -0
  203. package/src/lib/scss/private/components/_buttons.scss +193 -0
  204. package/src/lib/scss/private/components/_cards.scss +32 -0
  205. package/src/lib/scss/private/components/_index.scss +6 -0
  206. package/src/lib/scss/private/components/_input.scss +241 -0
  207. package/src/lib/scss/private/components/_notices.scss +39 -0
  208. package/src/lib/scss/private/components/_spinner.scss +60 -0
  209. package/src/lib/scss/private/components/assets/checkmark.svg +3 -0
  210. package/src/lib/scss/private/components/assets/icon-form-dropdown.svg +3 -0
  211. package/src/lib/scss/private/components/badge.stories.mdx +37 -0
  212. package/src/lib/scss/private/components/button.stories.mdx +107 -0
  213. package/src/lib/scss/private/components/cards.stories.mdx +35 -0
  214. package/src/lib/scss/private/components/checkbox.stories.mdx +47 -0
  215. package/src/lib/scss/private/components/input.stories.mdx +33 -0
  216. package/src/lib/scss/private/components/notices.stories.mdx +37 -0
  217. package/src/lib/scss/private/components/radio.stories.mdx +47 -0
  218. package/src/lib/scss/private/components/select.stories.mdx +17 -0
  219. package/src/lib/scss/private/components/spinner.stories.mdx +25 -0
  220. package/src/lib/scss/public/colors/_index.scss +2 -0
  221. package/src/lib/scss/public/colors/default.scss +127 -0
  222. package/src/lib/scss/public/colors/overrides.scss +0 -0
  223. package/src/lib/scss/public/colors.stories.mdx +27 -0
  224. package/src/lib/scss/public/demo.tsx +297 -0
  225. package/src/lib/scss/public/font/_index.scss +2 -0
  226. package/src/lib/scss/public/font/default.scss +3 -0
  227. package/src/lib/scss/public/font/overrides.scss +0 -0
  228. package/src/lib/scss/public/font-weight.scss +9 -0
  229. package/src/lib/scss/public/font-weight.stories.mdx +32 -0
  230. package/src/lib/scss/public/grid.scss +21 -0
  231. package/src/lib/scss/public/grid.stories.mdx +41 -0
  232. package/src/lib/scss/third-party/_google_places.scss +62 -0
  233. package/src/lib/scss/third-party/_index.scss +1 -0
  234. package/src/lib/scss/utils/_index.scss +3 -0
  235. package/src/lib/util/calendarDate/index.test.ts +32 -0
  236. package/src/lib/util/calendarDate/index.ts +30 -0
  237. package/src/lib/util/zeroFill.test.ts +15 -0
  238. package/src/lib/util/zeroFill.ts +7 -0
  239. package/src/react-app-env.d.ts +1 -0
  240. package/src/setupTests.js +8 -0
  241. package/src/theme.stories.mdx +54 -0
package/src/index.tsx ADDED
@@ -0,0 +1,37 @@
1
+ import ReactDOM from 'react-dom';
2
+ import App from './App';
3
+
4
+ export {
5
+ DateSelector,
6
+ Dropzone,
7
+ SignaturePad,
8
+ AutocompleteAddress,
9
+ Input,
10
+ MultiDropzone,
11
+ DownloadRing,
12
+ IbanInput,
13
+ CurrencyInput,
14
+ BottomModal,
15
+ RegularModal,
16
+ BottomOrRegularModal,
17
+ CardWithTopLeftIcon,
18
+ CardWithLeftIcon,
19
+ CardWithTopIcon,
20
+ InfoCard,
21
+ CardButton,
22
+ Button,
23
+ AutoSuggestMultiSelect,
24
+ Chip,
25
+ AutoSuggestInput,
26
+ ComparisonTable,
27
+ TableRating,
28
+ TableTrueFalse,
29
+ TableRowHeader,
30
+ TableInfoButton,
31
+ SegmentedControl,
32
+ DownloadButton
33
+ } from './lib';
34
+
35
+ export type { TableHeader, DownloadRingDownloadStatus, DownloadStatus } from './lib';
36
+
37
+ ReactDOM.render(<App />, document.getElementById('root'));
@@ -0,0 +1,41 @@
1
+ # Dirty Swan
2
+
3
+ <Meta title="Intro" />
4
+
5
+ Dirty Swan is the Design System build and maintained at [Feather](https://feather-insurance.com/).
6
+
7
+ ## Installation
8
+
9
+ Run the following command using [npm](https://www.npmjs.com):
10
+
11
+ ```bash
12
+ npm install @popsure/dirty-swan --save
13
+ ```
14
+
15
+ If you prefer [Yarn](https://www.npmjs.com), use the following command instead:
16
+
17
+ ```bash
18
+ yarn add @popsure/dirty-swan
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ To use Dirty Swan, import the scss file in one of your App entry point (typically `index/js` or `App.js` if you’re using [create react app](https://create-react-app.dev))
24
+
25
+ ```javaScript
26
+ import '@popsure/dirty-swan/dist/index.css';
27
+ ```
28
+
29
+ ## Design values
30
+
31
+ ### Simple Swan
32
+
33
+ We are a company that believes in the simplicity of things. We don't want to over complicate something that is already a thousand headed hydra at the best of times. We believe that problems can be solved elegantly but most importantly, simply.
34
+
35
+ We aren't ones to break the wheel, if it works we'll make full use of it. That's why we believe in a design system that is usable and reusable, designing with simplicity and durability in mind.
36
+
37
+ ### Lego Swan
38
+
39
+ Our design system, like many before it, uses the fundamental methodology of Atomic Design. Building from what is as a foundation and continuously improving from what was.
40
+
41
+ We believe in building a solid foundation in order to continue solidly from where we began. Future proofing is one of our fundamental values and beliefs. Everything that we design and implement is done with future features in mind.
@@ -0,0 +1,38 @@
1
+ import React, { useState } from 'react';
2
+ import { Address } from '@popsure/public-models';
3
+
4
+ import AutoCompleteAddress from '.';
5
+
6
+ export const WithoutAddress = () => {
7
+ const [address, setAddress] = useState<Partial<Address> | undefined>(
8
+ undefined
9
+ );
10
+ return (
11
+ <AutoCompleteAddress
12
+ onAddressChange={(address) => {
13
+ setAddress(address);
14
+ }}
15
+ address={address}
16
+ apiKey="AIzaSyDg0DSrjYKt5smmsjkVasDz7c4T5rbOXT8"
17
+ />
18
+ );
19
+ };
20
+
21
+ export const WithAddress = () => {
22
+ const [address, setAddress] = useState<Partial<Address> | undefined>({
23
+ street: 'Lohmuehlenstraße',
24
+ houseNumber: '65',
25
+ city: 'Berlin',
26
+ country: 'DE',
27
+ additionalInformation: 'c/o Factory',
28
+ });
29
+ return (
30
+ <AutoCompleteAddress
31
+ onAddressChange={(address) => {
32
+ setAddress(address);
33
+ }}
34
+ address={address}
35
+ apiKey="AIzaSyDg0DSrjYKt5smmsjkVasDz7c4T5rbOXT8"
36
+ />
37
+ );
38
+ };
@@ -0,0 +1,44 @@
1
+ import { useState } from 'react';
2
+
3
+ import { Meta, Preview } from '@storybook/addon-docs/blocks';
4
+
5
+ import AutocompleteAddress from '.';
6
+ import { WithoutAddress, WithAddress } from './demo';
7
+
8
+ <Meta title="JSX/Autocomplete Address" component={AutocompleteAddress} />
9
+
10
+ # Autocomplete Address
11
+
12
+ | attribute | unit | description | default value | required |
13
+ | --------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ------------- | -------- |
14
+ | address | `Partial<Address>` | The address | undefined | false |
15
+ | onAddressChange | `function (newAddress: Partial<Address>)` | Callback with the updated address, this function will get called everytime the address gets updated. | n/a | true |
16
+ | apiKey | string | Your private API key for the [Google Places API](https://developers.google.com/maps/documentation/places/web-service/overview) | n/a | true |
17
+
18
+ Autocomplete Address are user interface elements which allow users start typing an address and get autocompletion suggestions on the address.
19
+
20
+ ## Important notes
21
+
22
+ This component is for now only restricted to "address" types and will restrict every query to Germany.
23
+
24
+ ## Default example
25
+
26
+ ### Input without an address filled
27
+
28
+ <WithoutAddress />
29
+
30
+ ### Input with an address filled
31
+
32
+ <WithAddress />
33
+
34
+ ```typescript
35
+ import React, { useState } from 'react';
36
+ import { Address } from '@popsure/public-models';
37
+
38
+ import AutoCompleteAddress from '.';
39
+
40
+ export default () => {
41
+ const [address, setAddress] = useState<Address>(undefined);
42
+ return <AutoCompleteAddress onAddressChange={setAddress} address={address} />;
43
+ };
44
+ ```
@@ -0,0 +1,316 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+ import classNames from 'classnames';
3
+ import debounce from 'lodash.debounce';
4
+ import isEqual from 'lodash.isequal';
5
+ import Input from '../input';
6
+ import { Address, countryNameFromAlphaCode } from '@popsure/public-models';
7
+
8
+ import { geocoderAddressComponentToPartialAddress } from './util';
9
+
10
+ import styles from './style.module.scss';
11
+
12
+ const GERMANY_LAT_LNG = { lat: 51.54317, lng: 10.3181503 };
13
+
14
+ const GERMANY_ALPHA_CODE = 'DE';
15
+
16
+ const MAP_CONFIG_OBJ = {
17
+ zoom: 6,
18
+ center: GERMANY_LAT_LNG,
19
+ fullscreenControl: false,
20
+ mapTypeControl: false,
21
+ panControl: false,
22
+ zoomControl: false,
23
+ streetViewControl: false,
24
+ scrollwheel: false,
25
+ scaleControl: false,
26
+ rotateControl: false,
27
+ draggable: false,
28
+ };
29
+
30
+ const loadGoogleMapsApiDynamically = (callback: () => void, apiKey: string) => {
31
+ const existingScript = document.getElementById('googleMapsImportScript');
32
+
33
+ if (existingScript) {
34
+ return;
35
+ }
36
+
37
+ const googleMapImportScript = document.createElement('script');
38
+ googleMapImportScript.id = 'googleMapsImportScript';
39
+ googleMapImportScript.type = 'text/javascript';
40
+ googleMapImportScript.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=places`;
41
+ document.head.appendChild(googleMapImportScript);
42
+
43
+ googleMapImportScript.onload = () => {
44
+ callback();
45
+ };
46
+ };
47
+
48
+ const AutoCompleteAddress = ({
49
+ apiKey,
50
+ address: initialAddress,
51
+ onAddressChange,
52
+ }: {
53
+ apiKey: string;
54
+ address?: Partial<Address>;
55
+ onAddressChange: (address: Partial<Address>) => void;
56
+ }) => {
57
+ const [manualAddressEntry, setManualAddressEntry] = useState(false);
58
+ const [isLoading, setIsLoading] = useState(false);
59
+ const autocomplete = useRef<google.maps.places.Autocomplete | null>(null);
60
+ const autocompleteElement = useRef<HTMLInputElement | null>(null);
61
+ const map = useRef<google.maps.Map | null>(null);
62
+ const marker = useRef<google.maps.Marker | null>(null);
63
+ const [address, setAddress] = useState(initialAddress);
64
+ const [hasLoadedGoogleAPI, setHasLoadedGoogleAPI] = useState(
65
+ window.google !== undefined
66
+ );
67
+
68
+ loadGoogleMapsApiDynamically(() => {
69
+ setHasLoadedGoogleAPI(true);
70
+ }, apiKey);
71
+
72
+ const [place, setPlace] = useState<google.maps.places.PlaceResult | null>(
73
+ null
74
+ );
75
+
76
+ useEffect(() => {
77
+ if (address) {
78
+ if (autocompleteElement.current && address.street) {
79
+ autocompleteElement.current.value = address.street;
80
+ }
81
+
82
+ if (isEqual(address, initialAddress) === false) {
83
+ onAddressChange({ ...address });
84
+ }
85
+ handleEnterAddressManually();
86
+ }
87
+ }, [initialAddress, address, onAddressChange, hasLoadedGoogleAPI]);
88
+
89
+ useEffect(() => {
90
+ if (hasLoadedGoogleAPI === false) {
91
+ return;
92
+ }
93
+
94
+ const reference = document.getElementById(
95
+ 'autocomplete'
96
+ ) as HTMLInputElement;
97
+
98
+ autocomplete.current = new google.maps.places.Autocomplete(reference, {
99
+ types: ['address'],
100
+ componentRestrictions: { country: GERMANY_ALPHA_CODE },
101
+ });
102
+
103
+ autocomplete.current.addListener('place_changed', onPlaceChanged);
104
+
105
+ map.current = new google.maps.Map(
106
+ document.getElementById('map')!,
107
+ MAP_CONFIG_OBJ
108
+ );
109
+
110
+ import('./mapStyle').then(({ style }) => {
111
+ map.current?.mapTypes.set('styled_map', style);
112
+ map.current?.setMapTypeId('styled_map');
113
+ });
114
+
115
+ marker.current = new google.maps.Marker({
116
+ map: map.current,
117
+ });
118
+
119
+ setPlaceFromAddress(address);
120
+ }, [hasLoadedGoogleAPI]); // eslint-disable-line
121
+
122
+ const onPlaceChanged = (
123
+ newPlace:
124
+ | google.maps.places.PlaceResult
125
+ | undefined = autocomplete.current?.getPlace(),
126
+ updateAddress: boolean = true
127
+ ) => {
128
+ if (newPlace?.geometry?.location) {
129
+ const geocoderAddress = geocoderAddressComponentToPartialAddress(
130
+ newPlace.address_components!
131
+ );
132
+
133
+ setPlace(newPlace);
134
+ if (updateAddress) {
135
+ setAddress((oldValue) => ({
136
+ ...geocoderAddress,
137
+ additionalInformation: oldValue?.additionalInformation,
138
+ }));
139
+ }
140
+
141
+ map.current?.panTo(newPlace.geometry.location);
142
+ map.current?.setZoom(15);
143
+
144
+ marker.current?.setPosition(newPlace.geometry.location);
145
+ }
146
+ };
147
+
148
+ const setPlaceFromAddress = useCallback((address: Partial<Address> | undefined) => {
149
+ if (!map.current) {
150
+ return;
151
+ }
152
+
153
+ if (address) {
154
+ const service = new google.maps.places.PlacesService(map.current);
155
+ const query = `${address.street ?? ''} ${address.houseNumber ?? ''}, ${
156
+ address.city ?? ''
157
+ }, ${address.country ? countryNameFromAlphaCode(address.country) : ''}`;
158
+ setIsLoading(true);
159
+ service.findPlaceFromQuery(
160
+ {
161
+ fields: ['place_id'],
162
+ query,
163
+ },
164
+ (results) => {
165
+ const firstResult = results && results[0];
166
+ if (firstResult && firstResult.place_id) {
167
+ service.getDetails(
168
+ { placeId: firstResult.place_id },
169
+ (newPlace) => {
170
+ onPlaceChanged(newPlace ?? undefined, false);
171
+ }
172
+ );
173
+ }
174
+ setIsLoading(false);
175
+ }
176
+ );
177
+ }
178
+ }, []);
179
+
180
+ const debouncedSetPlace = debounce(setPlaceFromAddress, 1000)
181
+
182
+ const handleEnterAddressManually = () => {
183
+ setManualAddressEntry(true);
184
+ };
185
+
186
+ return (
187
+ <>
188
+ <div
189
+ className={classNames(`wmx8 bg-grey-500 ${styles['map-container']}`, {
190
+ [styles['map-container--hidden']]: place === null,
191
+ })}
192
+ >
193
+ <div className={styles.map} id="map" />
194
+ {isLoading && (
195
+ <div className={styles['loading-spinner']}>
196
+ <div className="ds-spinner ds-spinner__m" />
197
+ </div>
198
+ )}
199
+ </div>
200
+ <div className={`wmx8`}>
201
+ {manualAddressEntry === false ? (
202
+ <div style={{ position: 'relative' }}>
203
+ <Input
204
+ className="w100"
205
+ id="autocomplete"
206
+ data-cy="autocomplete"
207
+ type="text"
208
+ placeholder="Search for address"
209
+ ref={autocompleteElement}
210
+ />
211
+ {hasLoadedGoogleAPI === false && (
212
+ <div className={styles['loading-spinner']}>
213
+ <div className="ds-spinner ds-spinner__m" />
214
+ </div>
215
+ )}
216
+ </div>
217
+ ) : (
218
+ <>
219
+ <div className={`d-flex ${styles['input-line']}`}>
220
+ <Input
221
+ className="w100"
222
+ data-cy="autocomplete"
223
+ type="text"
224
+ placeholder="Street"
225
+ value={address?.street || ''}
226
+ onChange={(e) => {
227
+ const newAddress = {
228
+ ...address,
229
+ street: e.target.value,
230
+ country: GERMANY_ALPHA_CODE,
231
+ };
232
+ setAddress(newAddress);
233
+ debouncedSetPlace(newAddress);
234
+ }}
235
+ />
236
+ <Input
237
+ className={`wmx2 ${styles['house-number-input']}`}
238
+ data-cy="autocomplete-house-number"
239
+ placeholder="House Number"
240
+ value={address?.houseNumber || ''}
241
+ onChange={(e) => {
242
+ const newAddress = {
243
+ ...address,
244
+ houseNumber: e.target.value,
245
+ country: GERMANY_ALPHA_CODE,
246
+ };
247
+ setAddress(newAddress);
248
+ debouncedSetPlace(newAddress);
249
+ }}
250
+ />
251
+ </div>
252
+ <Input
253
+ className="mt16"
254
+ data-cy="autocomplete-additional-info"
255
+ placeholder="Additional information (C/O, appartment…)"
256
+ value={address?.additionalInformation || ''}
257
+ onChange={(e) => {
258
+ const newAddress = {
259
+ ...address,
260
+ additionalInformation: e.target.value,
261
+ country: GERMANY_ALPHA_CODE,
262
+ };
263
+ setAddress(newAddress);
264
+ }}
265
+ />
266
+ <div className={`d-flex mt16 ${styles['input-line']}`}>
267
+ <Input
268
+ className="w100"
269
+ data-cy="autocomplete-postcode"
270
+ placeholder="Postcode"
271
+ value={address?.postcode || ''}
272
+ onChange={(e) => {
273
+ const newAddress = {
274
+ ...address,
275
+ postcode: e.target.value,
276
+ country: GERMANY_ALPHA_CODE,
277
+ };
278
+ setAddress(newAddress);
279
+ debouncedSetPlace(newAddress);
280
+ }}
281
+ />
282
+ <Input
283
+ className="w100"
284
+ data-cy="autocomplete-city"
285
+ placeholder="City"
286
+ value={address?.city || ''}
287
+ onChange={(e) => {
288
+ const newAddress = {
289
+ ...address,
290
+ city: e.target.value,
291
+ country: GERMANY_ALPHA_CODE,
292
+ };
293
+ setAddress(newAddress);
294
+ debouncedSetPlace(newAddress);
295
+ }}
296
+ />
297
+ </div>
298
+ </>
299
+ )}
300
+ </div>
301
+ {manualAddressEntry === false && (
302
+ <div className="p-p mt8">
303
+ Or{' '}
304
+ <span
305
+ className="p-a fw-bold c-pointer"
306
+ onClick={handleEnterAddressManually}
307
+ >
308
+ Enter address manually
309
+ </span>
310
+ </div>
311
+ )}
312
+ </>
313
+ );
314
+ };
315
+
316
+ export default AutoCompleteAddress;
@@ -0,0 +1,187 @@
1
+ export const style = new google.maps.StyledMapType(
2
+ [
3
+ {
4
+ elementType: 'geometry',
5
+ stylers: [
6
+ {
7
+ color: '#f5f5f5',
8
+ },
9
+ ],
10
+ },
11
+ {
12
+ elementType: 'labels',
13
+ stylers: [
14
+ {
15
+ visibility: 'off',
16
+ },
17
+ ],
18
+ },
19
+ {
20
+ elementType: 'labels.icon',
21
+ stylers: [
22
+ {
23
+ visibility: 'off',
24
+ },
25
+ ],
26
+ },
27
+ {
28
+ elementType: 'labels.text.fill',
29
+ stylers: [
30
+ {
31
+ color: '#616161',
32
+ },
33
+ ],
34
+ },
35
+ {
36
+ elementType: 'labels.text.stroke',
37
+ stylers: [
38
+ {
39
+ color: '#f5f5f5',
40
+ },
41
+ ],
42
+ },
43
+ {
44
+ featureType: 'administrative.land_parcel',
45
+ stylers: [
46
+ {
47
+ visibility: 'off',
48
+ },
49
+ ],
50
+ },
51
+ {
52
+ featureType: 'administrative.land_parcel',
53
+ elementType: 'labels.text.fill',
54
+ stylers: [
55
+ {
56
+ color: '#bdbdbd',
57
+ },
58
+ ],
59
+ },
60
+ {
61
+ featureType: 'administrative.neighborhood',
62
+ stylers: [
63
+ {
64
+ visibility: 'off',
65
+ },
66
+ ],
67
+ },
68
+ {
69
+ featureType: 'poi',
70
+ elementType: 'geometry',
71
+ stylers: [
72
+ {
73
+ color: '#eeeeee',
74
+ },
75
+ ],
76
+ },
77
+ {
78
+ featureType: 'poi',
79
+ elementType: 'labels.text.fill',
80
+ stylers: [
81
+ {
82
+ color: '#757575',
83
+ },
84
+ ],
85
+ },
86
+ {
87
+ featureType: 'poi.park',
88
+ elementType: 'geometry',
89
+ stylers: [
90
+ {
91
+ color: '#e5e5e5',
92
+ },
93
+ ],
94
+ },
95
+ {
96
+ featureType: 'poi.park',
97
+ elementType: 'labels.text.fill',
98
+ stylers: [
99
+ {
100
+ color: '#9e9e9e',
101
+ },
102
+ ],
103
+ },
104
+ {
105
+ featureType: 'road',
106
+ elementType: 'geometry',
107
+ stylers: [
108
+ {
109
+ color: '#ffffff',
110
+ },
111
+ ],
112
+ },
113
+ {
114
+ featureType: 'road.arterial',
115
+ elementType: 'labels.text.fill',
116
+ stylers: [
117
+ {
118
+ color: '#757575',
119
+ },
120
+ ],
121
+ },
122
+ {
123
+ featureType: 'road.highway',
124
+ elementType: 'geometry',
125
+ stylers: [
126
+ {
127
+ color: '#dadada',
128
+ },
129
+ ],
130
+ },
131
+ {
132
+ featureType: 'road.highway',
133
+ elementType: 'labels.text.fill',
134
+ stylers: [
135
+ {
136
+ color: '#616161',
137
+ },
138
+ ],
139
+ },
140
+ {
141
+ featureType: 'road.local',
142
+ elementType: 'labels.text.fill',
143
+ stylers: [
144
+ {
145
+ color: '#9e9e9e',
146
+ },
147
+ ],
148
+ },
149
+ {
150
+ featureType: 'transit.line',
151
+ elementType: 'geometry',
152
+ stylers: [
153
+ {
154
+ color: '#e5e5e5',
155
+ },
156
+ ],
157
+ },
158
+ {
159
+ featureType: 'transit.station',
160
+ elementType: 'geometry',
161
+ stylers: [
162
+ {
163
+ color: '#eeeeee',
164
+ },
165
+ ],
166
+ },
167
+ {
168
+ featureType: 'water',
169
+ elementType: 'geometry',
170
+ stylers: [
171
+ {
172
+ color: '#c9c9c9',
173
+ },
174
+ ],
175
+ },
176
+ {
177
+ featureType: 'water',
178
+ elementType: 'labels.text.fill',
179
+ stylers: [
180
+ {
181
+ color: '#9e9e9e',
182
+ },
183
+ ],
184
+ },
185
+ ],
186
+ { name: 'Styled Map' }
187
+ );