@croct/plug-react 0.8.0 โ†’ 0.9.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/README.md CHANGED
@@ -1,863 +1,55 @@
1
- ![Plug React](https://user-images.githubusercontent.com/943036/213265380-8ad0a5f7-063a-495f-ab2e-0d5a238d8424.png)
2
-
1
+ <p align="center">
2
+ <a href="https://croct.com" target="_blank">
3
+ <picture>
4
+ <source media="(min-width: 769px) and (prefers-color-scheme: light)" srcset="https://github.com/croct-tech/plug-js/blob/master/.github/assets/header-light.svg">
5
+ <source media="(min-width: 769px) and (prefers-color-scheme: dark)" srcset="https://github.com/croct-tech/plug-js/blob/master/.github/assets/header-dark.svg">
6
+ <source media="(max-width: 768px) and (prefers-color-scheme: dark)" srcset="https://github.com/croct-tech/plug-js/blob/master/.github/assets/header-dark-mobile.svg">
7
+ <source media="(max-width: 768px) and (prefers-color-scheme: light)" srcset="https://github.com/croct-tech/plug-js/blob/master/.github/assets/header-light-mobile.svg">
8
+ <img src="https://raw.githubusercontent.com/croct-tech/plug-js/refs/heads/update-readme/.github/assets/header-light-mobile.svg" alt="Croct React SDK" title="Croct React SDK" width="100%">
9
+ </picture>
10
+ </a>
11
+ <br/>
12
+ <strong>Croct React SDK</strong><br/>
13
+ Bring dynamic, personalized content natively into your applications.
14
+ </p>
15
+ <div align="center">
16
+ <strong>๐Ÿ“˜ <a href="https://docs.croct.com/reference/sdk/react/installation">Quick start &rarr;</a></strong>
17
+ </div>
18
+ <br/>
3
19
  <p align="center">
4
20
  <a href="https://www.npmjs.com/package/@croct/plug-react"><img alt="Version" src="https://img.shields.io/npm/v/@croct/plug-react"/></a>
5
- <a href="https://github.com/croct-tech/plug-react/actions?query=workflow%3AValidations"><img alt="Build" src="https://github.com/croct-tech/plug-react/workflows/Validations/badge.svg"/></a>
6
- <a href="https://codeclimate.com/repos/60665953e0608a018c001907/maintainability"><img alt="Maintainability" src="https://api.codeclimate.com/v1/badges/24f7d3e788ed2c66f2ab/maintainability"/></a>
7
21
  <a href="https://codeclimate.com/repos/60665953e0608a018c001907/test_coverage"><img alt="Coverage" src="https://api.codeclimate.com/v1/badges/24f7d3e788ed2c66f2ab/test_coverage"/></a>
8
- <br />
9
- <br />
10
- <a href="https://github.com/croct-tech/plug-react/releases">๐Ÿ“ฆ Releases</a>
11
- ยท
12
- <a href="https://github.com/croct-tech/plug-react/issues/new?labels=bug&template=bug-report.md">๐Ÿž Report Bug</a>
13
- ยท
14
- <a href="https://github.com/croct-tech/plug-react/issues/new?labels=enhancement&template=feature-request.md">โœจ Request Feature</a>
15
22
  </p>
16
23
 
17
24
  ## Introduction
18
25
 
19
- The React Plug library provides components and hooks for personalizing applications in real-time that are easy for your
20
- marketing team to scale and maintain.
21
-
22
- - **Easy integration**: personalize existing components without touching their code.
23
- - **Suspense-ready**: take advantage of the latest React features to improve user experience.
24
- - **Server-side rendering**: seamless integration with server-side frameworks like Next.js.
25
- - **Zero configuration**: no setup steps are required.
26
- - **Type-safety**: Typescript typings are included for improved development experience.
27
- - **Blazing-fast queries**: double-digit millisecond latency for real-time evaluations.
28
- - **Playground integration**: one-click to connect, no configuration needed.
29
-
30
- Check out the [Storybook](https://croct-tech.github.io/plug-react) to see some minimal examples in action,
31
- or the [example folder](examples) for full code examples.
32
-
33
- ## Getting Started
34
-
35
- The following steps will walk you through installing the library and integrating it into your application.
26
+ Croct is a headless CMS that helps you manage content, run AB tests, and personalize experiences without the hassle of complex integrations.
36
27
 
37
- > [!TIP]
38
- > If you are using Next.js, head over to the [Plug Next.js](https://github.com/croct-tech/plug-next) library for a more
39
- > integrated experience.
28
+ ## Installation
40
29
 
41
- This guide assumes you're already familiar with some key concepts and tools around Croct, like
42
- Contextual Query Language (CQL) and the playground. If you're not,
43
- [this 15-minute quickstart](https://croct.link/plug-js/quick-start) that will give you a hands-on overview of
44
- all the terms and tools you need to get started.
45
-
46
- ### Installation
47
-
48
- The recommended way to install the library is via [NPM](https://npmjs.com).
49
-
50
- Run the following command to add the client as a dependency to your project and then install it:
30
+ Run this command to install the SDK:
51
31
 
52
32
  ```sh
53
33
  npm install @croct/plug-react
54
34
  ```
35
+ See our [quick start guide](https://docs.croct.com/reference/sdk/react/installation) for more details.
55
36
 
56
- ### Plugging in
57
-
58
- You connect Croct to React with the `<CroctProvider />` component. The `<CroctProvider />` uses a regular React's
59
- `<Context.Provider />` to wrap your React app and make the SDK available anywhere in your component tree.
60
-
61
- We suggest putting the `<CroctProvider />` somewhere high in your app, above any component that might be personalized,
62
- ideally in the top-level `<App/>` component.
63
-
64
- ```tsx
65
- import {render} from 'react-dom';
66
- import {CroctProvider} from '@croct/plug-react';
67
-
68
- function App() {
69
- return (
70
- <CroctProvider appId="<APP_ID>">
71
- <div>
72
- <h1>My first personalized app ๐Ÿš€</h1>
73
- </div>
74
- </CroctProvider>
75
- );
76
- }
77
-
78
- render(<App/>, document.getElementById('root'));
79
- ```
80
-
81
- > Replace `<APP_ID>` with your public app ID that you can find at Workspaces > Applications > Setup.
82
- > In case you don't have an account yet, you can use the sandbox application ID `00000000-0000-0000-0000-000000000000`
83
-
84
- ### Evaluating queries
85
-
86
- Once your application is plugged in, you're ready to start personalizing your components using the `<Personalization />`
87
- component or the `useEvaluation` hook.
88
-
89
- We'll go through a simple example that shows how you can implement feature flags (also known as feature toggles)
90
- to conditionally renders a different button depending on the user's persona.
91
-
92
- ![Evaluation Example](https://user-images.githubusercontent.com/943036/116588852-6a114200-a8f2-11eb-9d88-c346f002e2a1.png)
93
-
94
- Let's first implement the use-case using the `<Personalization />` component. It takes an query (
95
- e.g. `user's persona`)
96
- and a render function, which tells the component how to render the UI, depending on the evaluation result.
97
-
98
- This is what our component would look like:
99
-
100
- ```tsx
101
- import {ReactElement, Suspense} from 'react';
102
- import {Personalization} from '@croct/plug-react';
103
-
104
- function OnboardingPage(): ReactElement {
105
- return (
106
- <Suspense fallback="โœจ Personalizing...">
107
- <Personalization query="user's persona is not 'developer'">
108
- {(isDeveloper: boolean) => isDeveloper
109
- ? <a href="/docs">View docs</a>
110
- : <a href="/share">Share with your developer</a>
111
- }
112
- </Personalization>
113
- </Suspense>
114
- )
115
- }
116
- ```
117
-
118
- If you don't want your component to suspend while loading, you can provide an `initial` state to be rendered instead:
119
-
120
- ```tsx
121
- import {ReactElement} from 'react';
122
- import {Personalization} from '@croct/plug-react';
123
-
124
- function OnboardingPage(): ReactElement {
125
- return (
126
- <Personalization query="user's persona is not 'developer'" initial={false}>
127
- {(isDeveloper: boolean) => isDeveloper
128
- ? <a href="/docs">View docs</a>
129
- : <a href="/share">Share with your developer</a>
130
- }
131
- </Personalization>
132
- )
133
- }
134
- ```
135
-
136
- Now, let's create a `ViewDocsLink` component to see the `useEvaluation` hook in action:
137
-
138
- ```tsx
139
- import {ReactElement, Suspense} from 'react';
140
- import {useEvaluation} from '@croct/plug-react';
141
-
142
- function ViewDocsLink(): ReactElement {
143
- const isDeveloper = useEvaluation<boolean>("user's persona is 'developer'");
144
-
145
- return (
146
- isDeveloper
147
- ? <a href="/docs">View docs</a>
148
- : <a href="/share">Share with your developer</a>
149
- );
150
- }
151
-
152
- export default function OnboardingPage(): ReactElement {
153
- return (
154
- <Suspense fallback="โœจ Personalizing...">
155
- <ViewDocsLink/>
156
- </Suspense>
157
- )
158
- }
159
- ```
160
-
161
- If you run the application and there is no persona assigned to your profile, you will see the button for non-developers
162
- โ€” otherwise, the button for sharing the code with developers.
163
- Check out [Accessing the Plug instance](#accessing-the-plug-instance) for an example of how to save information in a
164
- user's profile.
165
-
166
- #### Fault tolerance
167
-
168
- We strongly recommend specifying the `fallback` property in client-side rendered applications to ensure your app behaves
169
- the same way regardless of the personalization. In this way, the UI will still be fully functional even in maintenance
170
- windows. **Specifying a `fallback` is required for server-side rendering (SSR).**
171
-
172
- The following example shows how you can specify a fallback behaviour for the docs link:
173
-
174
- ```tsx
175
- import {ReactElement, Fragment, Suspense} from 'react';
176
- import {Personalization, useEvaluation} from '@croct/plug-react';
177
-
178
- function ViewDocsLink(): ReactElement {
179
- const isDeveloper = useEvaluation<boolean>("user's persona is 'developer'", {fallback: false});
180
-
181
- return <Fragment>{isDeveloper && <a href="/docs">View docs</a>}</Fragment>
182
- }
183
-
184
- export default function OnboardingPage(): ReactElement {
185
- return (
186
- <Suspense fallback="โœจ Personalizing...">
187
- {/* Using the <Personalization /> component */}
188
- <Personalization query="user's persona is 'developer'" fallback={false}>
189
- {(isDeveloper: boolean) => (
190
- <Fragment>
191
- {isDeveloper && <a href="/docs">View docs</a>}
192
- </Fragment>
193
- )}
194
- </Personalization>
195
-
196
- {/* Using useEvaluation hook */}
197
- <ViewDocsLink/>
198
- </Suspense>
199
- )
200
- }
201
- ```
202
-
203
- For a full list of the available options, please refer to the [API documentation](#component-api-reference).
204
-
205
- ### Using slots
206
-
207
- Evaluating query is a flexible and powerful way to customize your UI. However, for components whose content
208
- changes too often, this approach can be overkill. For those cases, we encourage you to use the Slots feature instead.
209
- Using slots gives your team the flexibility to change the content or personalization rules whenever needed without
210
- touching the component code.
211
-
212
- ![Slot Example](https://user-images.githubusercontent.com/943036/116586841-44833900-a8f0-11eb-8d32-acec2eacee01.png)
213
-
214
- To render a slot, all you need to do is provide the `id` you configured in your Croct workspace. Based on the
215
- slot's personalization rules and the user's context, the component will decide which content show to that user.
216
- Notice that there's no logic on the client-side, meaning that your marketing or product team can freely change the
217
- slot content as they need without requiring an update to your React app.
218
-
219
- For the next example, we assume that you have already defined a slot with id `home-banner` in your Croct workspace
220
- with the following structure:
221
-
222
- ```ts
223
- type HomeBannerContent = {
224
- title: string,
225
- subtitle: string,
226
- cta: {
227
- label: string,
228
- link: string,
229
- },
230
- };
231
- ```
232
-
233
- To render the content of the slot, you can either use the `<Slot />` component or the `useContent` hook.
234
-
235
- Here's how to use the `<Slot />` component:
236
-
237
- ```tsx
238
- import {ReactElement, Suspense} from 'react';
239
- import {Slot} from '@croct/plug-react';
240
-
241
- type HomeBannerContent = {
242
- title: string,
243
- subtitle: string,
244
- cta: {
245
- label: string,
246
- link: string,
247
- },
248
- };
249
-
250
- export default function OnboardingPage(): ReactElement {
251
- return (
252
- <Suspense fallback="โœจ Personalizing content...">
253
- <Slot id="home-banner">
254
- {({
255
- title,
256
- subtitle,
257
- cta
258
- }: HomeBannerContent) => (
259
- <div>
260
- <strong>{title}</strong>
261
- <p>{subtitle}</p>
262
- <a href={cta.link}>{cta.label}</a>
263
- </div>
264
- )}
265
- </Slot>
266
- </Suspense>
267
- )
268
- }
269
- ```
270
-
271
- To avoid the component from suspending while loading, you can provide an `initial` state to be rendered instead:
272
-
273
- ```tsx
274
- import {ReactElement} from 'react';
275
- import {Slot} from '@croct/plug-react';
276
-
277
- type HomeBannerContent = {
278
- title: string,
279
- subtitle: string,
280
- cta: {
281
- label: string,
282
- link: string,
283
- },
284
- };
285
-
286
- export default function OnboardingPage(): ReactElement {
287
- return (
288
- <Slot id="home-banner" initial={null}>
289
- {(props: HomeBannerContent | null) => (
290
- props === null
291
- ? 'โœจ Personalizing...'
292
- : (
293
- <div>
294
- <strong>{props.title}</strong>
295
- <p>{props.subtitle}</p>
296
- <a href={props.cta.link}>{props.cta.label}</a>
297
- </div>
298
- )
299
- )}
300
- </Slot>
301
- )
302
- }
303
- ```
304
-
305
- And here's an example using the `useContent` hook:
306
-
307
- ```tsx
308
- import {ReactElement, Suspense} from 'react';
309
- import {useContent} from '@croct/plug-react';
310
-
311
- type HomeBannerContent = {
312
- title: string,
313
- subtitle: string,
314
- cta: {
315
- label: string,
316
- link: string,
317
- },
318
- };
319
-
320
- function HomeBanner(): ReactElement {
321
- const {
322
- title,
323
- subtitle,
324
- cta
325
- } = useContent<HomeBannerContent>('home-banner');
326
-
327
- return (
328
- <div>
329
- <strong>{title}</strong>
330
- <p>{subtitle}</p>
331
- <a href={cta.link}>{cta.label}</a>
332
- </div>
333
- )
334
- }
335
-
336
- export default function HomePage(): ReactElement {
337
- return (
338
- <Suspense fallback="Personalizing content...">
339
- <HomeBanner/>
340
- </Suspense>
341
- )
342
- }
343
- ```
344
-
345
- You can specify the version of the slot by passing a versioned ID in the form `id@version`. For example,
346
- passing `home-banner@1` will fetch the content for the `home-banner` slot in version 1. Not specifying a
347
- version number is the same as passing `home-banner@latest`, which will load the latest version of the slot.
348
-
349
- > โœ… Best practice
350
- > It's strongly recommended to specify a slot version for production deployments.
351
- > That way, you ensure the front end will always receive content with the expected
352
- > schema while your team can freely evolve the content's schema in parallel.
353
-
354
- #### Fault tolerance
355
-
356
- The following example shows how you can specify a fallback state for the `home-banner` slot:
357
-
358
- ```tsx
359
- import {ReactElement, Suspense} from 'react';
360
- import {Slot, useContent} from '@croct/plug-react';
361
-
362
- type HomeBannerContent = {
363
- title: string,
364
- subtitle: string,
365
- cta: {
366
- label: string,
367
- link: string,
368
- },
369
- };
370
-
371
- const fallbackBanner: HomeBannerContent = {
372
- title: 'Default title',
373
- subtitle: 'Default subtitle',
374
- cta: {
375
- label: 'Try now',
376
- link: 'https://croct.com',
377
- }
378
- };
379
-
380
- function HomeBanner(): ReactElement {
381
- const {
382
- title,
383
- subtitle,
384
- cta
385
- } = useContent<HomeBannerContent>('home-banner', {fallback: fallbackBanner});
386
-
387
- return (
388
- <div>
389
- <strong>{title}</strong>
390
- <p>{subtitle}</p>
391
- <a href={cta.link}>{cta.label}</a>
392
- </div>
393
- )
394
- }
395
-
396
- export default function HomePage(): ReactElement {
397
- return (
398
- <Suspense fallback="Personalizing content...">
399
- {/* Using the <Slot /> component */}
400
- <Slot id="home-banner" fallback={fallbackBanner}>
401
- {({
402
- title,
403
- subtitle,
404
- cta
405
- }: HomeBannerContent) => (
406
- <div>
407
- <strong>{title}</strong>
408
- <p>{subtitle}</p>
409
- <a href={cta.link}>{cta.label}</a>
410
- </div>
411
- )}
412
- </Slot>
413
-
414
- {/* Using the useContent hook */}
415
- <HomeBanner/>
416
- </Suspense>
417
- )
418
- }
419
- ```
420
-
421
- Again, we strongly recommend always providing a value for the `fallback` property. For a full list of the available
422
- options,
423
- please refer to the [API documentation](#component-api-reference).
424
-
425
- #### ๐Ÿ’ก ProTip
426
-
427
- In the previous examples, you may have noticed that we specified the content type in the `userFetch` call and in the
428
- `<Slot />` component's render function to have the benefit of strong typing.
429
-
430
- For an even more robust approach, you can also declare the type of all available slots in a single declaration file
431
- using module augmentation as follows:
432
-
433
- ```ts
434
- // slots.d.ts
435
- import {HomeBanner} from './HomePage';
436
-
437
- declare module '@croct/plug/slot' {
438
- interface SlotMap {
439
- 'home-banner': HomeBanner;
440
- }
441
- }
442
- ```
443
-
444
- If you use an IDE with Typescript code completion support, you will get autocomplete suggestions for
445
- slot IDs and content properties as a bonus:
446
-
447
- ![Autocomplete](https://user-images.githubusercontent.com/943036/113335703-b1101580-92fb-11eb-973d-3720ea133a95.gif)
448
-
449
- ### Server-side rendering
450
-
451
- You can use the same components and hooks on the server-side by simply providing an `initial` state which is used to
452
- pre-render on the server - the personalization happens transparently on the client during the initial render.
453
- That means it's SEO friendly and can be cached with no performance overhead.
454
-
455
- Notice that the methods exposed by the Plug work only on the client-side. Therefore, if you are
456
- using [`useCroct`](#usecroct),
457
- the operations have to be executed inside the `useEffect` hook or client-side callbacks, such as `onClick` or `onChange`
458
- , for example.
459
-
460
- ### Accessing the Plug instance
461
-
462
- This library is built on top of the PlugJS. You can access the Plug instance through the `useCroct` hook to track
463
- events,
464
- login and logout users, and more.
465
-
466
- In the following example we use the `useCroct` to get the Plug instance and set an attribute to the user profile:
467
-
468
- ```tsx
469
- import {ReactElement, useCallback} from 'react';
470
- import {useCroct} from '@croct/plug-react';
471
-
472
- export default function DeveloperButton(): ReactElement {
473
- const croct = useCroct();
474
- const setPersona = useCallback(
475
- () => croct.user.edit()
476
- .set('custom.persona', 'developer')
477
- .save(),
478
- [croct],
479
- );
480
-
481
- return (<button onClick={setPersona}>I'm a developer</button>);
482
- }
483
- ```
484
-
485
- ## Component API reference
486
-
487
- This reference documents all components available in the library.
488
-
489
- ### &lt;CroctProvider /&gt;
490
-
491
- The `<CroctProvider />` component leverages [React's Context API](https://reactjs.org/docs/context.html) to
492
- make a configured [Plug instance](https://github.com/croct-tech/plug-js/blob/master/docs/plug.md) available throughout
493
- a React component tree.
494
-
495
- #### Properties
496
-
497
- The component takes the followings properties:
498
-
499
- | Option | Type | Required | Default Value | Description |
500
- |--------------------------|--------------|----------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
501
- | `appId` | string | Yes | None | The ID of the application you set up on Croct. |
502
- | `debug` | boolean | No | `false` | If `true`, turns on debug mode, which logs helpful messages to the console. |
503
- | `track` | boolean | No | `true` | If `true`, enables the automatic event tracking on initialization. |
504
- | `clientId` | string | No | None | The ID of the client using the application. |
505
- | `token` | string\|null | No | None | The JWT token issued by Croct. If `null`, clears any token specified on previous calls. |
506
- | `userId` | string | No | None | The ID of the user logged into the application. Internally, the SDK will issue a token using the specified ID as the subject claim of the token. The `token` and `userId` options are mutually exclusive. |
507
- | `tokenScope` | string | No | `global` | Defines how the SDK should synchronize the token across multiple tabs, see [token scopes](#token-scopes) for more details. |
508
- | `eventMetadata` | JSON | No | None | Any additional information that may be useful to include as part of the event metadata. A common use case is to record the version of the application for future reference. |
509
- | `logger` | object | No | None | A custom logger to handle log messages. By default, all logs are suppressed. |
510
- | `urlSanitizer` | function | No | None | A function to sanitize URLs that allows removing sensitive information from URLs, such as tokens, that should not be sent to the platform. |
511
- | `baseEndpointUrl` | string | No | None | The base URL to use for the API calls. By default, the SDK will use the production endpoint. |
512
- | `cidAssignerEndpointUrl` | string | No | None | The URL to use for the client ID assignment. By default, the SDK will use the production endpoint. |
513
-
514
- #### Code Sample
515
-
516
- Here's a simple example showing how to initialize the Plug instance:
517
-
518
- ```tsx
519
- import {CroctProvider} from '@croct/plug-react';
520
-
521
- function App() {
522
- return (
523
- <CroctProvider appId="<APP_ID>">
524
- <div>
525
- <h1>My first personalized app ๐Ÿš€</h1>
526
- </div>
527
- </CroctProvider>
528
- );
529
- }
530
- ```
531
-
532
- > Replace "<APP_ID>" with your public app ID that you can find at Workspaces > Applications > API Keys.
533
-
534
- ### &lt;Personalization /&gt;
535
-
536
- The `<Personalization />` component evaluates and renders a CQL query.
537
-
538
- #### Properties
539
-
540
- The component takes the followings properties:
541
-
542
- | Option | Type | Required | Description |
543
- |--------------|----------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
544
- | `query` | string | Yes | The CQL query to evaluate. |
545
- | `children` | Function | Yes | A callback to render the result. |
546
- | `fallback` | Result | No | A value to render when the evaluation fails. If not specified, the hook will throw an exception in case of failures. |
547
- | `initial` | Result | SSR only | A value to render while loading, required for server-side rendering. If not specified, the rendering will suspend. |
548
- | `timeout` | number | No | The maximum evaluation time in milliseconds. Once reached, the evaluation will fail. |
549
- | `attributes` | JSON | No | A map of attributes to inject in the evaluation context. For example, passing the attributes `{cities: ['New York', 'San Francisco']}` you can reference them in queries like `context's cities include location's city`. |
550
- | `cacheKey` | string | No | An identifier that allows keeping the cached result separate from other cached items. By default, the cache key is formed from the query and attributes. |
551
- | `expiration` | number | No | The cache expiration time in milliseconds, extended on every render. If negative, the cache never expires. By default, the cache lifespan is set to 60000 (1 minute). |
552
-
553
- #### Code Sample
554
-
555
- Here's a simple example showing how to evaluate the user's persona:
556
-
557
- ```tsx
558
- import {ReactElement} from 'react';
559
- import {Personalization} from '@croct/plug-react';
560
-
561
- function PersonaBadge(): ReactElement {
562
- return (
563
- <Personalization query="user's persona or else 'unknown'">
564
- {persona => (<span>{persona}</span>)}
565
- </Personalization>
566
- );
567
- }
568
- ```
569
-
570
- ### &lt;Slot /&gt;
571
-
572
- The `<Slot />` component fetches and renders a slot.
573
-
574
- #### Properties
575
-
576
- The component takes the followings properties:
577
-
578
- | Option | Type | Required | Description |
579
- |-------------------|----------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
580
- | `id` | string | Yes | The ID of the slot to fetch. |
581
- | `children` | Function | Yes | A callback to render the result. |
582
- | `fallback` | Result | No | A value to render when the fetch fails. If not specified, the hook will throw an exception in case of failures. |
583
- | `preferredLocale` | string | No | The preferred locale to fetch. If not specified or not available, the hook will fetch the default locale. |
584
- | `initial` | Result | SSR only | A value to render while loading, required for server-side rendering. If not specified, the rendering will suspend. |
585
- | `cacheKey` | string | No | An identifier that allows keeping the cached result separate from other cached items. By default, the cache key is formed from the query and attributes. |
586
- | `expiration` | number | No | The cache expiration time in milliseconds, extended on every render. If negative, the cache never expires. By default, the cache lifespan is set to 60000 (1 minute). |
587
-
588
- #### Code Sample
589
-
590
- Here's a simple example showing how to render a banner in a slot:
591
-
592
- ```tsx
593
- import {ReactElement} from 'react';
594
- import {Slot} from '@croct/plug-react';
595
-
596
- function HeroBanner(): ReactElement {
597
- return (
598
- <Slot id="hero">
599
- {({
600
- title,
601
- subtitle
602
- }) => (
603
- <div>
604
- <h1>{title}</h1>
605
- <p>{subtitle}</p>
606
- </div>
607
- )}
608
- </Slot>
609
- );
610
- }
611
- ```
612
-
613
- ## Hook API reference
614
-
615
- This reference documents all hooks available in the library.
616
-
617
- ### useCroct
618
-
619
- The `useCroct` hook provides access to the Plug instance.
620
-
621
- #### Signature
622
-
623
- The hook has the following signature:
624
-
625
- ```ts
626
- useCroct(): Plug
627
- ```
628
-
629
- #### Code Sample
630
-
631
- Here's a simple example showing how anonymize a user:
632
-
633
- ```tsx
634
- import {ReactElement, useCallback} from 'react';
635
- import {useCroct} from '@croct/plug-react';
636
-
637
- function LogoutButton(): ReactElement {
638
- const croct = useCroct();
639
- const anonymize = useCallback(() => croct.anonymize(), [croct]);
640
-
641
- return <button type="button" onClick={anonymize}>Logout</button>
642
- }
643
- ```
644
-
645
- ### useEvaluation
646
-
647
- The `useEvaluation` hook evaluates a CQL query.
648
-
649
- #### Signature
650
-
651
- The hook has the following signature:
652
-
653
- ```ts
654
- function useEvaluation<Result extends JsonValue>(query: string, options: Options = {}): Result
655
- ```
656
-
657
- These are the currently supported options:
658
-
659
- | Option | Type | Description |
660
- |--------------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
661
- | `fallback` | Result | The value returned when the evaluation fails. If not specified, the hook will throw an exception in case of failures. |
662
- | `timeout` | number | The maximum evaluation time in milliseconds. Once reached, the evaluation will fail. |
663
- | `attributes` | JSON | The map of attributes to inject in the evaluation context. For example, passing the attributes `{cities: ['New York', 'San Francisco']}` you can reference them in querys like `context's cities include location's city`. |
664
- | `cacheKey` | string | An identifier that allows keeping the cached result separate from other cached items. By default, the cache key is formed from the query and attributes. |
665
- | `expiration` | number | The cache expiration time in milliseconds, extended on every render. If negative, the cache never expires. By default, the cache lifespan is set to 60000 (1 minute). |
666
-
667
- #### Code Sample
668
-
669
- Here's a simple example showing how to evaluate the user's persona:
670
-
671
- ```tsx
672
- import {ReactElement} from 'react';
673
- import {useEvaluation} from '@croct/plug-react';
674
-
675
- function PersonaBadge(): ReactElement {
676
- const persona = useEvaluation<string>("user's persona or else 'unknown'", {fallback: 'unknown'});
677
-
678
- return <span>{persona}</span>
679
- }
680
- ```
681
-
682
- ### useContent
683
-
684
- The `useContent` hook fetches the content of a slot.
685
-
686
- #### Signature
687
-
688
- The hook has the following signature:
689
-
690
- ```ts
691
- function useContent(slotId: string, options: Options = {}): JsonObject
692
- ```
693
-
694
- These are the currently supported options:
695
-
696
- | Option | Type | Description |
697
- |-------------------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
698
- | `fallback` | Content | The content returned when the fetch fails. If not specified, the hook will throw an exception in case of failures. |
699
- | `preferredLocale` | string | The preferred locale to fetch. If not specified or not available, the hook will fetch the default locale. |
700
- | `cacheKey` | string | An identifier that allows keeping the cached content separate from other cached items. By default, the cache key is formed from the slot ID. |
701
- | `expiration` | number | The cache expiration time in milliseconds, extended on every render. If negative, the cache never expires. By default, the cache lifespan is set to 60000 (1 minute). |
702
-
703
-
704
- #### Code Sample
705
-
706
- Here's a simple example showing how to fetch the content for a banner:
707
-
708
- ```tsx
709
- import {ReactElement} from 'react';
710
- import {useContent} from '@croct/plug-react';
711
-
712
- type HomeBannerContent = {
713
- title: string,
714
- subtitle: string,
715
- cta: {
716
- label: string,
717
- link: string,
718
- },
719
- };
720
-
721
- export default function HeroBanner(): ReactElement {
722
- const {
723
- title,
724
- subtitle
725
- } = useContent<HomeBannerContent>('hero');
726
-
727
- return (
728
- <div>
729
- <h1>{title}</h1>
730
- <p>{subtitle}</p>
731
- </div>
732
- );
733
- }
734
- ```
735
-
736
- ## Standalone function reference
737
-
738
- This reference documents all standalone functions available in the library.
739
-
740
- ### evaluate
741
-
742
- The `evaluate` function evaluates a CQL query on the server-side and returns the result.
743
-
744
- #### Signature
745
-
746
- The function has the following signature:
747
-
748
- ```ts
749
- function evaluate(query: string, options: EvaluationOptions): Promise<JsonValue>
750
- ```
751
-
752
- These are the currently supported options:
753
-
754
- | Option | Type | Required | Description |
755
- |----------------------------|--------|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
756
- | `apiKey` | string | Yes | The private API key of the application. This is a private key that should never be exposed to the client-side. |
757
- | `baseEndpointUrl` | string | No | The base URL of the Evaluation API. Defaults to the production endpoint. |
758
- | `fallback` | JSON | No | The value returned when the evaluation fails. If not specified, the function will throw an exception in case of failures. |
759
- | `timeout` | number | No | The maximum evaluation time in milliseconds. Once reached, the evaluation will fail. |
760
- | `clientId` | string | No | A UUID v4 that uniquely identifies the client across multiple evaluations. You should generate this identifier on your server-side using a random, cryptographically secure generator and ensure it doesn't change throughout the user journey (e.g. store in cookies). If not specified, the evaluation will run in an anonymous context. |
761
- | `clientIp` | string | No | The IP address of the client to determine the location. The IP is only used to determine the location and then discarded. |
762
- | `userAgent` | string | No | The user agent of the client to determine the device. |
763
- | `userToken` | string | No | The token that uniquely identifies the user. You can use this to provide consistent experiences across multiple channels. |
764
- | `context` | JSON | No | The evaluation context. |
765
- | `context.timeZone` | string | No | The time zone of the client. |
766
- | `context.campaign` | JSON | No | The marketing campaign that brought the user to the application. |
767
- | `context.campaign.name` | string | No | The name of the campaign. |
768
- | `context.campaign.source` | string | No | The source of the campaign. For example, "google", "newsletter", "facebook". |
769
- | `context.campaign.medium` | string | No | The marketing medium. For example, "cpc", "banner", "ads". |
770
- | `context.campaign.term` | string | No | The campaign keywords. For example, "smartphone online sale". |
771
- | `context.campaign.content` | string | No | The campaign content. For example, "top-banner", "cta", "sidebar". |
772
- | `context.page` | JSON | No | The page the user is currently viewing. |
773
- | `context.page.url` | string | Yes | The URL of the page. |
774
- | `context.page.title` | string | No | The title of the page. |
775
- | `context.page.referrer` | string | No | The URL of the page that referred the user to the current page. |
776
- | `context.attributes` | JSON | No | The map of attributes to inject in the evaluation context. For example, passing the attributes `{cities: ['New York', 'San Francisco']}` you can reference them in querys like `context's cities include location's city`. |
777
- | `extra` | JSON | No | Additional [options](https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters) to pass to the fetch function. |
778
-
779
- #### Code Sample
780
-
781
- Here's a simple example showing how to evaluate a CQL query:
782
-
783
- ```ts
784
- import {evaluate} from '@croct/plug/api';
785
-
786
- const result = await evaluate("user's persona", {
787
- apiKey: process.env.CROCT_API_KEY,
788
- });
789
- ```
790
-
791
- ### fetchContent
792
-
793
- The `fetchContent` function fetches the content for a slot on the server-side and returns the result.
794
-
795
- #### Signature
796
-
797
- The function has the following signature:
798
-
799
- ```ts
800
- function fetchContent(slotId: string, options: FetchOptions): Promise<{content: JsonValue}>
801
- ```
802
-
803
- These are the currently supported options:
804
-
805
-
806
- | Option | Type | Required | Description |
807
- |----------------------------|---------|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
808
- | `apiKey` | string | Yes | The private API key of the application. This is a private key that should never be exposed to the client-side. |
809
- | `baseEndpointUrl` | string | No | The base URL of the Content API. Defaults to the production endpoint. |
810
- | `fallback` | JSON | No | The value returned when the fetch fails. If not specified, the function will throw an exception in case of failures. |
811
- | `static` | boolean | No | Whether to fetch the static content. If not specified, the function will fetch the dynamic content. |
812
- | `timeout` | number | No | The maximum fetch time in milliseconds. Once reached, the fetch will fail. |
813
- | `previewToken` | string | No | The token that enables preview mode. |
814
- | `preferredLocale` | string | No | The preferred locale to fetch. If not specified or not available, the hook will fetch the default locale. |
815
- | `clientId` | string | No | A UUID v4 that uniquely identifies the client across multiple evaluations. You should generate this identifier on your server-side using a random, cryptographically secure generator and ensure it doesn't change throughout the user journey (e.g. store in cookies). If not specified, the evaluation will run in an anonymous context. |
816
- | `clientIp` | string | No | The IP address of the client to determine the location. The IP is only used to determine the location and then discarded. |
817
- | `userAgent` | string | No | The user agent of the client to determine the device. |
818
- | `userToken` | string | No | The token that uniquely identifies the user. You can use this to provide consistent experiences across multiple channels. |
819
- | `context` | JSON | No | The evaluation context. |
820
- | `context.timeZone` | string | No | The time zone of the client. |
821
- | `context.campaign` | JSON | No | The marketing campaign that brought the user to the application. |
822
- | `context.campaign.name` | string | No | The name of the campaign. |
823
- | `context.campaign.source` | string | No | The source of the campaign. For example, "google", "newsletter", "facebook". |
824
- | `context.campaign.medium` | string | No | The marketing medium. For example, "cpc", "banner", "ads". |
825
- | `context.campaign.term` | string | No | The campaign keywords. For example, "smartphone online sale". |
826
- | `context.campaign.content` | string | No | The campaign content. For example, "top-banner", "cta", "sidebar". |
827
- | `context.page` | JSON | No | The page the user is currently viewing. |
828
- | `context.page.url` | string | Yes | The URL of the page. |
829
- | `context.page.title` | string | No | The title of the page. |
830
- | `context.page.referrer` | string | No | The URL of the page that referred the user to the current page. |
831
- | `context.attributes` | JSON | No | The map of attributes to inject in the evaluation context. For example, passing the attributes `{cities: ['New York', 'San Francisco']}` you can reference them in querys like `context's cities include location's city`. |
832
- | `extra` | JSON | No | Additional [options](https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters) to pass to the fetch function. |
37
+ ## Documentation
833
38
 
39
+ Visit our [official documentation](https://docs.croct.com/reference/sdk/react/installation).
834
40
 
835
41
  ## Support
836
42
 
837
- If this documentation has not answered all your questions, don't worry.
838
- Here are some alternative ways to get help from the Croct community.
839
-
840
- ### Stack Overflow
841
-
842
- Someone else from the community may have already asked a similar question or may be able to help with your problem.
843
-
844
- The Croct team will also monitor posts with the "croct" tag. If there aren't any existing questions that help,
845
- please [ask a new one](https://stackoverflow.com/questions/ask?tags=croct%20plug-react%20react).
846
-
847
- ### GitHub
848
-
849
- If you have what looks like a bug, or you would like to make a feature request, please
850
- [open a new issue on GitHub](https://github.com/croct-tech/plug-react/issues/new/choose).
43
+ Join our official [Slack channel](https://croct.link/community) to get help from the Croct team and other developers.
851
44
 
852
- Before you file an issue, a good practice is to search for issues to see whether others have the same or similar
853
- problems.
854
- If you are unable to find an open issue addressing the problem, then feel free to open a new one.
45
+ ## Contribution
855
46
 
856
- ### Slack Channel
47
+ Contributions are always welcome!
857
48
 
858
- Many people from the Croct community hang out on the Croct Slack Group.
859
- Feel free to [join us and start a conversation](https://croct.link/community).
49
+ - Report any bugs or issues on the [issue tracker](https://github.com/croct-tech/plug-react/issues).
50
+ - For major changes, please [open an issue](https://github.com/croct-tech/plug-react/issues) first to discuss what you would like to change.
51
+ - Please make sure to update tests as appropriate. Run tests with `npm test`.
860
52
 
861
53
  ## License
862
54
 
863
- This project is released under the [MIT License](LICENSE).
55
+ This library is licensed under the [MIT license](LICENSE).