@hashicorp/react-components 1.1.10 → 1.2.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 (173) hide show
  1. package/README.md +1 -1
  2. package/package.json +8 -13
  3. package/postcss.config.js +1 -1
  4. package/src/components/nav-panel/components/flight-icon/index.tsx +53 -0
  5. package/src/components/nav-panel/components/flight-icon/style.module.css +3 -0
  6. package/src/components/nav-panel/components/link/cloud-fill.svg +3 -0
  7. package/src/components/nav-panel/components/link/index.tsx +139 -0
  8. package/src/components/nav-panel/components/link/layers-fill.svg +5 -0
  9. package/src/components/nav-panel/components/link/shield-alert-fill.svg +3 -0
  10. package/src/components/nav-panel/components/link/style.module.css +64 -0
  11. package/src/components/nav-panel/components/link/zap-fill.svg +3 -0
  12. package/src/components/nav-panel/components/link-list/index.tsx +12 -64
  13. package/src/components/nav-panel/components/link-list/style.module.css +1 -50
  14. package/src/components/nav-panel/components/panel/column/style.module.css +2 -2
  15. package/src/components/nav-panel/components/panel/root/style.module.css +5 -5
  16. package/src/components/nav-panel/components/promo/index.tsx +35 -15
  17. package/src/components/nav-panel/components/promo/style.module.css +32 -28
  18. package/src/components/nav-panel/components/text/index.tsx +34 -0
  19. package/src/components/nav-panel/product-panel/index.tsx +71 -20
  20. package/src/components/nav-panel/product-panel/style.module.css +111 -53
  21. package/src/components/nav-panel/standard-panel/index.tsx +3 -0
  22. package/src/components/nav-panel/standard-panel/style.module.css +2 -2
  23. package/src/lib/get-localized-link-props/index.test.ts +30 -0
  24. package/src/lib/get-localized-link-props/index.ts +45 -0
  25. package/src/lib/parse-url/index.test.ts +57 -2
  26. package/src/lib/parse-url/index.ts +97 -13
  27. package/src/lib/send-posthog-event/index.ts +22 -0
  28. package/src/lib/supported-locales/index.ts +10 -0
  29. package/src/lib/track-nav-click-event/index.ts +5 -5
  30. package/src/lib/v/index.ts +9 -4
  31. package/tsconfig.json +1 -2
  32. package/.eslintrc.js +0 -4
  33. package/.stylelintrc.js +0 -3
  34. package/src/components/actions/index.tsx +0 -107
  35. package/src/components/actions/style.module.css +0 -28
  36. package/src/components/actions/types.ts +0 -73
  37. package/src/components/call-to-action/index.tsx +0 -205
  38. package/src/components/call-to-action/styles/variant-centered.module.css +0 -93
  39. package/src/components/call-to-action/styles/variant-compact-grid.module.css +0 -88
  40. package/src/components/call-to-action/styles/variant-compact.module.css +0 -91
  41. package/src/components/call-to-action/styles/variant-links.module.css +0 -85
  42. package/src/components/card/README.md +0 -11
  43. package/src/components/card/card.tsx +0 -45
  44. package/src/components/card/index.test.tsx +0 -69
  45. package/src/components/card/index.tsx +0 -14
  46. package/src/components/card/newsroom-card/index.test.tsx +0 -39
  47. package/src/components/card/newsroom-card/index.tsx +0 -37
  48. package/src/components/card/newsroom-card/style.module.css +0 -12
  49. package/src/components/card/partner-card/index.test.tsx +0 -57
  50. package/src/components/card/partner-card/index.tsx +0 -69
  51. package/src/components/card/partner-card/style.module.css +0 -24
  52. package/src/components/card/person-card/index.test.tsx +0 -71
  53. package/src/components/card/person-card/index.tsx +0 -93
  54. package/src/components/card/person-card/style.module.css +0 -33
  55. package/src/components/card/primitives.tsx +0 -176
  56. package/src/components/card/promo-card/index.tsx +0 -51
  57. package/src/components/card/resource-card/index.test.tsx +0 -48
  58. package/src/components/card/resource-card/index.tsx +0 -37
  59. package/src/components/card/style.module.css +0 -145
  60. package/src/components/card/types.ts +0 -66
  61. package/src/components/card/unified-card/index.tsx +0 -64
  62. package/src/components/consent-manager/README.md +0 -73
  63. package/src/components/consent-manager/components/banner/banner.module.css +0 -23
  64. package/src/components/consent-manager/components/banner/banner.test.tsx +0 -31
  65. package/src/components/consent-manager/components/banner/banner.tsx +0 -73
  66. package/src/components/consent-manager/components/dialog/dialog.module.css +0 -145
  67. package/src/components/consent-manager/components/dialog/dialog.test.tsx +0 -194
  68. package/src/components/consent-manager/components/dialog/dialog.tsx +0 -339
  69. package/src/components/consent-manager/img/icn_close.tsx +0 -19
  70. package/src/components/consent-manager/index.test.tsx +0 -334
  71. package/src/components/consent-manager/index.tsx +0 -186
  72. package/src/components/consent-manager/loader/README.md +0 -29
  73. package/src/components/consent-manager/loader/categories.ts +0 -22
  74. package/src/components/consent-manager/loader/index.tsx +0 -94
  75. package/src/components/consent-manager/loader/presets/enterprise.ts +0 -12
  76. package/src/components/consent-manager/loader/presets/oss.ts +0 -10
  77. package/src/components/consent-manager/loader/services.ts +0 -45
  78. package/src/components/consent-manager/scripts/custom.tsx +0 -59
  79. package/src/components/consent-manager/scripts/segment.tsx +0 -87
  80. package/src/components/consent-manager/style.module.css +0 -9
  81. package/src/components/consent-manager/types.ts +0 -55
  82. package/src/components/consent-manager/util/cookies.test.ts +0 -75
  83. package/src/components/consent-manager/util/cookies.ts +0 -70
  84. package/src/components/consent-manager/util/integrations.test.ts +0 -115
  85. package/src/components/consent-manager/util/integrations.ts +0 -110
  86. package/src/components/intro/index.tsx +0 -82
  87. package/src/components/intro/style.module.css +0 -67
  88. package/src/components/intro/types.ts +0 -44
  89. package/src/components/marketo-form/CHANGELOG.md +0 -122
  90. package/src/components/marketo-form/README.md +0 -1
  91. package/src/components/marketo-form/contexts/FormMetadata.ts +0 -11
  92. package/src/components/marketo-form/docs.mdx +0 -197
  93. package/src/components/marketo-form/fixtures/index.ts +0 -185
  94. package/src/components/marketo-form/form/index.tsx +0 -369
  95. package/src/components/marketo-form/index.test.tsx +0 -320
  96. package/src/components/marketo-form/index.ts +0 -11
  97. package/src/components/marketo-form/package.original.json +0 -30
  98. package/src/components/marketo-form/partials/error-message/index.tsx +0 -12
  99. package/src/components/marketo-form/partials/error-message/style.module.css +0 -13
  100. package/src/components/marketo-form/partials/field/index.tsx +0 -90
  101. package/src/components/marketo-form/partials/field-wrapper/index.tsx +0 -26
  102. package/src/components/marketo-form/partials/fields/checkbox-field/index.tsx +0 -32
  103. package/src/components/marketo-form/partials/fields/email-field/index.tsx +0 -35
  104. package/src/components/marketo-form/partials/fields/form-page-url-field/index.tsx +0 -21
  105. package/src/components/marketo-form/partials/fields/hidden-field/index.tsx +0 -37
  106. package/src/components/marketo-form/partials/fields/htmltext-field/index.tsx +0 -21
  107. package/src/components/marketo-form/partials/fields/htmltext-field/style.module.css +0 -18
  108. package/src/components/marketo-form/partials/fields/name-field/index.tsx +0 -19
  109. package/src/components/marketo-form/partials/fields/name-field/style.module.css +0 -13
  110. package/src/components/marketo-form/partials/fields/radio-buttons-field/index.tsx +0 -48
  111. package/src/components/marketo-form/partials/fields/select-field/index.tsx +0 -39
  112. package/src/components/marketo-form/partials/fields/select-field/style.module.css +0 -5
  113. package/src/components/marketo-form/partials/fields/telephone-field/index.tsx +0 -30
  114. package/src/components/marketo-form/partials/fields/text-field/index.tsx +0 -30
  115. package/src/components/marketo-form/partials/fields/textarea-field/index.tsx +0 -29
  116. package/src/components/marketo-form/partials/label/index.tsx +0 -24
  117. package/src/components/marketo-form/partials/label/style.module.css +0 -12
  118. package/src/components/marketo-form/partials/visibility-rule/index.tsx +0 -84
  119. package/src/components/marketo-form/props.js +0 -66
  120. package/src/components/marketo-form/server/api-routes.ts +0 -109
  121. package/src/components/marketo-form/server/client.ts +0 -98
  122. package/src/components/marketo-form/server/index.ts +0 -8
  123. package/src/components/marketo-form/types.ts +0 -268
  124. package/src/components/marketo-form/utils.test.tsx +0 -103
  125. package/src/components/marketo-form/utils.ts +0 -449
  126. package/src/components/next-steps/index.tsx +0 -137
  127. package/src/components/next-steps/style.module.css +0 -270
  128. package/src/components/next-steps/types.ts +0 -63
  129. package/src/components/product-badge/index.test.tsx +0 -11
  130. package/src/components/product-badge/index.tsx +0 -42
  131. package/src/components/product-badge/style.module.css +0 -76
  132. package/src/components/products-used/index.tsx +0 -84
  133. package/src/components/products-used/style.module.css +0 -87
  134. package/src/components/products-used/types.ts +0 -31
  135. package/src/components/related-content/index.test.tsx +0 -74
  136. package/src/components/related-content/index.tsx +0 -56
  137. package/src/components/related-content/style.module.css +0 -89
  138. package/src/components/related-content/types.ts +0 -21
  139. package/src/components/subnav/helpers/areBasePathsMatching.ts +0 -13
  140. package/src/components/subnav/helpers/traverse/index.ts +0 -42
  141. package/src/components/subnav/helpers/useHeightRef.ts +0 -42
  142. package/src/components/subnav/helpers/useNavRef.ts +0 -30
  143. package/src/components/subnav/helpers/useOverflowRef.ts +0 -85
  144. package/src/components/subnav/helpers/useStuckRef.ts +0 -51
  145. package/src/components/subnav/index.tsx +0 -199
  146. package/src/components/subnav/partials/CtaLinks/github-stars-link/formatStarCount/index.test.ts +0 -26
  147. package/src/components/subnav/partials/CtaLinks/github-stars-link/formatStarCount/index.ts +0 -22
  148. package/src/components/subnav/partials/CtaLinks/github-stars-link/index.tsx +0 -87
  149. package/src/components/subnav/partials/CtaLinks/github-stars-link/parseGithubUrl/index.test.ts +0 -29
  150. package/src/components/subnav/partials/CtaLinks/github-stars-link/parseGithubUrl/index.ts +0 -32
  151. package/src/components/subnav/partials/CtaLinks/github-stars-link/style.module.css +0 -85
  152. package/src/components/subnav/partials/CtaLinks/icons/github-logo.js +0 -20
  153. package/src/components/subnav/partials/CtaLinks/icons/github.svg.js +0 -7
  154. package/src/components/subnav/partials/CtaLinks/icons/star.js +0 -20
  155. package/src/components/subnav/partials/CtaLinks/index.tsx +0 -130
  156. package/src/components/subnav/partials/CtaLinks/style.module.css +0 -45
  157. package/src/components/subnav/partials/DropdownTrigger/index.tsx +0 -35
  158. package/src/components/subnav/partials/DropdownTrigger/style.module.css +0 -36
  159. package/src/components/subnav/partials/MenuItemsDefault/index.tsx +0 -151
  160. package/src/components/subnav/partials/MenuItemsDefault/style.module.css +0 -91
  161. package/src/components/subnav/partials/MenuItemsOverflow/index.tsx +0 -139
  162. package/src/components/subnav/partials/MenuItemsOverflow/style.module.css +0 -82
  163. package/src/components/subnav/partials/TitleLink/index.tsx +0 -113
  164. package/src/components/subnav/partials/TitleLink/mktg-logos/all-community-product-logos_on-dark.ts +0 -9
  165. package/src/components/subnav/partials/TitleLink/mktg-logos/all-community-product-logos_on-light.ts +0 -9
  166. package/src/components/subnav/partials/TitleLink/mktg-logos/all-primary-logos_on-dark.ts +0 -23
  167. package/src/components/subnav/partials/TitleLink/mktg-logos/all-primary-logos_on-light.ts +0 -23
  168. package/src/components/subnav/partials/TitleLink/style.module.css +0 -43
  169. package/src/components/subnav/partials/nav-item-text/index.tsx +0 -37
  170. package/src/components/subnav/partials/nav-item-text/style.module.css +0 -15
  171. package/src/components/subnav/style.module.css +0 -68
  172. package/src/components/subnav/subnav-consts.ts +0 -1
  173. package/src/components/subnav/theme.module.css +0 -50
