@graphcommerce/algolia-personalization 9.0.0-canary.73 → 9.0.0-canary.75

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 CHANGED
@@ -1,3 +1,7 @@
1
1
  # @graphcommerce/algolia-personalization
2
2
 
3
+ ## 9.0.0-canary.75
4
+
5
+ ## 9.0.0-canary.74
6
+
3
7
  ## 9.0.0-canary.73
@@ -0,0 +1,10 @@
1
+ extend input GraphCommerceAlgoliaConfig {
2
+ """
3
+ Send algolia analytics events.
4
+ """
5
+ analyticsEnabled: Boolean
6
+ """
7
+ Enable personalized queries.
8
+ """
9
+ personalizationEnabled: Boolean
10
+ }
package/README.md CHANGED
@@ -1,7 +1,36 @@
1
1
  # Algolia Magento 2
2
2
 
3
- An implementation of Algolia personalization through the GraphQL Mesh.
3
+ An implementation of Algolia personalization/Analytics through the GraphQL Mesh.
4
4
 
5
5
  ## Prerequisites
6
6
 
7
- Make sure you have configured @graphcommerce/algolia-mesh
7
+ 1. Make sure you have configured @graphcommerce/algolia-mesh.
8
+ 2. As this is an extension of the google-datalayer. Make sure you have installed
9
+ @graphcommerce/google-datalayer
10
+
11
+ ## Installation
12
+
13
+ 1. Find current version of your `@graphcommerce/next-ui` in your package.json.
14
+ 2. `yarn add @graphcommerce/algolia-personalization@9.0.0` (replace 9.0.0 with
15
+ the version of the step above)
16
+
17
+ ## Configuration
18
+
19
+ 1. See [Config](./Config.graphqls) for the configuration values. Add the
20
+ following to your graphcommerce.config.js:
21
+
22
+ ```js
23
+ const config = {
24
+ // Even if you do not use personalization, enabling analytics still allows you to track events in Algolia.
25
+ algoliaEnableAnalytics: true,
26
+ algoliaPersonalizationEnabled: true,
27
+ }
28
+ ```
29
+
30
+ 2. In your algolia dashboard make sure, you have personalization enabled.
31
+ 3. Continue to browse the site, and make sure your events are logged in de event
32
+ debugger in your algolia dashboard. In the under left corner.
33
+ `Data Sources > Events > Debugger`. Once you've collected several events, you
34
+ can start configuring personalization
35
+ 4. in `Enchance > personalization` setup the strategies. Note: if you can't find
36
+ some events, make sure you have send several.
@@ -19,6 +19,8 @@ const getSHA256Hash = async (input: string) => {
19
19
  return hash
20
20
  }
21
21
 
