@hashicorp/react-components 1.1.8 → 1.1.11
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.
- package/package.json +4 -8
- package/src/components/nav-panel/components/flight-icon/index.tsx +51 -0
- package/src/components/nav-panel/components/flight-icon/style.module.css +3 -0
- package/src/components/nav-panel/components/link-list/index.tsx +15 -9
- package/src/components/nav-panel/components/link-list/style.module.css +10 -10
- package/src/components/nav-panel/components/panel/column/style.module.css +3 -3
- package/src/components/nav-panel/components/panel/root/style.module.css +6 -6
- package/src/components/nav-panel/components/promo/index.tsx +15 -9
- package/src/components/nav-panel/components/promo/style.module.css +27 -13
- package/src/components/nav-panel/components/text/index.tsx +34 -0
- package/src/components/nav-panel/product-panel/index.tsx +39 -14
- package/src/components/nav-panel/product-panel/style.module.css +78 -37
- package/src/components/nav-panel/standard-panel/index.tsx +3 -0
- package/src/components/nav-panel/standard-panel/style.module.css +2 -2
- package/src/lib/get-localized-link-props/index.test.ts +30 -0
- package/src/lib/get-localized-link-props/index.ts +45 -0
- package/src/lib/parse-url/index.test.ts +40 -1
- package/src/lib/parse-url/index.ts +75 -9
- package/src/lib/send-posthog-event/index.ts +22 -0
- package/src/lib/supported-locales/index.ts +1 -0
- package/src/lib/track-nav-click-event/index.ts +4 -4
- package/src/lib/v/index.ts +4 -5
- package/src/components/actions/index.tsx +0 -107
- package/src/components/actions/style.module.css +0 -28
- package/src/components/actions/types.ts +0 -73
- package/src/components/call-to-action/index.tsx +0 -205
- package/src/components/call-to-action/styles/variant-centered.module.css +0 -93
- package/src/components/call-to-action/styles/variant-compact-grid.module.css +0 -88
- package/src/components/call-to-action/styles/variant-compact.module.css +0 -91
- package/src/components/call-to-action/styles/variant-links.module.css +0 -85
- package/src/components/card/README.md +0 -11
- package/src/components/card/card.tsx +0 -45
- package/src/components/card/index.test.tsx +0 -69
- package/src/components/card/index.tsx +0 -14
- package/src/components/card/newsroom-card/index.test.tsx +0 -39
- package/src/components/card/newsroom-card/index.tsx +0 -37
- package/src/components/card/newsroom-card/style.module.css +0 -12
- package/src/components/card/partner-card/index.test.tsx +0 -57
- package/src/components/card/partner-card/index.tsx +0 -69
- package/src/components/card/partner-card/style.module.css +0 -24
- package/src/components/card/person-card/index.test.tsx +0 -71
- package/src/components/card/person-card/index.tsx +0 -93
- package/src/components/card/person-card/style.module.css +0 -33
- package/src/components/card/primitives.tsx +0 -176
- package/src/components/card/promo-card/index.tsx +0 -51
- package/src/components/card/resource-card/index.test.tsx +0 -48
- package/src/components/card/resource-card/index.tsx +0 -37
- package/src/components/card/style.module.css +0 -145
- package/src/components/card/types.ts +0 -66
- package/src/components/card/unified-card/index.tsx +0 -64
- package/src/components/consent-manager/README.md +0 -73
- package/src/components/consent-manager/components/banner/banner.module.css +0 -23
- package/src/components/consent-manager/components/banner/banner.test.tsx +0 -31
- package/src/components/consent-manager/components/banner/banner.tsx +0 -73
- package/src/components/consent-manager/components/dialog/dialog.module.css +0 -145
- package/src/components/consent-manager/components/dialog/dialog.test.tsx +0 -194
- package/src/components/consent-manager/components/dialog/dialog.tsx +0 -339
- package/src/components/consent-manager/img/icn_close.tsx +0 -19
- package/src/components/consent-manager/index.test.tsx +0 -334
- package/src/components/consent-manager/index.tsx +0 -186
- package/src/components/consent-manager/loader/README.md +0 -29
- package/src/components/consent-manager/loader/categories.ts +0 -22
- package/src/components/consent-manager/loader/index.tsx +0 -94
- package/src/components/consent-manager/loader/presets/enterprise.ts +0 -12
- package/src/components/consent-manager/loader/presets/oss.ts +0 -10
- package/src/components/consent-manager/loader/services.ts +0 -45
- package/src/components/consent-manager/scripts/custom.tsx +0 -59
- package/src/components/consent-manager/scripts/segment.tsx +0 -87
- package/src/components/consent-manager/style.module.css +0 -9
- package/src/components/consent-manager/types.ts +0 -55
- package/src/components/consent-manager/util/cookies.test.ts +0 -75
- package/src/components/consent-manager/util/cookies.ts +0 -70
- package/src/components/consent-manager/util/integrations.test.ts +0 -115
- package/src/components/consent-manager/util/integrations.ts +0 -110
- package/src/components/intro/index.tsx +0 -82
- package/src/components/intro/style.module.css +0 -67
- package/src/components/intro/types.ts +0 -44
- package/src/components/marketo-form/CHANGELOG.md +0 -122
- package/src/components/marketo-form/README.md +0 -1
- package/src/components/marketo-form/contexts/FormMetadata.ts +0 -11
- package/src/components/marketo-form/docs.mdx +0 -197
- package/src/components/marketo-form/fixtures/index.ts +0 -185
- package/src/components/marketo-form/form/index.tsx +0 -369
- package/src/components/marketo-form/index.test.tsx +0 -320
- package/src/components/marketo-form/index.ts +0 -11
- package/src/components/marketo-form/package.original.json +0 -30
- package/src/components/marketo-form/partials/error-message/index.tsx +0 -12
- package/src/components/marketo-form/partials/error-message/style.module.css +0 -13
- package/src/components/marketo-form/partials/field/index.tsx +0 -90
- package/src/components/marketo-form/partials/field-wrapper/index.tsx +0 -26
- package/src/components/marketo-form/partials/fields/checkbox-field/index.tsx +0 -32
- package/src/components/marketo-form/partials/fields/email-field/index.tsx +0 -35
- package/src/components/marketo-form/partials/fields/form-page-url-field/index.tsx +0 -21
- package/src/components/marketo-form/partials/fields/hidden-field/index.tsx +0 -37
- package/src/components/marketo-form/partials/fields/htmltext-field/index.tsx +0 -21
- package/src/components/marketo-form/partials/fields/htmltext-field/style.module.css +0 -18
- package/src/components/marketo-form/partials/fields/name-field/index.tsx +0 -19
- package/src/components/marketo-form/partials/fields/name-field/style.module.css +0 -13
- package/src/components/marketo-form/partials/fields/radio-buttons-field/index.tsx +0 -48
- package/src/components/marketo-form/partials/fields/select-field/index.tsx +0 -39
- package/src/components/marketo-form/partials/fields/select-field/style.module.css +0 -5
- package/src/components/marketo-form/partials/fields/telephone-field/index.tsx +0 -30
- package/src/components/marketo-form/partials/fields/text-field/index.tsx +0 -30
- package/src/components/marketo-form/partials/fields/textarea-field/index.tsx +0 -29
- package/src/components/marketo-form/partials/label/index.tsx +0 -24
- package/src/components/marketo-form/partials/label/style.module.css +0 -12
- package/src/components/marketo-form/partials/visibility-rule/index.tsx +0 -84
- package/src/components/marketo-form/props.js +0 -66
- package/src/components/marketo-form/server/api-routes.ts +0 -109
- package/src/components/marketo-form/server/client.ts +0 -98
- package/src/components/marketo-form/server/index.ts +0 -8
- package/src/components/marketo-form/types.ts +0 -268
- package/src/components/marketo-form/utils.test.tsx +0 -103
- package/src/components/marketo-form/utils.ts +0 -449
- package/src/components/next-steps/index.tsx +0 -137
- package/src/components/next-steps/style.module.css +0 -270
- package/src/components/next-steps/types.ts +0 -63
- package/src/components/product-badge/index.test.tsx +0 -11
- package/src/components/product-badge/index.tsx +0 -42
- package/src/components/product-badge/style.module.css +0 -76
- package/src/components/products-used/index.tsx +0 -84
- package/src/components/products-used/style.module.css +0 -87
- package/src/components/products-used/types.ts +0 -31
- package/src/components/related-content/index.test.tsx +0 -74
- package/src/components/related-content/index.tsx +0 -56
- package/src/components/related-content/style.module.css +0 -89
- package/src/components/related-content/types.ts +0 -21
- package/src/components/subnav/helpers/areBasePathsMatching.ts +0 -13
- package/src/components/subnav/helpers/traverse/index.ts +0 -42
- package/src/components/subnav/helpers/useHeightRef.ts +0 -42
- package/src/components/subnav/helpers/useNavRef.ts +0 -30
- package/src/components/subnav/helpers/useOverflowRef.ts +0 -85
- package/src/components/subnav/helpers/useStuckRef.ts +0 -51
- package/src/components/subnav/index.tsx +0 -199
- package/src/components/subnav/partials/CtaLinks/github-stars-link/formatStarCount/index.test.ts +0 -26
- package/src/components/subnav/partials/CtaLinks/github-stars-link/formatStarCount/index.ts +0 -22
- package/src/components/subnav/partials/CtaLinks/github-stars-link/index.tsx +0 -87
- package/src/components/subnav/partials/CtaLinks/github-stars-link/parseGithubUrl/index.test.ts +0 -29
- package/src/components/subnav/partials/CtaLinks/github-stars-link/parseGithubUrl/index.ts +0 -32
- package/src/components/subnav/partials/CtaLinks/github-stars-link/style.module.css +0 -85
- package/src/components/subnav/partials/CtaLinks/icons/github-logo.js +0 -20
- package/src/components/subnav/partials/CtaLinks/icons/github.svg.js +0 -7
- package/src/components/subnav/partials/CtaLinks/icons/star.js +0 -20
- package/src/components/subnav/partials/CtaLinks/index.tsx +0 -130
- package/src/components/subnav/partials/CtaLinks/style.module.css +0 -45
- package/src/components/subnav/partials/DropdownTrigger/index.tsx +0 -35
- package/src/components/subnav/partials/DropdownTrigger/style.module.css +0 -36
- package/src/components/subnav/partials/MenuItemsDefault/index.tsx +0 -151
- package/src/components/subnav/partials/MenuItemsDefault/style.module.css +0 -91
- package/src/components/subnav/partials/MenuItemsOverflow/index.tsx +0 -139
- package/src/components/subnav/partials/MenuItemsOverflow/style.module.css +0 -82
- package/src/components/subnav/partials/TitleLink/index.tsx +0 -113
- package/src/components/subnav/partials/TitleLink/mktg-logos/all-community-product-logos_on-dark.ts +0 -9
- package/src/components/subnav/partials/TitleLink/mktg-logos/all-community-product-logos_on-light.ts +0 -9
- package/src/components/subnav/partials/TitleLink/mktg-logos/all-primary-logos_on-dark.ts +0 -23
- package/src/components/subnav/partials/TitleLink/mktg-logos/all-primary-logos_on-light.ts +0 -23
- package/src/components/subnav/partials/TitleLink/style.module.css +0 -43
- package/src/components/subnav/partials/nav-item-text/index.tsx +0 -37
- package/src/components/subnav/partials/nav-item-text/style.module.css +0 -15
- package/src/components/subnav/style.module.css +0 -68
- package/src/components/subnav/subnav-consts.ts +0 -1
- package/src/components/subnav/theme.module.css +0 -50
|
@@ -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,45 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
googleAnalytics: {
|
|
3
|
-
name: 'Google Analytics',
|
|
4
|
-
description:
|
|
5
|
-
'Google Analytics is a popular service for tracking web traffic. We use this data to determine what content our users find important so that we can dedicate more resources toward improving what matters most.',
|
|
6
|
-
category: 'Analytics',
|
|
7
|
-
},
|
|
8
|
-
googleTagManager: {
|
|
9
|
-
name: 'Google Tag Manager',
|
|
10
|
-
description:
|
|
11
|
-
'Google Tag Manager allows us to see how effective our advertising campaigns have been by measuring how many users arrived at our site via external advertisements for HashiCorp services. It is also used for the Google Optimize service, which performs A/B tests designed to optimize the usability of our websites.',
|
|
12
|
-
category: 'Analytics',
|
|
13
|
-
},
|
|
14
|
-
linkedIn: {
|
|
15
|
-
name: 'LinkedIn Insight Tag',
|
|
16
|
-
description:
|
|
17
|
-
'This small script allows us to see how effective our LinkedIn campaigns are by measuring how many users have clicked prompts on LinkedIn to arrive at our site.',
|
|
18
|
-
category: 'Advertising',
|
|
19
|
-
},
|
|
20
|
-
heap: {
|
|
21
|
-
name: 'Heap',
|
|
22
|
-
description:
|
|
23
|
-
'Heap is an analytics tool that is used to track interaction with specific elements on websites, like menus or buttons in sequence, as opposed to tracking overall pageviews like Google Analytics. We use this to test our user experience and ensure that people are able to find what they are looking for on our websites.',
|
|
24
|
-
category: 'Analytics',
|
|
25
|
-
},
|
|
26
|
-
marketo: {
|
|
27
|
-
name: 'Marketo V2',
|
|
28
|
-
description:
|
|
29
|
-
'Marketo is a marketing automation tool that allows us to segment users into different categories based off of their behaviors. We use this information to provide tailored information to users in our email campaigns.',
|
|
30
|
-
category: 'Email Marketing',
|
|
31
|
-
},
|
|
32
|
-
engagio: {
|
|
33
|
-
name: 'Engagio',
|
|
34
|
-
description:
|
|
35
|
-
"Engagio is a service that aids with the company's marketing efforts by estimating the types of visitors that are using our website and the way they move through it, allowing us to optimize content to best fit expectations.",
|
|
36
|
-
category: 'Advertising',
|
|
37
|
-
body: `var _eiq = _eiq || [];var _engagio_settings = {accountId: "a44336530751c27cca1d8124d3f1ad1867bb0c93"};(function() {var ei = document.createElement('script'); ei.type = 'text/javascript'; ei.async = true;ei.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'web-analytics.engagio.com/js/ei.js';var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ei, s);})();`,
|
|
38
|
-
},
|
|
39
|
-
googleAds: {
|
|
40
|
-
name: 'Google Ads (Gtag)',
|
|
41
|
-
description:
|
|
42
|
-
'This script keeps track of whether those who have clicked on advertisements for HashiCorp services we have run through google have clicked and arrived successfully on our website.',
|
|
43
|
-
category: 'Advertising',
|
|
44
|
-
},
|
|
45
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import Script from 'next/script'
|
|
2
|
-
import { ConsentManagerService, ConsentManagerPreferences } from '../types'
|
|
3
|
-
|
|
4
|
-
interface CustomScriptProps {
|
|
5
|
-
service: ConsentManagerService
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
interface CustomScriptsProps {
|
|
9
|
-
preferences: ConsentManagerPreferences
|
|
10
|
-
services?: ConsentManagerService[]
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function CustomScript({ service }: CustomScriptProps) {
|
|
14
|
-
const dataAttrs = service.dataAttrs
|
|
15
|
-
? Object.fromEntries(
|
|
16
|
-
service.dataAttrs.map((attr) => [`data-${attr.name}`, attr.value])
|
|
17
|
-
)
|
|
18
|
-
: {}
|
|
19
|
-
|
|
20
|
-
const strategy =
|
|
21
|
-
service.strategy ?? service.async ? 'afterInteractive' : 'beforeInteractive'
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
<Script
|
|
25
|
-
src={service.url}
|
|
26
|
-
strategy={strategy}
|
|
27
|
-
id={service.name}
|
|
28
|
-
{...dataAttrs}
|
|
29
|
-
onLoad={service?.onLoad}
|
|
30
|
-
>
|
|
31
|
-
{service.body ? service.body : null}
|
|
32
|
-
</Script>
|
|
33
|
-
)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export default function CustomScripts({
|
|
37
|
-
preferences,
|
|
38
|
-
services = [],
|
|
39
|
-
}: CustomScriptsProps) {
|
|
40
|
-
if (!preferences.loadAll && services?.length === 0) return null
|
|
41
|
-
|
|
42
|
-
let servicesToInject: ConsentManagerService[] = []
|
|
43
|
-
|
|
44
|
-
if (preferences.loadAll) {
|
|
45
|
-
servicesToInject = services
|
|
46
|
-
} else {
|
|
47
|
-
servicesToInject = services.filter(
|
|
48
|
-
(service) => preferences?.custom?.[service.name]
|
|
49
|
-
)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return (
|
|
53
|
-
<>
|
|
54
|
-
{servicesToInject.map((service) => (
|
|
55
|
-
<CustomScript service={service} key={service.name} />
|
|
56
|
-
))}
|
|
57
|
-
</>
|
|
58
|
-
)
|
|
59
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import Script from 'next/script'
|
|
2
|
-
|
|
3
|
-
declare global {
|
|
4
|
-
interface Window {
|
|
5
|
-
heap?: $TSFixMe
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
// Define a function that's responsible for sending Segment-related properties to Heap
|
|
10
|
-
// We pass this callback function to Segment's ready method (https://segment.com/docs/sources/website/analytics.js/#ready)
|
|
11
|
-
const segmentReadyCb = function passSegmentKeysToHeap() {
|
|
12
|
-
if (!window.heap) return
|
|
13
|
-
|
|
14
|
-
// Send XID
|
|
15
|
-
if (!localStorage.getItem('seg_heap_xid')) {
|
|
16
|
-
const xId = localStorage.getItem('seg_xid')
|
|
17
|
-
|
|
18
|
-
if (xId) {
|
|
19
|
-
window.heap.addUserProperties({
|
|
20
|
-
'Segment Cross Origin ID': JSON.parse(xId),
|
|
21
|
-
})
|
|
22
|
-
localStorage.setItem('seg_heap_xid', Date.now().toString())
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Send Anonymous ID
|
|
27
|
-
if (!localStorage.getItem('seg_heap_anonymous_id')) {
|
|
28
|
-
const anonId = localStorage.getItem('ajs_anonymous_id')
|
|
29
|
-
|
|
30
|
-
if (anonId) {
|
|
31
|
-
window.heap.addUserProperties({
|
|
32
|
-
'Segment Dotcom Anonymous ID': JSON.parse(anonId),
|
|
33
|
-
})
|
|
34
|
-
localStorage.setItem('seg_heap_anonymous_id', Date.now().toString())
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Version of the segment snippet we're using. This is used by:
|
|
40
|
-
// - SegmentScript
|
|
41
|
-
// - SegmentPreloadScript
|
|
42
|
-
const SNIPPET_VERSION = '4.1.0'
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* This script is provided by Segment
|
|
46
|
-
* - @see https://segment.com/docs/connections/sources/catalog/libraries/website/javascript/quickstart/#step-2-add-the-segment-snippet
|
|
47
|
-
*
|
|
48
|
-
* It has been modified to “preload” the window.analytics API without loading the full `analytics.js` segment script so we can buffer tracking calls before segment fully loads.
|
|
49
|
-
*
|
|
50
|
-
* This has also been modified to use the HashiCorp proxy, artemis.hashicorp.com & custom filename, instead of cdn.segment.com.
|
|
51
|
-
*/
|
|
52
|
-
export const SegmentPreloadScript = () => {
|
|
53
|
-
return (
|
|
54
|
-
<script
|
|
55
|
-
dangerouslySetInnerHTML={{
|
|
56
|
-
__html: `!function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on"];analytics.factory=function(t){return function(){var e=Array.prototype.slice.call(arguments);e.unshift(t);analytics.push(e);return analytics}};for(var t=0;t<analytics.methods.length;t++){var e=analytics.methods[t];analytics[e]=analytics.factory(e)}analytics.load=function(t,e){var n=document.createElement("script");n.type="text/javascript";n.async=!0;n.src="https://artemis.hashicorp.com/script/"+t;var a=document.getElementsByTagName("script")[0];a.parentNode.insertBefore(n,a);analytics._loadOptions=e};analytics._cdn="https://artemis.hashicorp.com";analytics.SNIPPET_VERSION="${SNIPPET_VERSION}";}}();`,
|
|
57
|
-
}}
|
|
58
|
-
/>
|
|
59
|
-
)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export default function SegmentScript({ preferences, writeKey }) {
|
|
63
|
-
if (!preferences.loadAll && !preferences.segment) return null
|
|
64
|
-
|
|
65
|
-
const integrations = Object.assign(
|
|
66
|
-
{ All: Boolean(preferences.loadAll), 'Segment.io': true },
|
|
67
|
-
preferences.segment ?? {}
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
return (
|
|
71
|
-
<Script id="segment">
|
|
72
|
-
{/**
|
|
73
|
-
* @note This snippet is provided by Segment and has been modified to
|
|
74
|
-
* use artemis.hashicorp.com instead of cdn.segment.com.
|
|
75
|
-
*
|
|
76
|
-
* @see https://segment.com/docs/connections/sources/catalog/libraries/website/javascript/quickstart/#step-2-add-the-segment-snippet
|
|
77
|
-
*/}
|
|
78
|
-
{`!function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on"];analytics.factory=function(t){return function(){var e=Array.prototype.slice.call(arguments);e.unshift(t);analytics.push(e);return analytics}};for(var t=0;t<analytics.methods.length;t++){var e=analytics.methods[t];analytics[e]=analytics.factory(e)}analytics.load=function(t,e){var n=document.createElement("script");n.type="text/javascript";n.async=!0;n.src="https://artemis.hashicorp.com/script/"+t;var a=document.getElementsByTagName("script")[0];a.parentNode.insertBefore(n,a);analytics._loadOptions=e};analytics._cdn="https://artemis.hashicorp.com";analytics.SNIPPET_VERSION="${SNIPPET_VERSION}";
|
|
79
|
-
analytics.load("${writeKey}", ${
|
|
80
|
-
integrations ? JSON.stringify({ integrations: integrations }) : {}
|
|
81
|
-
});
|
|
82
|
-
analytics.page();
|
|
83
|
-
analytics.ready(${segmentReadyCb});
|
|
84
|
-
}}();`}
|
|
85
|
-
</Script>
|
|
86
|
-
)
|
|
87
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { ScriptProps } from 'next/script'
|
|
2
|
-
export interface ConsentManagerService {
|
|
3
|
-
async?: boolean
|
|
4
|
-
strategy?: Pick<ScriptProps, 'strategy'>
|
|
5
|
-
body?: string
|
|
6
|
-
category: string
|
|
7
|
-
description: string
|
|
8
|
-
name: string
|
|
9
|
-
url?: string
|
|
10
|
-
dataAttrs?: { name: string; value: string }[]
|
|
11
|
-
/**
|
|
12
|
-
* Optional function that determines whether
|
|
13
|
-
* or not the script will load on the page.
|
|
14
|
-
* If left undefined, script will load as usual.
|
|
15
|
-
*/
|
|
16
|
-
shouldLoad?: () => boolean
|
|
17
|
-
/**
|
|
18
|
-
* Optional function that runs when a script has
|
|
19
|
-
* finished loading.
|
|
20
|
-
* Docs: https://nextjs.org/docs/pages/api-reference/components/script#onload
|
|
21
|
-
*/
|
|
22
|
-
onLoad?: () => void
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface ConsentManagerPreset {
|
|
26
|
-
additionalServices: ConsentManagerService[]
|
|
27
|
-
segmentServices: ConsentManagerService[]
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface ConsentManagerCategory {
|
|
31
|
-
description: string
|
|
32
|
-
name: string
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface ConsentManagerProps {
|
|
36
|
-
additionalServices?: ConsentManagerService[]
|
|
37
|
-
categories?: ConsentManagerCategory[]
|
|
38
|
-
className?: string
|
|
39
|
-
companyName?: string
|
|
40
|
-
cookiePolicyLink?: string
|
|
41
|
-
forceShow?: boolean
|
|
42
|
-
privacyPolicyLink?: string
|
|
43
|
-
segmentServices?: ConsentManagerService[]
|
|
44
|
-
segmentWriteKey?: string
|
|
45
|
-
showDialog?: boolean
|
|
46
|
-
version?: number
|
|
47
|
-
onManagePreferences?: () => void
|
|
48
|
-
onAcceptAll?: () => void
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export interface ConsentManagerPreferences {
|
|
52
|
-
loadAll?: boolean
|
|
53
|
-
segment?: Record<string, boolean>
|
|
54
|
-
custom?: Record<string, boolean>
|
|
55
|
-
}
|