@@ -1,334 +0,0 @@
1
- import { fireEvent, render, screen, act } from '@testing-library/react'
2
-
3
- const defaultProps = {
4
- version: 0,
5
- showDialog: false,
6
- segmentWriteKey: 'iyi06c432UL7SB1r3fQReec4bNwFyzkW',
7
- privacyPolicyLink: 'https://www.hashicorp.com/privacy',
8
- companyName: 'HashiCorp',
9
- segmentServices: [
10
- {
11
- name: 'Example Name',
12
- category: 'Example Category',
13
- description:
14
- 'A short description of what the service is and how your company uses the data.',
15
- },
16
- ],
17
- additionalServices: [
18
- {
19
- name: 'Name of the service',
20
- category: 'Example Category',
21
- description:
22
- 'A short description of what the service is and how your company uses the data.',
23
- body: '',
24
- url: 'http://www.an-optional-url-for-a-script-to-add-to-the-page.com',
25
- async: true,
26
- },
27
- {
28
- name: 'Name of the service 2',
29
- category: 'Example Category',
30
- description: 'A script with additional elements to be injected',
31
- body: '',
32
- url: 'https://source-url-of-script.com',
33
- async: true,
34
- addToBody: true,
35
- dataAttrs: [
36
- {
37
- name: 'test',
38
- value: 'foobar',
39
- },
40
- ],
41
- },
42
- {
43
- name: 'Name of the service 3',
44
- category: 'Example Category',
45
- description: 'A script with additional elements to be injected',
46
- body: 'window.foo = "bar"',
47
- async: true,
48
- dataAttrs: [
49
- {
50
- name: 'test',
51
- value: 'foobar',
52
- },
53
- ],
54
- },
55
- {
56
- name: 'Name of the conditionally loaded service',
57
- category: 'Example Category with conditionally loaded service',
58
- description: 'A script with additional elements to be injected',
59
- body: 'window.foo = "bar"',
60
- url: 'https://source-of-conditionally-loaded-script.com',
61
- async: true,
62
- dataAttrs: [
63
- {
64
- name: 'test',
65
- value: 'foobar',
66
- },
67
- ],
68
- shouldLoad: () => false,
69
- },
70
- ],
71
- categories: [
72
- {
73
- name: 'Example Category',
74
- description: 'A short description of the category',
75
- },
76
- ],
77
- container: '#consent-manager',
78
- }
79
-
80
- beforeAll(() => {
81
- HTMLDialogElement.prototype.show = vi.fn()
82
- HTMLDialogElement.prototype.showModal = vi.fn()
83
- HTMLDialogElement.prototype.close = vi.fn()
84
- })
85
-
86
- describe('ConsentManager', () => {
87
- afterEach(() => {
88
- vi.resetModules()
89
- })
90
-
91
- test('shows the banner if the forceShow prop is true', async () => {
92
- const { default: ConsentManager } = await import('./')
93
- render(<ConsentManager {...defaultProps} forceShow={true} />)
94
- expect(screen.getByTestId('consent-banner')).toBeInTheDocument()
95
- })
96
-
97
- test('sets existing preferences and does not show the banner if preferences are already set', async () => {
98
- await runWithMockedImport(
99
- './util/cookies',
100
- {
101
- loadPreferences: () => {
102
- return { loadAll: false, segment: false, version: 0 }
103
- },
104
- // eslint-disable-next-line @typescript-eslint/no-empty-function
105
- savePreferences: () => {},
106
- },
107
- (MockedConsentManager) => {
108
- render(<MockedConsentManager {...defaultProps} forceShow={false} />)
109
- expect(screen.queryByTestId('consent-banner')).not.toBeInTheDocument()
110
- }
111
- )
112
- })
113
-
114
- test('shows the banner if preferences are set but version has increased', async () => {
115
- await runWithMockedImport(
116
- './util/cookies',
117
- {
118
- loadPreferences: () => {
119
- return { loadAll: false, segment: false, version: 1 }
120
- },
121
- // eslint-disable-next-line @typescript-eslint/no-empty-function
122
- savePreferences: () => {},
123
- },
124
- (MockedConsentManager) => {
125
- render(
126
- <MockedConsentManager
127
- {...defaultProps}
128
- forceShow={false}
129
- version={2}
130
- />
131
- )
132
- expect(screen.queryByTestId('consent-banner')).toBeInTheDocument()
133
- }
134
- )
135
- })
136
-
137
- test('if the manage preferences button is clicked, opens the dialog and makes body un-scrollable', async () => {
138
- const { default: ConsentManager } = await import('./')
139
-
140
- render(<ConsentManager {...defaultProps} forceShow={true} />)
141
- fireEvent.click(screen.getByTestId('manage-preferences'))
142
- expect(screen.getByTestId('consent-mgr-dialog')).toBeInTheDocument()
143
- expect(document.body.className).toBe('g-noscroll')
144
- })
145
-
146
- test('opens the dialog when the open function is called', async () => {
147
- const { default: ConsentManager, open } = await import('./')
148
- render(<ConsentManager {...defaultProps} />)
149
- act(() => open())
150
- expect(screen.getByTestId('consent-mgr-dialog')).toBeInTheDocument()
151
- })
152
-
153
- test('if accept all button is clicked, any open dialogs are closed and all analytics are loaded', async () => {
154
- let prefs
155
- await runWithMockedImport(
156
- './util/cookies',
157
- {
158
- // eslint-disable-next-line @typescript-eslint/no-empty-function
159
- loadPreferences: () => {},
160
- savePreferences: (preferences) => {
161
- prefs = preferences
162
- },
163
- },
164
- (MockedConsentManager) => {
165
- render(<MockedConsentManager {...defaultProps} forceShow={true} />)
166
- fireEvent.click(screen.getByTestId('accept'))
167
- }
168
- )
169
- expect(prefs.loadAll).toBe(true)
170
- })
171
-
172
- test('loads segment and additional services if loadAll is passed', async () => {
173
- await runWithMockedImport(
174
- './util/cookies',
175
- {
176
- loadPreferences: () => {
177
- return { loadAll: true, segment: { foo: 'bar' } }
178
- },
179
- // eslint-disable-next-line @typescript-eslint/no-empty-function
180
- savePreferences: () => {},
181
- },
182
- (MockedConsentManager) => {
183
- render(
184
- <MockedConsentManager
185
- {...defaultProps}
186
- forceShow={false}
187
- version={2}
188
- />
189
- )
190
- const html = document.body.innerHTML
191
- // script was injected
192
- expect(html).toMatch(
193
- /<script type="text\/javascript" src="https:\/\/artemis.hashicorp.com\/script/
194
- )
195
- // all services loaded, as well as custom segment
196
- expect(html).toMatch(
197
- /analytics\.load\("iyi06c432UL7SB1r3fQReec4bNwFyzkW", {"integrations":{"All":true,"Segment\.io":true,"foo":"bar"}}\);/
198
- )
199
-
200
- // custom service loaded
201
- expect(html).toMatch(
202
- /src="http:\/\/www.an-optional-url-for-a-script-to-add-to-the-page\.com"/
203
- )
204
-
205
- // conditionally loaded service not loaded
206
- expect(html).not.toMatch(
207
- /src="https:\/\/source-of-conditionally-loaded-script\.com"/
208
- )
209
-
210
- // custom inline script
211
- expect(html).toMatch(/window\.foo = "bar"/)
212
- }
213
- )
214
- })
215
-
216
- describe('handles custom events', () => {
217
- test('manage preferences callback', async () => {
218
- const fn = vi.fn()
219
- await runWithMockedImport(
220
- './components/dialog',
221
- {
222
- default: () => {
223
- return <p data-testid="mocked-dialog">test</p>
224
- },
225
- },
226
- (MockedConsentManager) => {
227
- render(
228
- <MockedConsentManager
229
- {...defaultProps}
230
- forceShow={true}
231
- onManagePreferences={fn}
232
- />
233
- )
234
- fireEvent.click(screen.getByTestId('manage-preferences'))
235
- expect(fn).toHaveBeenCalled()
236
- }
237
- )
238
- })
239
-
240
- test('accept all callback', async () => {
241
- const fn = vi.fn()
242
- await runWithMockedImport(
243
- './components/dialog',
244
- {
245
- default: () => {
246
- return <p data-testid="mocked-dialog">test</p>
247
- },
248
- },
249
- (MockedConsentManager) => {
250
- render(
251
- <MockedConsentManager
252
- {...defaultProps}
253
- forceShow={true}
254
- onAcceptAll={fn}
255
- />
256
- )
257
- fireEvent.click(screen.getByTestId('accept'))
258
- expect(fn).toHaveBeenCalled()
259
- }
260
- )
261
- })
262
- })
263
-
264
- describe('handles conditionally loaded services in dialog', () => {
265
- test('additional services category is not in dialog when shouldLoad() is false in all category services', async () => {
266
- const { default: ConsentManager, open } = await import('./')
267
- render(<ConsentManager {...defaultProps} />)
268
- act(() => open())
269
-
270
- const shownCategory = await screen.findByText('Example Category')
271
- const hiddenCategory = screen.queryByText(
272
- 'Example Category with conditionally loaded service'
273
- )
274
- expect(shownCategory).toBeInTheDocument()
275
- expect(hiddenCategory).not.toBeInTheDocument()
276
- })
277
-
278
- test('additional services category is in dialog when shouldLoad() is false in some category services but service is not in dialog', async () => {
279
- const newService = {
280
- name: 'Name of the new service',
281
- category: 'Example Category with conditionally loaded service',
282
- description: 'A script with additional elements to be injected',
283
- body: 'window.foo = "bar"',
284
- async: true,
285
- dataAttrs: [
286
- {
287
- name: 'test',
288
- value: 'foobar',
289
- },
290
- ],
291
- }
292
-
293
- const { default: ConsentManager, open } = await import('./')
294
- render(
295
- <ConsentManager
296
- {...{
297
- ...defaultProps,
298
- additionalServices: [
299
- ...defaultProps.additionalServices,
300
- newService,
301
- ],
302
- }}
303
- />
304
- )
305
- act(() => open())
306
- const category = await screen.findByText(
307
- 'Example Category with conditionally loaded service'
308
- )
309
-
310
- expect(category).toBeInTheDocument()
311
- const showMoreButton = category.nextSibling!.nextSibling!
312
- // Open category accordion item to make services visible
313
- fireEvent.click(showMoreButton)
314
- const shouldLoadService = await screen.findByText(
315
- 'Name of the new service'
316
- )
317
- const shouldNotLoadService = screen.queryByText(
318
- 'Name of the conditionally loaded service'
319
- )
320
- expect(shouldLoadService).toBeInTheDocument()
321
- expect(shouldNotLoadService).not.toBeInTheDocument()
322
- })
323
- })
324
- })
325
-
326
- // Given an internal module name and mock implementation, mocks the given module and returns a version
327
- // of the component with the module mocked.
328
- async function runWithMockedImport(module, mock, cb) {
329
- vi.doMock(module, () => mock)
330
- return import('./').then(({ default: ConsentManager, open }) => {
331
- cb(ConsentManager, open)
332
- vi.doUnmock(module)
333
- })
334
- }
@@ -1,186 +0,0 @@
1
- import { useState, useEffect, useCallback } from 'react'
2
- import { EventEmitter } from 'events'
3
- import classNames from 'classnames'
4
- import { isInUS } from '@hashicorp/platform-util/geo'
5
- import { loadPreferences, savePreferences } from './util/cookies'
6
- import ConsentBanner from './components/banner/banner'
7
- import ConsentPreferences from './components/dialog/dialog'
8
- import SegmentScript from './scripts/segment'
9
- import CustomScripts from './scripts/custom'
10
- import s from './style.module.css'
11
- import {
12
- ConsentManagerCategory,
13
- ConsentManagerService,
14
- ConsentManagerPreferences,
15
- } from './types'
16
-
17
- interface ConsentManagerProps {
18
- additionalServices?: ConsentManagerService[]
19
- categories?: ConsentManagerCategory[]
20
- className?: string
21
- cookiePolicyLink?: string
22
- forceShow?: boolean
23
- privacyPolicyLink?: string
24
- segmentServices?: ConsentManagerService[]
25
- segmentWriteKey?: string
26
- showDialog?: boolean
27
- version?: number
28
- onManagePreferences?: () => void
29
- onAcceptAll?: () => void
30
- }
31
-
32
- const emitter = new EventEmitter()
33
-
34
- export function open() {
35
- emitter.emit('openDialog')
36
- }
37
-
38
- export function saveAndLoadAnalytics(preferences: ConsentManagerPreferences) {
39
- emitter.emit('saveAndLoadAnalytics', preferences)
40
- }
41
-
42
- export default function ConsentManager(props: ConsentManagerProps) {
43
- const [preferences, setPreferences] = useState<{
44
- loadAll?: boolean
45
- version?: number
46
- }>(loadPreferences() ?? {})
47
- const [showDialog, setShowDialog] = useState(props.showDialog ?? false)
48
- const [showBanner, setShowBanner] = useState(() => {
49
- // 1. If prop override is set, always show the consent bar.
50
- if (props.forceShow) return true
51
- })
52
-
53
- const hasEmptyPreferencesOrVersionMismatch =
54
- Object.keys(preferences).length === 0 ||
55
- preferences.version !== props.version
56
-
57
- const closeDialog = () => {
58
- document.body.classList.remove('g-noscroll')
59
- setShowDialog(false)
60
- setShowBanner(false)
61
- setPreferences(loadPreferences() ?? {})
62
- }
63
-
64
- const saveAndLoadAnalytics = useCallback(
65
- (preferences) => {
66
- if (typeof preferences === 'undefined') {
67
- preferences = { loadAll: false, segment: false }
68
- }
69
- savePreferences(preferences, props.version)
70
-
71
- // If analytics have already been added to page, it's likely you're updating your preferences
72
- // We reload the page to re-initiate the script with the updated integrations
73
- if (window.analytics && window.analytics.initialized) {
74
- window.location.reload()
75
- return
76
- }
77
-
78
- closeDialog()
79
- },
80
- [props.version]
81
- )
82
-
83
- const openDialog = useCallback(() => {
84
- document.body.classList.add('g-noscroll')
85
- setShowBanner(false)
86
- setShowDialog(true)
87
- }, [])
88
-
89
- // Setup the event handler to open the dialog imperatively
90
- useEffect(() => {
91
- emitter.on('openDialog', openDialog)
92
- return () => {
93
- emitter.off('openDialog', openDialog)
94
- }
95
- }, [openDialog])
96
-
97
- // Setup the event handler to save and load analytics imperatively
98
- useEffect(() => {
99
- emitter.on('saveAndLoadAnalytics', saveAndLoadAnalytics)
100
- return () => {
101
- emitter.off('saveAndLoadAnalytics', saveAndLoadAnalytics)
102
- }
103
- }, [saveAndLoadAnalytics])
104
-
105
- // Show banner if there are no preferences or the version mismatches
106
- useEffect(() => {
107
- setShowBanner(hasEmptyPreferencesOrVersionMismatch)
108
- // eslint-disable-next-line react-hooks/exhaustive-deps -- We only want to run this check once
109
- }, [])
110
-
111
- useEffect(() => {
112
- if (hasEmptyPreferencesOrVersionMismatch && isInUS()) {
113
- saveAndLoadAnalytics({ loadAll: true })
114
- setShowBanner(true)
115
- }
116
- // eslint-disable-next-line react-hooks/exhaustive-deps -- We only want to run this check once
117
- }, [])
118
-
119
- const escFunction = useCallback(
120
- (event) => {
121
- if (showDialog && event.key === 'Escape') {
122
- closeDialog()
123
- }
124
- },
125
- [showDialog]
126
- )
127
-
128
- useEffect(() => {
129
- document.addEventListener('keydown', escFunction, false)
130
-
131
- return () => {
132
- document.removeEventListener('keydown', escFunction, false)
133
- }
134
- }, [escFunction])
135
-
136
- const filteredAdditionalServices = props.additionalServices?.filter(
137
- (service) => service.shouldLoad === undefined || service.shouldLoad()
138
- )
139
-
140
- return (
141
- <div className={classNames(s.root, props.className)}>
142
- {/* Consent banner at the bottom */}
143
- {showBanner && (
144
- <ConsentBanner
145
- preferences={preferences}
146
- privacyPolicyLink={props.privacyPolicyLink}
147
- cookiePolicyLink={props.cookiePolicyLink}
148
- onManagePreferences={() => {
149
- openDialog()
150
- if (props.onManagePreferences) {
151
- props.onManagePreferences()
152
- }
153
- }}
154
- onAccept={() => {
155
- saveAndLoadAnalytics({ loadAll: true })
156
- if (props.onAcceptAll) {
157
- props.onAcceptAll()
158
- }
159
- }}
160
- />
161
- )}
162
- {/* Consent manager preferences dialog */}
163
- <ConsentPreferences
164
- version={props.version}
165
- segmentWriteKey={props.segmentWriteKey}
166
- segmentServices={props.segmentServices}
167
- additionalServices={filteredAdditionalServices}
168
- preferences={preferences}
169
- categories={props.categories || []}
170
- privacyPolicyLink={props.privacyPolicyLink}
171
- cookiePolicyLink={props.cookiePolicyLink}
172
- saveAndLoadAnalytics={saveAndLoadAnalytics}
173
- showDialog={showDialog}
174
- />
175
-
176
- <SegmentScript
177
- preferences={preferences}
178
- writeKey={props.segmentWriteKey}
179
- />
180
- <CustomScripts
181
- preferences={preferences}
182
- services={filteredAdditionalServices}
183
- />
184
- </div>
185
- )
186
- }
@@ -1,29 +0,0 @@
1
- # Consent Manager Loader
2
-
3
- The consent manager component is large and complex, with many configurable options. The consent manager loader interface makes a bunch of assumptions and strips down the number of configurable options to very few, which is enough to do the trick for most of our web properties.
4
-
5
- The loader also ships with a couple **presets**, which load in standard sets of tracking scripts that we tend to adhere towards. Currently, the available options are `oss` and `enterprise`.
6
-
7
- ## Usage
8
-
9
- Code block below shows basic usage:
10
-
11
- ```js
12
- import createConsentManager from '@web/react-components/src/components/consent-manager/loader'
13
-
14
- const { ConsentManager, openConsentManager } = createConsentManager({
15
- preset: 'oss',
16
- })
17
-
18
- // sample implementation
19
- export default function SomePage() {
20
- return (
21
- <>
22
- <p>my page content</p>
23
- <ConsentManager />
24
- </>
25
- )
26
- }
27
- ```
28
-
29
- Check out the [types](types.ts) to get an overview of the full options that can be passed in!
@@ -1,22 +0,0 @@
1
- export default [
2
- {
3
- name: 'Functional',
4
- description:
5
- 'Functional services provide a utility to the website, such as the ability to log in, or to get live support. Disabling any of these scripts will cause that utility to be missing from the site.',
6
- },
7
- {
8
- name: 'Analytics',
9
- description:
10
- 'Analytics services keep track of page traffic and user behavior while browsing the site. We use this data internally to improve the usability and performance of the site. Disabling any of these scripts makes it more difficult for us to understand how our site is being used, and slower to improve it.',
11
- },
12
- {
13
- name: 'Email Marketing',
14
- description:
15
- 'Email Marketing services track user behavior while browsing the site. We use this data internally in our marketing efforts to provide users contextually relevant information based off of their behaviors. Disabling any of these scripts makes it more difficult for us to provide you contextually relevant information.',
16
- },
17
- {
18
- name: 'Advertising',
19
- description:
20
- "Advertising services allow us to keep track of whether our company advertising campaigns have been successful or not. We absolutely never display any third party advertisements on our own websites, or sell any user data to third parties. Disabling any of these scripts makes it more difficult for us to gauge whether our company's advertisements are resonating with current and potential future customers.",
21
- },
22
- ]
@@ -1,94 +0,0 @@
1
- import React from 'react'
2
- import ConsentManagerComponent, { open, saveAndLoadAnalytics } from '../'
3
- import defaultCategories from './categories'
4
- import ossPreset from './presets/oss'
5
- import enterprisePreset from './presets/enterprise'
6
- import {
7
- ConsentManagerCategory,
8
- ConsentManagerPreferences,
9
- ConsentManagerProps,
10
- ConsentManagerService,
11
- } from '../types'
12
-
13
- const VERSION = 4
14
- const COMPANY_NAME = 'HashiCorp'
15
- const PRIVACY_LINK = 'https://www.hashicorp.com/privacy'
16
- const COOKIES_LINK = 'https://www.hashicorp.com/cookies'
17
-
18
- export default function createConsentManager({
19
- segmentWriteKey = process.env.SEGMENT_WRITE_KEY,
20
- preset,
21
- segmentServices,
22
- otherServices,
23
- categories,
24
- forceShow = false,
25
- onAcceptAll,
26
- onManagePreferences,
27
- }: {
28
- segmentWriteKey?: string
29
- preset?: 'oss' | 'enterprise'
30
- segmentServices?: ConsentManagerService[]
31
- otherServices?: ConsentManagerService[]
32
- categories?: ConsentManagerCategory[]
33
- forceShow?: boolean
34
- onAcceptAll?: () => void
35
- onManagePreferences?: () => void
36
- }): {
37
- ConsentManager: typeof ConsentManagerComponent
38
- openConsentManager: () => void
39
- saveAndLoadAnalytics: (preferences: ConsentManagerPreferences) => void
40
- } {
41
- // if hashi env is present, check against it. if not, fall back to checking node env
42
- const isProd = process.env.HASHI_ENV
43
- ? process.env.HASHI_ENV === 'production'
44
- : process.env.NODE_ENV === 'production'
45
-
46
- if (!process.env.HASHI_ENV)
47
- console.warn(
48
- 'Consent manager expects the "HASHI_ENV" environment variable to be set in order to ensure proper analytics tracking. Please make sure "HASHI_ENV" is set appropriately within your app.'
49
- )
50
-
51
- // set the correct segment key based on environment
52
- const segmentKey = isProd
53
- ? segmentWriteKey
54
- : '0EXTgkNx0Ydje2PGXVbRhpKKoe5wtzcE'
55
-
56
- // next we build the config objct, kicking it off with the default values
57
- let config: ConsentManagerProps = {
58
- version: VERSION,
59
- companyName: COMPANY_NAME,
60
- privacyPolicyLink: PRIVACY_LINK,
61
- cookiePolicyLink: COOKIES_LINK,
62
- segmentWriteKey: segmentKey,
63
- categories: defaultCategories,
64
- forceShow,
65
- onAcceptAll,
66
- onManagePreferences,
67
- }
68
-
69
- // add preset values if present
70
- if (preset === 'oss') config = { ...config, ...ossPreset }
71
- if (preset === 'enterprise') config = { ...config, ...enterprisePreset }
72
-
73
- // add any other custom values nondestructively if present
74
- if (segmentServices) {
75
- if (!config.segmentServices) config.segmentServices = []
76
- config.segmentServices.push(...segmentServices)
77
- }
78
- if (otherServices) {
79
- if (!config.additionalServices) config.additionalServices = []
80
- config.additionalServices.push(...otherServices)
81
- }
82
- if (categories) config.categories!.push(...categories)
83
-
84
- // finally, we return a HOC that will render the fully configured consent manager
85
- return {
86
- ConsentManager: function ConsentManagerWrapper() {
87
- return (
88
- <ConsentManagerComponent {...config} categories={config.categories!} />
89
- )
90
- },
91
- openConsentManager: open,
92
- saveAndLoadAnalytics,
93
- }
94
- }
@@ -1,12 +0,0 @@
1
- import services from '../services'
2
-
3
- export default {
4
- segmentServices: [
5
- services.googleAnalytics,
6
- services.googleTagManager,
7
- services.linkedIn,
8
- services.heap,
9
- services.marketo,
10
- services.googleAds,
11
- ],
12
- }
@@ -1,10 +0,0 @@
1
- import services from '../services'
2
-
3
- export default {
4
- segmentServices: [
5
- services.googleAnalytics,
6
- services.googleAds,
7
- services.linkedIn,
8
- services.marketo,
9
- ],
10
- }