22
+ export const ALGOLIA_USER_TOKEN_COOKIE_NAME = '_algolia_userToken'
23
+
22
24
  function mapSelectedFiltersToAlgoliaEvent(filters: ProductFilterParams['filters']) {
23
25
  const flattenedFilters: string[] = []
24
26
 
@@ -88,7 +90,6 @@ const dataLayerToAlgoliaMap: {
88
90
 
89
91
  const events: AlgoliaEventsItems_Input[] = []
90
92
 
91
- console.log(queryID)
92
93
  if (
93
94
  // Values of filters are different when using Algolia vs Magento, thus it does not make sense to send the filters
94
95
  queryID &&
@@ -100,7 +101,7 @@ const dataLayerToAlgoliaMap: {
100
101
  const newlyAppliedFilters = filters.filter((filter) => !prevFilters.includes(filter))
101
102
  prevFilters = filters
102
103
 
103
- if (newlyAppliedFilters) {
104
+ if (newlyAppliedFilters.length > 0) {
104
105
  events.push({
105
106
  Clicked_filters_Input: {
106
107
  eventName: `${eventName}_filter_diff`,
@@ -309,7 +310,6 @@ export function useSendAlgoliaEvent() {
309
310
  const client = useApolloClient()
310
311
  const index = useAlgoliaIndexName()
311
312
  const algoliaQuery = useAlgoliaQuery()
312
- console.log(algoliaQuery)
313
313
 
314
314
  const eventsBuffer = useRef<AlgoliaEventsItems_Input[]>([])
315
315
  const submit = useDebounce(
@@ -350,16 +350,16 @@ export function useSendAlgoliaEvent() {
350
350
  return useEventCallback<typeof sendEvent>(async (eventName, eventData) => {
351
351
  const email = client.cache.readQuery({ query: CustomerDocument })?.customer?.email
352
352
  const authenticatedUserToken = email ? await getSHA256Hash(email) : undefined
353
- let userToken = cookie('_algolia_userToken')
353
+ let userToken = cookie(ALGOLIA_USER_TOKEN_COOKIE_NAME)
354
354
  if (!userToken) {
355
355
  userToken = (Math.random() + 1).toString(36).substring(2)
356
- cookie('_algolia_userToken', userToken, { sameSite: true })
356
+ cookie(ALGOLIA_USER_TOKEN_COOKIE_NAME, userToken, { sameSite: true })
357
357
  }
358
358
 
359
359
  // todo check if valid
360
- if (authenticatedUserToken) {
361
- userToken = authenticatedUserToken
362
- }
360
+ // if (authenticatedUserToken) {
361
+ // userToken = authenticatedUserToken
362
+ // }
363
363
 
364
364
  const events = dataLayerToAlgoliaMap[eventName]?.(eventName, eventData, {
365
365
  index,
@@ -0,0 +1,12 @@
1
+ import { MeshContext } from '@graphcommerce/graphql-mesh'
2
+ // eslint-disable-next-line import/no-extraneous-dependencies
3
+ import { parse } from 'cookie'
4
+
5
+ const ALGOLIA_USER_TOKEN_COOKIE_NAME = '_algolia_userToken'
6
+ export function getUserToken(context: MeshContext): string | undefined {
7
+ const { headers } = context as MeshContext & { headers?: Record<string, string | undefined> }
8
+
9
+ const cookie = headers?.cookie
10
+ if (cookie) return parse(cookie)[ALGOLIA_USER_TOKEN_COOKIE_NAME]
11
+ return undefined
12
+ }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@graphcommerce/algolia-personalization",
3
3
  "homepage": "https://www.graphcommerce.org/",
4
4
  "repository": "github:graphcommerce-org/graphcommerce",
5
- "version": "9.0.0-canary.73",
5
+ "version": "9.0.0-canary.75",
6
6
  "sideEffects": false,
7
7
  "prettier": "@graphcommerce/prettier-config-pwa",
8
8
  "eslintConfig": {
@@ -15,14 +15,14 @@
15
15
  "generate-insights": "tsx scripts/generate-insights-spec.mts"
16
16
  },
17
17
  "peerDependencies": {
18
- "@graphcommerce/algolia-mesh": "^9.0.0-canary.73",
19
- "@graphcommerce/google-datalayer": "^9.0.0-canary.73",
20
- "@graphcommerce/graphql": "^9.0.0-canary.73",
21
- "@graphcommerce/graphql-mesh": "^9.0.0-canary.73",
22
- "@graphcommerce/magento-customer": "^9.0.0-canary.73",
23
- "@graphcommerce/magento-product": "^9.0.0-canary.73",
24
- "@graphcommerce/next-config": "^9.0.0-canary.73",
25
- "@graphcommerce/next-ui": "^9.0.0-canary.73",
18
+ "@graphcommerce/algolia-mesh": "^9.0.0-canary.75",
19
+ "@graphcommerce/google-datalayer": "^9.0.0-canary.75",
20
+ "@graphcommerce/graphql": "^9.0.0-canary.75",
21
+ "@graphcommerce/graphql-mesh": "^9.0.0-canary.75",
22
+ "@graphcommerce/magento-customer": "^9.0.0-canary.75",
23
+ "@graphcommerce/magento-product": "^9.0.0-canary.75",
24
+ "@graphcommerce/next-config": "^9.0.0-canary.75",
25
+ "@graphcommerce/next-ui": "^9.0.0-canary.75",
26
26
  "react": "^18.2.0"
27
27
  },
28
28
  "devDependencies": {
@@ -0,0 +1,32 @@
1
+ import {
2
+ type getInContextInput as getInContextInputType,
3
+ type useInContextInput as useInContextInputType,
4
+ } from '@graphcommerce/graphql'
5
+ import type { InContextInput } from '@graphcommerce/graphql-mesh'
6
+ import type { FunctionPlugin, PluginConfig } from '@graphcommerce/next-config'
7
+ import { cookie } from '@graphcommerce/next-ui'
8
+ import { ALGOLIA_USER_TOKEN_COOKIE_NAME } from '../hooks/useSendAlgoliaEvent'
9
+
10
+ export const config: PluginConfig = {
11
+ type: 'function',
12
+ module: '@graphcommerce/graphql',
13
+ ifConfig: 'algolia.personalizationEnabled',
14
+ }
15
+
16
+ export const getInContextInput: FunctionPlugin<typeof getInContextInputType> = (
17
+ prev,
18
+ client,
19
+ ...args
20
+ ) => {
21
+ const algoliaUserToken = cookie(ALGOLIA_USER_TOKEN_COOKIE_NAME)
22
+ const res = prev(client, ...args)
23
+ if (!algoliaUserToken) return res
24
+ return { ...res, algoliaUserToken } satisfies InContextInput
25
+ }
26
+
27
+ export const useInContextInput: FunctionPlugin<typeof useInContextInputType> = (prev, ...args) => {
28
+ const algoliaUserToken = cookie(ALGOLIA_USER_TOKEN_COOKIE_NAME)
29
+ const res = prev(...args)
30
+ if (!algoliaUserToken) return res
31
+ return { ...res, algoliaUserToken }
32
+ }
@@ -0,0 +1,20 @@
1
+ import type { getSearchResultsInput as getSearchResultsInputType } from '@graphcommerce/algolia-mesh'
2
+ import { FunctionPlugin, PluginConfig } from '@graphcommerce/next-config'
3
+ import { getUserToken } from '../mesh/getUserToken'
4
+
5
+ export const config: PluginConfig = {
6
+ type: 'function',
7
+ module: '@graphcommerce/algolia-mesh',
8
+ ifConfig: 'algolia.personalizationEnabled',
9
+ }
10
+
11
+ export const getSearchResultsInput: FunctionPlugin<typeof getSearchResultsInputType> = async (
12
+ prev,
13
+ args,
14
+ context,
15
+ ) => ({
16
+ ...(await prev(args, context)),
17
+ clickAnalytics: true,
18
+ analytics: true,
19
+ userToken: getUserToken(context),
20
+ })
@@ -0,0 +1,18 @@
1
+ import type { getSearchResultsInput as getSearchResultsInputType } from '@graphcommerce/algolia-mesh'
2
+ import { FunctionPlugin, PluginConfig } from '@graphcommerce/next-config'
3
+
4
+ export const config: PluginConfig = {
5
+ type: 'function',
6
+ module: '@graphcommerce/algolia-mesh',
7
+ ifConfig: 'algolia.personalizationEnabled',
8
+ }
9
+
10
+ export const getSearchResultsInput: FunctionPlugin<typeof getSearchResultsInputType> = async (
11
+ prev,
12
+ args,
13
+ context,
14
+ ) => ({
15
+ ...(await prev(args, context)),
16
+ // enablePersonalization: true,
17
+ // personalizationImpact: 50,
18
+ })
@@ -0,0 +1,18 @@
1
+ import type { getSearchSuggestionsInput as getSearchSuggestionsInputType } from '@graphcommerce/algolia-mesh'
2
+ import { FunctionPlugin, PluginConfig } from '@graphcommerce/next-config'
3
+ import { getUserToken } from '../mesh/getUserToken'
4
+
5
+ export const config: PluginConfig = {
6
+ type: 'function',
7
+ module: '@graphcommerce/algolia-mesh',
8
+ ifConfig: 'algolia.analyticsEnabled',
9
+ }
10
+
11
+ export const getSearchSuggestionsInput: FunctionPlugin<
12
+ typeof getSearchSuggestionsInputType
13
+ > = async (prev, search, context) => ({
14
+ ...(await prev(search, context)),
15
+ clickAnalytics: true,
16
+ analytics: true,
17
+ userToken: getUserToken(context),
18
+ })
@@ -0,0 +1,16 @@
1
+ import type { getSearchSuggestionsInput as getSearchSuggestionsInputType } from '@graphcommerce/algolia-mesh'
2
+ import { FunctionPlugin, PluginConfig } from '@graphcommerce/next-config'
3
+
4
+ export const config: PluginConfig = {
5
+ type: 'function',
6
+ module: '@graphcommerce/algolia-mesh',
7
+ ifConfig: 'algolia.personalizationEnabled',
8
+ }
9
+
10
+ export const getSearchSuggestionsInput: FunctionPlugin<
11
+ typeof getSearchSuggestionsInputType
12
+ > = async (prev, search, context) => ({
13
+ ...(await prev(search, context)),
14
+ // enablePersonalization: true,
15
+ // personalizationImpact: 50,
16
+ })
@@ -10,13 +10,8 @@ export const meshConfig: FunctionPlugin<typeof meshConfigBase> = (
10
10
  prev,
11
11
  baseConfig,
12
12
  graphCommerceConfig,
13
- ) => {
14
- if (!graphCommerceConfig.algoliaApplicationId || !graphCommerceConfig.algoliaSearchOnlyApiKey) {
15
- console.log('Algolia credentials not provided, skipping Algolia plugin')
16
- return prev(baseConfig, graphCommerceConfig)
17
- }
18
-
19
- return prev(
13
+ ) =>
14
+ prev(
20
15
  {
21
16
  ...baseConfig,
22
17
  sources: [
@@ -29,12 +24,12 @@ export const meshConfig: FunctionPlugin<typeof meshConfigBase> = (
29
24
  source: '@graphcommerce/algolia-personalization/algolia-insights-spec.yaml',
30
25
  ignoreErrorResponses: true,
31
26
  schemaHeaders: {
32
- 'X-Algolia-Application-Id': graphCommerceConfig.algoliaApplicationId,
33
- 'X-Algolia-API-Key': graphCommerceConfig.algoliaSearchOnlyApiKey,
27
+ 'X-Algolia-Application-Id': graphCommerceConfig.algolia.applicationId,
28
+ 'X-Algolia-API-Key': graphCommerceConfig.algolia.searchOnlyApiKey,
34
29
  },
35
30
  operationHeaders: {
36
- 'X-Algolia-Application-Id': graphCommerceConfig.algoliaApplicationId,
37
- 'X-Algolia-API-Key': graphCommerceConfig.algoliaSearchOnlyApiKey,
31
+ 'X-Algolia-Application-Id': graphCommerceConfig.algolia.applicationId,
32
+ 'X-Algolia-API-Key': graphCommerceConfig.algolia.searchOnlyApiKey,
38
33
  },
39
34
  selectQueryOrMutationField: [
40
35
  { type: 'Query', fieldName: 'searchSingleIndex' },
@@ -69,4 +64,3 @@ export const meshConfig: FunctionPlugin<typeof meshConfigBase> = (
69
64
  },
70
65
  graphCommerceConfig,
71
66
  )
72
- }
@@ -9,6 +9,7 @@ import { useSendAlgoliaEvent } from '../hooks/useSendAlgoliaEvent'
9
9
  export const config: PluginConfig = {
10
10
  module: '@graphcommerce/google-datalayer',
11
11
  type: 'function',
12
+ ifConfig: 'algolia.analyticsEnabled',
12
13
  }
13
14
 
14
15
  export const useSendEvent: FunctionPlugin<typeof useSendEventBase> = (prev) => {
@@ -0,0 +1,3 @@
1
+ input InContextInput {
2
+ algoliaUserToken: String
3
+ }