@reykjavik/webtools 0.0.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.
- package/CHANGELOG.md +11 -0
- package/CookieHubConsent.d.ts +231 -0
- package/CookieHubConsent.js +127 -0
- package/README.md +452 -0
- package/esm/CookieHubConsent.d.ts +231 -0
- package/esm/CookieHubConsent.js +99 -0
- package/esm/http.d.ts +82 -0
- package/esm/http.js +125 -0
- package/esm/index.d.ts +6 -0
- package/esm/index.js +1 -0
- package/esm/next/SiteImprove.d.ts +81 -0
- package/esm/next/SiteImprove.js +100 -0
- package/esm/next/http.d.ts +56 -0
- package/esm/next/http.js +81 -0
- package/esm/package.json +1 -0
- package/http.d.ts +82 -0
- package/http.js +129 -0
- package/index.d.ts +6 -0
- package/index.js +2 -0
- package/next/SiteImprove.d.ts +81 -0
- package/next/SiteImprove.js +131 -0
- package/next/http.d.ts +56 -0
- package/next/http.js +103 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
# @reykjavik/webtools
|
|
2
|
+
|
|
3
|
+
> **Warning** This repo is still very much WIP. The npm package has **NOT**
|
|
4
|
+
> been published yet.
|
|
5
|
+
>
|
|
6
|
+
> See [Project Prep TODO](https://github.com/reykjavikcity/webtools/issues/1)
|
|
7
|
+
> for what's planned
|
|
8
|
+
|
|
9
|
+
Miscellaneous JavaScript/TypeScript helpers used by Reykjavík City's web dev
|
|
10
|
+
teams.
|
|
11
|
+
|
|
12
|
+
This library is split up into multple individual modules to help keep your
|
|
13
|
+
bundles slim and aid tree-shaking.
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
yarn add @reykjavik/webtools
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Table of Contents:**
|
|
20
|
+
|
|
21
|
+
<!-- prettier-ignore-start -->
|
|
22
|
+
|
|
23
|
+
- [`@reykjavik/webtools/http`](#reykjavikwebtoolshttp)
|
|
24
|
+
- [HTTP Status Codes](#http-status-codes)
|
|
25
|
+
- [Types for HTTP Status code groups](#types-for-http-status-code-groups)
|
|
26
|
+
- [`cacheControl` helper](#cachecontrol-helper)
|
|
27
|
+
- [Type `TTLConfig`](#type-ttlconfig)
|
|
28
|
+
- [`@reykjavik/webtools/next/http`](#reykjavikwebtoolsnexthttp)
|
|
29
|
+
- [`makeErrorizeAppHOC`](#makeerrorizeapphoc)
|
|
30
|
+
- [`showErrorPage` helper](#showerrorpage-helper)
|
|
31
|
+
- [`notModified304` helper](#notmodified304-helper)
|
|
32
|
+
- [`@reykjavik/webtools/CookieHubConsent`](#reykjavikwebtoolscookiehubconsent)
|
|
33
|
+
- [`CookieHubProvider` component](#cookiehubprovider-component)
|
|
34
|
+
- [`useCookieHubConsent`](#usecookiehubconsent)
|
|
35
|
+
- [`@reykjavik/webtools/next/SiteImprove`](#reykjavikwebtoolsnextsiteimprove)
|
|
36
|
+
- [`SiteImprove` component](#siteimprove-component)
|
|
37
|
+
- [`pingSiteImprove` helper](#pingsiteimprove-helper)
|
|
38
|
+
- [Changelog](#changelog)
|
|
39
|
+
|
|
40
|
+
<!-- prettier-ignore-start -->
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## `@reykjavik/webtools/http`
|
|
45
|
+
|
|
46
|
+
Various framework agnostic helpers for leveraging HTTP magic.
|
|
47
|
+
|
|
48
|
+
### HTTP Status Codes
|
|
49
|
+
|
|
50
|
+
The most common HTTP status codes are exported with human-readable names.
|
|
51
|
+
|
|
52
|
+
- `HTTP_200_OK`
|
|
53
|
+
- `HTTP_201_Created`
|
|
54
|
+
- `HTTP_202_Accepted`
|
|
55
|
+
- `HTTP_301_MovedPermanently`
|
|
56
|
+
- `HTTP_302_Found`
|
|
57
|
+
- `HTTP_303_SeeOther`
|
|
58
|
+
- `HTTP_304_NotModified`
|
|
59
|
+
- `HTTP_307_TemporaryRedirect`
|
|
60
|
+
- `HTTP_308_PermanentRedirect`
|
|
61
|
+
- `HTTP_400_BadRequest`
|
|
62
|
+
- `HTTP_401_Unauthorized`
|
|
63
|
+
- `HTTP_403_Forbidden`
|
|
64
|
+
- `HTTP_404_NotFound`
|
|
65
|
+
- `HTTP_410_Gone`
|
|
66
|
+
- `HTTP_418_ImATeapot`
|
|
67
|
+
- `HTTP_500_InternalServerError`
|
|
68
|
+
|
|
69
|
+
### Types for HTTP Status code groups
|
|
70
|
+
|
|
71
|
+
These type unions are useful when writing HTTP helper functions and error
|
|
72
|
+
handling, etc.
|
|
73
|
+
|
|
74
|
+
- `HTTP_SUCCESS` (2xx)
|
|
75
|
+
- `HTTP_REDIRECTION` (3xx)
|
|
76
|
+
- `HTTP_NOTMODIFIED` (304)
|
|
77
|
+
- `HTTP_CLIENT_ERROR` (4xx)
|
|
78
|
+
- `HTTP_NOT_FOUND` (400, 404)
|
|
79
|
+
- `HTTP_BANNED` (401, 403)
|
|
80
|
+
- `HTTP_SERVER_ERROR` (5xx)
|
|
81
|
+
- `HTTP_ERROR` (4xx, 5xx)
|
|
82
|
+
- `HTTP_STATUS` (all of the above)
|
|
83
|
+
|
|
84
|
+
### `cacheControl` helper
|
|
85
|
+
|
|
86
|
+
**Syntax:**
|
|
87
|
+
`cacheConrol(response: ServerResponse | { res: ServerResponse }, ttlCfg: TTLConfig, eTag?: string|number): void`
|
|
88
|
+
|
|
89
|
+
Use this function to quickly set the `Cache-Control` header with a `max-age=`
|
|
90
|
+
on a HTTP response.
|
|
91
|
+
|
|
92
|
+
```js
|
|
93
|
+
import { cacheControl } from '@reykjavik/webtools/http';
|
|
94
|
+
|
|
95
|
+
// ...then inside an API handler
|
|
96
|
+
// or a framework's data loader function
|
|
97
|
+
cacheControl(res, '4h');
|
|
98
|
+
// ...then set statusCode and send data
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The directives `private` and `immutable` are used by by default.
|
|
102
|
+
|
|
103
|
+
Use the optional `eTag` parameter if you intend to
|
|
104
|
+
[handle conditional requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/Conditional_requests).
|
|
105
|
+
|
|
106
|
+
#### Type `TTLConfig`
|
|
107
|
+
|
|
108
|
+
```js
|
|
109
|
+
import type { TTLConfig } from '@reykjavik/webtools/http';
|
|
110
|
+
|
|
111
|
+
const myTTL1: TTLConfig = '4s';
|
|
112
|
+
const myTTL2: TTLConfig = { maxAge: '4s' };
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The `ttlCfg` parameter is either a bare `TTL` (max-age) value:
|
|
116
|
+
|
|
117
|
+
- `number` — seconds
|
|
118
|
+
- `"${number}${'s'|'m'|'h'|'d'|'w'}"` — gets converted to seconds
|
|
119
|
+
|
|
120
|
+
…one of these `TTLKeywords`:
|
|
121
|
+
|
|
122
|
+
- `"permanent"` — an alias for `maxAge: '365d'`
|
|
123
|
+
- `"no-cache"` — disables caching
|
|
124
|
+
- `"unset"` — removes the header altogether
|
|
125
|
+
|
|
126
|
+
…or a more complex `TTLConfig` object with the following properties:
|
|
127
|
+
|
|
128
|
+
**`TTLConfig.maxAge: TTL | TTLKeywords`** (required)
|
|
129
|
+
|
|
130
|
+
Sets the `max-age=` directive. See above definitions
|
|
131
|
+
|
|
132
|
+
(NOTE: Second values of zero or less get converted to `"no-cache"`.)
|
|
133
|
+
|
|
134
|
+
**`TTLConfig.staleWhileRevalidate?: TTL`**
|
|
135
|
+
|
|
136
|
+
If set to a positive value then `stale-while-revalidate=` is added to the
|
|
137
|
+
response header
|
|
138
|
+
|
|
139
|
+
**`TTLConfig.staleIfError?: TTL`**
|
|
140
|
+
|
|
141
|
+
If set to a positive value then `stale-if-error=` is added to the response
|
|
142
|
+
header
|
|
143
|
+
|
|
144
|
+
**`TTLConfig.publ?: boolean`**
|
|
145
|
+
|
|
146
|
+
Sets the response caching as "public", instead of the default "private"
|
|
147
|
+
|
|
148
|
+
**`TTLConfig.stability?: 'revalidate' | 'immutable' | 'normal'`**
|
|
149
|
+
|
|
150
|
+
Allows setting a "must-revalidate" flag instead of the default "immutable". A
|
|
151
|
+
value of `"normal"` omits the flagging and falls back to HTTP's default
|
|
152
|
+
behavior.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## `@reykjavik/webtools/next/http`
|
|
157
|
+
|
|
158
|
+
Contains HTTP helpers for Next.js projects
|
|
159
|
+
|
|
160
|
+
Re-exports all of the base [http module](#reykjaviktoolshttp)'s exports, for
|
|
161
|
+
convenience
|
|
162
|
+
|
|
163
|
+
### `makeErrorizeAppHOC`
|
|
164
|
+
|
|
165
|
+
**Syntax:**
|
|
166
|
+
`makeErrorizeAppHOC(ErrorPageComponent: ComponentType<EP>): (App: AppType<P>) => AppType<P | EP>`
|
|
167
|
+
|
|
168
|
+
Hhigher-order component (HOC) factory for Next.js App compnents to handle
|
|
169
|
+
cases when `getServerSideProps` returns an `__error` prop with `statusCode`
|
|
170
|
+
and optional friendly `message`.
|
|
171
|
+
|
|
172
|
+
Pass in an error-page compnent, and receive a HOC function that wraps any
|
|
173
|
+
Next.js App compnent. The HOC also has a type-safe
|
|
174
|
+
[`.showErrorPage`](#showerrorizedpage-helper) helper method to use inside
|
|
175
|
+
`getServerSideProps` in order to trigger display of the error page.
|
|
176
|
+
|
|
177
|
+
Set up the error page for your app:
|
|
178
|
+
|
|
179
|
+
```tsx
|
|
180
|
+
// src/helpers/myerrors.js
|
|
181
|
+
|
|
182
|
+
import {
|
|
183
|
+
makeErrorizeAppHOC,
|
|
184
|
+
ErrorProps,
|
|
185
|
+
InferErrorPageProps,
|
|
186
|
+
} from '@reykjavik/webtools/next/http';
|
|
187
|
+
|
|
188
|
+
type MyErrorPageProps = ErrorProps & {
|
|
189
|
+
/* ...custom props... */
|
|
190
|
+
};
|
|
191
|
+
const MyErrorPage = (props: MyErrorPageProps) => {
|
|
192
|
+
const { statusCode, message /* plus your custom props */ } = props;
|
|
193
|
+
return (
|
|
194
|
+
<div>
|
|
195
|
+
<h1>{statusCode}</h1>
|
|
196
|
+
{message && <p>{message}</p>}
|
|
197
|
+
</div>
|
|
198
|
+
);
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// Generate and export the HOC
|
|
202
|
+
export const withMyErrorHandling = makeErrorizeAppHOC(MyErrorPage);
|
|
203
|
+
// Export the gSSP helper
|
|
204
|
+
export const showErrorPage = withMyErrorHandling.showErrorPage;
|
|
205
|
+
// Export the props type of the error page
|
|
206
|
+
export type ErrorPageProps = InferErrorPageProps<typeof showErrorPage>;
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Wrap `_app.tsx` with the HOC you generated:
|
|
210
|
+
|
|
211
|
+
```jsx
|
|
212
|
+
// src/pages/_app.js
|
|
213
|
+
|
|
214
|
+
import { withMyErrorHandling } from '~/helpers/myerrors';
|
|
215
|
+
|
|
216
|
+
const App = ({ Component, pageProps }: AppProps<PageProps>) => {
|
|
217
|
+
// ...define your App component as normal...
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
export default withMyErrorHandling(App);
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Return errors inside your page/route modules, using `showErrorPage`
|
|
224
|
+
|
|
225
|
+
```tsx
|
|
226
|
+
// src/pages/index.js
|
|
227
|
+
|
|
228
|
+
import type { GetServerSideProps } from 'next';
|
|
229
|
+
import { showErrorPage, ErrorPageProps } from '~/helpers/errors';
|
|
230
|
+
|
|
231
|
+
type MyPageProps = {};
|
|
232
|
+
// Export the page component
|
|
233
|
+
export default function MyPage(props: MyPageProps) {
|
|
234
|
+
// ...
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export const getServerSideProps: GetServerSideProps<
|
|
238
|
+
MyPageProps | ErrorPageProps
|
|
239
|
+
> = async (ctx) => {
|
|
240
|
+
// ...fetch data from api
|
|
241
|
+
if (!apiRes.error === 'unauthorized') {
|
|
242
|
+
return showErrorPage(ctx.res, {
|
|
243
|
+
statusCode: HTTP_400_BadRequest,
|
|
244
|
+
// ...Add other custom MyErrorPage props
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
// ...return normal, happy page props.
|
|
248
|
+
};
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
See more below
|
|
252
|
+
|
|
253
|
+
### `showErrorPage` helper
|
|
254
|
+
|
|
255
|
+
**Syntax:**
|
|
256
|
+
`showErrorPage = (response: ServerResponse | NextContext, error: HTTP_ERROR | ErrorProps, ttl?: TTL | TTLConfig): void`
|
|
257
|
+
|
|
258
|
+
This method is attached to the HOC returned by
|
|
259
|
+
[`makeErrorizeAppHOC`](#makeerrorizeapphoc). Use it inside your pages'
|
|
260
|
+
`getServerSideProps` to return the appropriate an "error" props, including a
|
|
261
|
+
HTTP `statusCode`, etc.
|
|
262
|
+
|
|
263
|
+
```js
|
|
264
|
+
import { showErrorPage, ErrorPageProps } from '~/helpers/myerrors';
|
|
265
|
+
|
|
266
|
+
// ...then, somewhere inside getServerSideProps
|
|
267
|
+
if (invalidParams) {
|
|
268
|
+
return showErrorPage(
|
|
269
|
+
res,
|
|
270
|
+
{
|
|
271
|
+
statusCode: HTTP_400_BadRequest,
|
|
272
|
+
message: 'You passed me bad params :-(', // optional message
|
|
273
|
+
// ...Add other custom MyErrorPage props
|
|
274
|
+
},
|
|
275
|
+
'permanent'
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (!apiRes.error === 'unauthorized') {
|
|
280
|
+
// Optional `statusCode` shorthand signature, available if your
|
|
281
|
+
// error page has no required props (other than `statusCode`).
|
|
282
|
+
return showErrorPage(res, HTTP_403_Forbidden);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// ...return normal, happy page props.
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
The `ttl` parameter defaults to `'2s'`, but you can pass any
|
|
289
|
+
[`TTLConfig`](#type-ttlconfig).
|
|
290
|
+
|
|
291
|
+
### `notModified304` helper
|
|
292
|
+
|
|
293
|
+
**Syntax:** `notModified304(response: ServerResponse | NextContext): void`
|
|
294
|
+
|
|
295
|
+
Use this method to inside a `getServerSideProps` method (or API route) to
|
|
296
|
+
return a `HTTP_304_NotModified` response with an empty props object, in a way
|
|
297
|
+
that doesn't make TypeScript shout at you.
|
|
298
|
+
|
|
299
|
+
(Turns out that when a 304 status is returned, then Next.js doesn't even
|
|
300
|
+
attempt to render the Page compnoent, so the returned props don't matter.
|
|
301
|
+
TypeScript, however, doesn't know that.)
|
|
302
|
+
|
|
303
|
+
```js
|
|
304
|
+
import { notModified304 } from '@reykjavik/webtools/next/http';
|
|
305
|
+
|
|
306
|
+
// ...then, somewhere inside getServerSideProps
|
|
307
|
+
const notModified = data.modifiedTimestamp === req.headers['if-none-match'];
|
|
308
|
+
if (notModified) {
|
|
309
|
+
return notModified304(res);
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## `@reykjavik/webtools/CookieHubConsent`
|
|
316
|
+
|
|
317
|
+
Contains React helpers for loading CookieHub's consent manager and reading
|
|
318
|
+
users' consent values.
|
|
319
|
+
|
|
320
|
+
### `CookieHubProvider` component
|
|
321
|
+
|
|
322
|
+
This context provider component loads and initialises the CookieHub consent
|
|
323
|
+
management script and sets up a React state object with the relevant user
|
|
324
|
+
consent flags.
|
|
325
|
+
|
|
326
|
+
Wrap this provider around your component tree, and then use the
|
|
327
|
+
[`useCookieHubConsent()` hook](#usecookiehubconsent) to retrieve live consent
|
|
328
|
+
information, whereever you wish to set GDPR-affected cookies or perform any
|
|
329
|
+
sort of tracking/logging.
|
|
330
|
+
|
|
331
|
+
```js
|
|
332
|
+
import { CookieHubProvider } from '@reykjavik/webtools/CookieHubConsent';
|
|
333
|
+
|
|
334
|
+
import { AnalyticsStuff } from '../components/AnalyticsStuff';
|
|
335
|
+
|
|
336
|
+
// Maybe move this to an Env variable, or something...
|
|
337
|
+
const cookiehubAccountId = '[ACCOUNT_ID]'; // e.g. "a4b3c2d1"
|
|
338
|
+
|
|
339
|
+
export default function App() {
|
|
340
|
+
return (
|
|
341
|
+
<CookieHubProvider accountId={cookiehubAccountId}>
|
|
342
|
+
<div>
|
|
343
|
+
<p>...my App UI...</p>
|
|
344
|
+
<AnalyticsStuff />
|
|
345
|
+
</div>
|
|
346
|
+
</CookieHubProvider>
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
**Props:**
|
|
352
|
+
|
|
353
|
+
The Component's props have detailed JSDoc comments (displayed in your code
|
|
354
|
+
editor), but there's a brief summary:
|
|
355
|
+
|
|
356
|
+
- `accountId?: string` — Your CookieHub account ID. (alternative to
|
|
357
|
+
`scriptUrl` prop).
|
|
358
|
+
- `scriptUrl?: string` — The full CookieHub embed script URL. (alternative to
|
|
359
|
+
`accountId` prop).
|
|
360
|
+
- `options?: CookieHubOptions` — Raw CookieHub options object that gets used
|
|
361
|
+
when the script initializes.
|
|
362
|
+
- `onError?: OnErrorEventHandlerNonNull` — Fires if loading the script failed.
|
|
363
|
+
|
|
364
|
+
### `useCookieHubConsent`
|
|
365
|
+
|
|
366
|
+
**Syntax:** `useCookieHubConsent(): Record<CookieHubCategory, boolean>`
|
|
367
|
+
|
|
368
|
+
Returns up-to-date cookie consent `boolean` flags. For use in React components
|
|
369
|
+
or hook functions.
|
|
370
|
+
|
|
371
|
+
```js
|
|
372
|
+
import { useCookieHubConsent } from '@reykjavik/webtools/CookieHubConsent';
|
|
373
|
+
|
|
374
|
+
export const AnalyticsStuff = (props) => {
|
|
375
|
+
const consent = useCookieHubConsent();
|
|
376
|
+
if (!consent.analytics) {
|
|
377
|
+
return null;
|
|
378
|
+
}
|
|
379
|
+
// Perform analytics...
|
|
380
|
+
};
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
If the `CookieHubProvider` is missing from the VDOM tree above your component,
|
|
384
|
+
this hook will return an empty object.
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## `@reykjavik/webtools/next/SiteImprove`
|
|
389
|
+
|
|
390
|
+
Contains React helpers for loading SiteImprove's analytics scripts in Next.js
|
|
391
|
+
applications and perform custom event tracking.
|
|
392
|
+
|
|
393
|
+
### `SiteImprove` component
|
|
394
|
+
|
|
395
|
+
A component for loading a SiteImprove analytics script and set up page-view
|
|
396
|
+
tracking across Next.js routes.
|
|
397
|
+
|
|
398
|
+
```js
|
|
399
|
+
import { SiteImprove } from '@reykjavik/webtools/next/SiteImprove';
|
|
400
|
+
|
|
401
|
+
const siteImproveAccountId = '[ACCOUNT_ID]'; // e.g. "7654321"
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
The component has an optional `hasConsented` prop which can be used to
|
|
405
|
+
forcefully suppress loading the analytics script.
|
|
406
|
+
|
|
407
|
+
In dev mode it does NOT load the SiteImprove script and only logs page-view
|
|
408
|
+
events to the console.
|
|
409
|
+
|
|
410
|
+
**Props:**
|
|
411
|
+
|
|
412
|
+
The Component's props have detailed JSDoc comments (displayed in your code
|
|
413
|
+
editor), but there's a brief summary:
|
|
414
|
+
|
|
415
|
+
- `accountId?: string` — Your SiteImprove account ID. (alternative to
|
|
416
|
+
`scriptUrl` prop).
|
|
417
|
+
- `scriptUrl?: string` — The full SiteImprove analytics script URL.
|
|
418
|
+
(alternative to `accountId` prop).
|
|
419
|
+
- `hasConstented?: boolean` — Manual GDPR 'analytics' consent flag. Allows
|
|
420
|
+
hard opt-out, but defers to
|
|
421
|
+
[`CookieHubProvider` values](#usecookiehubconsent) by default.
|
|
422
|
+
- `onLoad?: (e: unknown) => void` — Fires when the script has loaded.
|
|
423
|
+
- `onError?: (e: unknown) => void` — Fires if loading the script failed.
|
|
424
|
+
|
|
425
|
+
### `pingSiteImprove` helper
|
|
426
|
+
|
|
427
|
+
**Syntax:**
|
|
428
|
+
`pingSiteImprove(category: string, action: string, label?: string): void`
|
|
429
|
+
|
|
430
|
+
A small helper for tracking custom UI events and reporting them to SiteImrove.
|
|
431
|
+
|
|
432
|
+
It safely manages GDPR consent, so you can use it unconditionally.
|
|
433
|
+
|
|
434
|
+
```js
|
|
435
|
+
import { pingSiteImprove } from '@reykjavik/webtools/next/SiteImprove';
|
|
436
|
+
|
|
437
|
+
const handleSubmit = () => {
|
|
438
|
+
// perform submit action...
|
|
439
|
+
if (success) {
|
|
440
|
+
pingSiteImprove('application', 'add_new');
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
In dev mode it only logs tracking events to the console.
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
## Changelog
|
|
450
|
+
|
|
451
|
+
See
|
|
452
|
+
[CHANGELOG.md](https://github.com/reykjavikcity/webtools/blob/main/CHANGELOG.md)
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { EitherObj } from '@reykjavik/hanna-utils';
|
|
3
|
+
declare global {
|
|
4
|
+
interface Window {
|
|
5
|
+
cookiehub: CookieHub;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
type CookieHub = {
|
|
9
|
+
/**
|
|
10
|
+
* Used to initialize, and configure, CookieHub.
|
|
11
|
+
*
|
|
12
|
+
* (Thin wrapper for `window.cookiehub.initialize`)
|
|
13
|
+
*
|
|
14
|
+
* @see https://support.cookiehub.com/article/86-methods-functions
|
|
15
|
+
*/
|
|
16
|
+
load(options?: CookieHubOptions): void;
|
|
17
|
+
/**
|
|
18
|
+
* Used to initialize, and configure, CookieHub.
|
|
19
|
+
*
|
|
20
|
+
* @see https://support.cookiehub.com/article/86-methods-functions
|
|
21
|
+
*/
|
|
22
|
+
initialize(options?: CookieHubOptions): void;
|
|
23
|
+
/**
|
|
24
|
+
* Used to check if the user has already made cookie choices.
|
|
25
|
+
*
|
|
26
|
+
* @see https://support.cookiehub.com/article/86-methods-functions
|
|
27
|
+
*/
|
|
28
|
+
hasAnswered(): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Used to check if the user has allowed the cookie category specified in
|
|
31
|
+
* the category parameter.
|
|
32
|
+
*
|
|
33
|
+
* @see https://support.cookiehub.com/article/86-methods-functions
|
|
34
|
+
*/
|
|
35
|
+
hasConsented(category: CookieHubCategory): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Used to check if the CookieHub script has been initialized
|
|
38
|
+
*
|
|
39
|
+
* @see https://support.cookiehub.com/article/86-methods-functions
|
|
40
|
+
*/
|
|
41
|
+
hasInitialized(): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Open the CookieHub dialog.
|
|
44
|
+
*
|
|
45
|
+
* @see https://support.cookiehub.com/article/86-methods-functions
|
|
46
|
+
*/
|
|
47
|
+
openDialog(): void;
|
|
48
|
+
/**
|
|
49
|
+
* Close the CookieHub dialog if it's still open.
|
|
50
|
+
*
|
|
51
|
+
* @see https://support.cookiehub.com/article/86-methods-functions
|
|
52
|
+
*/
|
|
53
|
+
closeDialog(): void;
|
|
54
|
+
/**
|
|
55
|
+
* Open the CookieHub settings dialog. This may be useful if you choose to
|
|
56
|
+
* hide the settings icon which is usually used to open the CookieHub
|
|
57
|
+
* settings dialog and want to create a custom link or button to open the
|
|
58
|
+
* dialog instead.
|
|
59
|
+
*
|
|
60
|
+
* @see https://support.cookiehub.com/article/86-methods-functions
|
|
61
|
+
*/
|
|
62
|
+
openSettings(): void;
|
|
63
|
+
/**
|
|
64
|
+
* Close the CookieHub settings dialog.
|
|
65
|
+
*
|
|
66
|
+
* @see https://support.cookiehub.com/article/86-methods-functions
|
|
67
|
+
*/
|
|
68
|
+
closeSettings(): void;
|
|
69
|
+
/**
|
|
70
|
+
* Denys all cookie categories.
|
|
71
|
+
*
|
|
72
|
+
* @see https://support.cookiehub.com/article/86-methods-functions
|
|
73
|
+
*/
|
|
74
|
+
denyAll(): void;
|
|
75
|
+
/**
|
|
76
|
+
* Allows all cookie categories.
|
|
77
|
+
*
|
|
78
|
+
* @see https://support.cookiehub.com/article/86-methods-functions
|
|
79
|
+
*/
|
|
80
|
+
allowAll(): void;
|
|
81
|
+
};
|
|
82
|
+
type CookieHubCategory = 'necessary' | 'preferences' | 'analytics' | 'marketing' | 'uncategorized';
|
|
83
|
+
type CookieHubOptions = {
|
|
84
|
+
/**
|
|
85
|
+
* Fired when CookieHub has finished loading.
|
|
86
|
+
*
|
|
87
|
+
* @see https://support.cookiehub.com/article/87-events
|
|
88
|
+
*/
|
|
89
|
+
onInitialise?: (this: CookieHub, status: CookiehubState) => void;
|
|
90
|
+
/**
|
|
91
|
+
* Fired any time users make changes to cookie choices and click the
|
|
92
|
+
* Save Settings or if the Allow All Cookies button is clicked.
|
|
93
|
+
*
|
|
94
|
+
* @see https://support.cookiehub.com/article/87-events
|
|
95
|
+
*/
|
|
96
|
+
onStatusChange?: (this: CookieHub, status: CookiehubState, previousStatus: CookiehubState) => void;
|
|
97
|
+
/**
|
|
98
|
+
* Fired any time a cookie category is allowed that was previously disallowed.
|
|
99
|
+
*
|
|
100
|
+
* @see https://support.cookiehub.com/article/87-events
|
|
101
|
+
*/
|
|
102
|
+
onAllow?: (this: CookieHub, category: CookieHubCategory) => void;
|
|
103
|
+
/**
|
|
104
|
+
* Fired any time a cookie category consent is revoked for a category that
|
|
105
|
+
* was previously allowed.
|
|
106
|
+
*
|
|
107
|
+
* @see https://support.cookiehub.com/article/87-events
|
|
108
|
+
*/
|
|
109
|
+
onRevoke?: (this: CookieHub, category: CookieHubCategory) => void;
|
|
110
|
+
dialog?: {
|
|
111
|
+
/**
|
|
112
|
+
* Controls the display of the action buttons in the popup dialog.
|
|
113
|
+
*
|
|
114
|
+
* @see https://support.cookiehub.com/article/128-changing-the-order-of-action-buttons
|
|
115
|
+
*/
|
|
116
|
+
actions?: Array<'allow' | 'deny' | 'settings'>;
|
|
117
|
+
};
|
|
118
|
+
cookie?: {
|
|
119
|
+
/**
|
|
120
|
+
* Empty string (`''`) will instruct the browser to set the cookie on
|
|
121
|
+
* the current domain instead of the top level domain which is the
|
|
122
|
+
* default value.
|
|
123
|
+
*
|
|
124
|
+
* @see https://support.cookiehub.com/article/85-cookiehub-on-multiple-domains-hosts
|
|
125
|
+
*/
|
|
126
|
+
domain?: string;
|
|
127
|
+
/**
|
|
128
|
+
* Controls the cookie behavior and access for the cookiehub cookie
|
|
129
|
+
*
|
|
130
|
+
* Possible values are:
|
|
131
|
+
*
|
|
132
|
+
* - **Lax** (Default): Allows pages on the domain and third party links
|
|
133
|
+
* to access the cookie. This is the default setting for CookieHub.
|
|
134
|
+
* - **Strict**: Only allows pages on the domain that set the cookie to
|
|
135
|
+
* access it. Links from third parties won’t be able to access the
|
|
136
|
+
* cookie.
|
|
137
|
+
* - **None**: No domain limitations and third-party cookies can fire.
|
|
138
|
+
*
|
|
139
|
+
* @see https://support.cookiehub.com/article/84-cookie-security-and-the-samesite-attribute
|
|
140
|
+
*/
|
|
141
|
+
sameSite?: 'Strict' | 'Lax' | 'None';
|
|
142
|
+
/**
|
|
143
|
+
* If the Secure attribute is set to true, the cookie will only be accessible
|
|
144
|
+
* if the page being loaded is loaded over a secure connection.
|
|
145
|
+
*
|
|
146
|
+
* Defaults to `false` but it's recommended to set it to true
|
|
147
|
+
*
|
|
148
|
+
* @see https://support.cookiehub.com/article/84-cookie-security-and-the-samesite-attribute
|
|
149
|
+
*/
|
|
150
|
+
secure?: boolean;
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
type CookiehubState = {
|
|
154
|
+
answered: boolean;
|
|
155
|
+
preconsent: boolean;
|
|
156
|
+
revision: number;
|
|
157
|
+
dnt: boolean;
|
|
158
|
+
allowSale: boolean;
|
|
159
|
+
implict: boolean;
|
|
160
|
+
region: string;
|
|
161
|
+
token: string;
|
|
162
|
+
timestamp: Date;
|
|
163
|
+
categories: Array<CookieHubCategoryState>;
|
|
164
|
+
};
|
|
165
|
+
type CookieHubCategoryState = {
|
|
166
|
+
cid: number;
|
|
167
|
+
id: CookieHubCategory;
|
|
168
|
+
value: boolean;
|
|
169
|
+
preconsent: boolean;
|
|
170
|
+
fired: boolean;
|
|
171
|
+
};
|
|
172
|
+
type CookieHubContextState = {
|
|
173
|
+
consent: Record<Exclude<CookieHubCategory, 'necessary'>, boolean>;
|
|
174
|
+
};
|
|
175
|
+
export type CookieHubProviderProps = EitherObj<{
|
|
176
|
+
/**
|
|
177
|
+
* Yuour CookieHub account ID.
|
|
178
|
+
*
|
|
179
|
+
* It's a random-looking alpha-numerical string, and it can usually be
|
|
180
|
+
* extracted from the script embed URL like this:
|
|
181
|
+
* `"https://cookiehub.net/c2/[ACCOUNT_ID].js"`
|
|
182
|
+
*
|
|
183
|
+
* @see https://support.cookiehub.com/article/155-manual-implementation-guide
|
|
184
|
+
*/
|
|
185
|
+
accountId: string;
|
|
186
|
+
}, {
|
|
187
|
+
/**
|
|
188
|
+
* The full CookieHub embed script URL.
|
|
189
|
+
*
|
|
190
|
+
* Something like `"https://cookiehub.net/c2/[ACCOUNT_ID].js"`
|
|
191
|
+
*
|
|
192
|
+
* @see https://support.cookiehub.com/article/155-manual-implementation-guide
|
|
193
|
+
*/
|
|
194
|
+
scriptUrl: string;
|
|
195
|
+
}> & {
|
|
196
|
+
children: ReactNode;
|
|
197
|
+
/**
|
|
198
|
+
* Custom callback that fires when CookieHub has initialized.
|
|
199
|
+
*
|
|
200
|
+
* To subscribe to other events run:
|
|
201
|
+
*
|
|
202
|
+
* ```js
|
|
203
|
+
* window.cookiehub.initialize({
|
|
204
|
+
* // Event handlers other than `onInitialize`
|
|
205
|
+
* })
|
|
206
|
+
* ```
|
|
207
|
+
*
|
|
208
|
+
* @see https://support.cookiehub.com/article/87-events
|
|
209
|
+
*/
|
|
210
|
+
options?: CookieHubOptions;
|
|
211
|
+
/**
|
|
212
|
+
* Error callback for if the CookieHub script fails to load.
|
|
213
|
+
*/
|
|
214
|
+
onError?: OnErrorEventHandlerNonNull;
|
|
215
|
+
};
|
|
216
|
+
/**
|
|
217
|
+
* This context provider component loads and initialises the CookieHub consent
|
|
218
|
+
* management script and sets up a React state object with the relevant user
|
|
219
|
+
* consent flags.
|
|
220
|
+
*
|
|
221
|
+
* @see https://github.com/reykjavikcity/webtools/tree/v0.1##cookiehubprovider-component
|
|
222
|
+
*/
|
|
223
|
+
export declare const CookieHubProvider: (props: CookieHubProviderProps) => JSX.Element;
|
|
224
|
+
/**
|
|
225
|
+
* Returns up-to-date cookie consent flags. For use in React components or hook
|
|
226
|
+
* functions.
|
|
227
|
+
*
|
|
228
|
+
* @see https://github.com/reykjavikcity/webtools/tree/v0.1##usecookiehubconsent
|
|
229
|
+
*/
|
|
230
|
+
export declare const useCookieHubConsent: () => Partial<CookieHubContextState['consent']>;
|
|
231
|
+
export {};
|