Skip to content

Commit f2e6b43

Browse files
committed
Extract Eularian in a separate util
1 parent e0c13a8 commit f2e6b43

File tree

7 files changed

+152
-99
lines changed

7 files changed

+152
-99
lines changed

src/eulerianAnalytics.ts

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { prDsfrLoaded } from "./start";
2+
3+
export type EulerianAnalyticsParams = {
4+
domain: string;
5+
/** default: false */
6+
enableRating?: boolean;
7+
page?: Partial<{
8+
path: string; // path for page tracking
9+
referrer: string; // referrer for virtual pages (not for real page, eulerian automatically collects document.referrer)
10+
id: string; // unique page id (string)
11+
title: string; // page title for virtual pages
12+
name: string; // equivalent to title if not defined
13+
author: string; // page author name
14+
date: string; // page creation date
15+
labels: string[];
16+
tags: string[]; // no tags limit
17+
template: string; // page template
18+
group: string; // page group. if not defined, fallback to template value
19+
segment: string; // site segment. if not defined, fallback to template value
20+
subtemplate: string; // page subtemplate
21+
theme: string; // page theme
22+
subtheme: string; // page subtheme
23+
related: string; // related page id
24+
depth: number; // page depth
25+
isError: boolean; // is this an error page (404, 500, 503...)
26+
current: number; // In case of pagination, current page number
27+
total: number; // In case of pagination, total pages number
28+
filters: string; // array of filters that were applied on the page (strings)
29+
}>;
30+
site?: Partial<{
31+
environment: "development" | "stage" | "production"; // by default development ['development', 'stage', 'production']
32+
entity: string; // Entity responsible for website
33+
language: string; // language of the website (ISO 639-1). default to html lang
34+
target: string; // site target
35+
type: string; // site type
36+
region: string; // region of the website (ISO 3166-2:FR)
37+
department: string; // department of the website (ISO 3166-2:FR)
38+
}>;
39+
user?: Partial<{
40+
connect: {
41+
uid: string; // user id - required when connected
42+
email: string; // encoded user email - required when connected
43+
isNew: boolean; // user just registered
44+
};
45+
profile: string; // user profile
46+
language: string;
47+
type: string;
48+
}>;
49+
search?: Partial<{
50+
engine: string;
51+
results: number;
52+
terms: string;
53+
category: string;
54+
theme: string;
55+
type: string;
56+
method: string;
57+
}>;
58+
funnel?: Partial<{
59+
id: string;
60+
type: string;
61+
name: string;
62+
step: string; // step name
63+
current: number; // step number
64+
total: number; // total number of steps
65+
objective: string; // form objective
66+
error: string; // form's error type
67+
}>;
68+
cmp?: Partial<{
69+
id: string;
70+
}>;
71+
};
72+
73+
export async function startEulerianAnalytics(params: EulerianAnalyticsParams) {
74+
await prDsfrLoaded;
75+
76+
// @ts-expect-error
77+
window.dsfr.analytics = params;
78+
79+
// @ts-expect-error
80+
await import("./dsfr/analytics/analytics.module.min");
81+
82+
return {
83+
// @ts-expect-error
84+
"enable": () => {
85+
window.dsfr.analytics.opt.enable();
86+
},
87+
// @ts-expect-error
88+
"disable": () => {
89+
window.dsfr.analytics.opt.disable();
90+
}
91+
};
92+
}

src/next-appdir/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
export type { RegisterLink } from "../link";
22
export type { DefaultColorScheme } from "./zz_internal/defaultColorScheme";
33
export { startReactDsfr } from "./zz_internal/start";
4-
export type { EulerianAnalytics } from "../start";

src/next-appdir/zz_internal/start.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { ReactNode } from "react";
2-
import { start, type EulerianAnalytics } from "../../start";
2+
import { start } from "../../start";
33
import type { RegisteredLinkProps } from "../../link";
44
import { setLink } from "../../link";
55
import { type DefaultColorScheme, setDefaultColorSchemeClientSide } from "./defaultColorScheme";
@@ -14,9 +14,8 @@ export function startReactDsfr(params: {
1414
verbose?: boolean;
1515
/** Default: <a /> */
1616
Link?: (props: RegisteredLinkProps & { children: ReactNode }) => ReturnType<React.FC>;
17-
eulerianAnalytics?: EulerianAnalytics;
1817
}) {
19-
const { defaultColorScheme, verbose = false, Link, eulerianAnalytics } = params;
18+
const { defaultColorScheme, verbose = false, Link } = params;
2019

2120
setDefaultColorSchemeClientSide({ defaultColorScheme });
2221

@@ -28,7 +27,6 @@ export function startReactDsfr(params: {
2827
start({
2928
defaultColorScheme,
3029
verbose,
31-
eulerianAnalytics,
3230
"nextParams": {
3331
"doPersistDarkModePreferenceWithCookie": false,
3432
"registerEffectAction": action => {

src/next-pagesdir.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,13 @@ import FaviconSvg from "./dsfr/favicon/favicon.svg";
1616
import FaviconIco from "./dsfr/favicon/favicon.ico";
1717
import { getAssetUrl } from "./tools/getAssetUrl";
1818
import { getColors } from "./fr/colors";
19-
import { start, type EulerianAnalytics } from "./start";
19+
import { start } from "./start";
2020
import type { RegisterLink, RegisteredLinkProps } from "./link";
2121
import { setLink } from "./link";
2222
import { setUseLang } from "./i18n";
2323
import { assert } from "tsafe/assert";
2424
import "./assets/dsfr_plus_icons.css";
2525

26-
export type { EulerianAnalytics };
27-
2826
const isProduction = process.env.NODE_ENV !== "development";
2927

3028
export type { RegisterLink, RegisteredLinkProps };
@@ -43,7 +41,6 @@ export type CreateNextDsfrIntegrationApiParams = {
4341
doPersistDarkModePreferenceWithCookie?: boolean;
4442
/** Default: ()=> "fr" */
4543
useLang?: () => string;
46-
eulerianAnalytics?: EulerianAnalytics;
4744
};
4845

4946
function readIsDarkInCookie(cookie: string) {
@@ -91,8 +88,7 @@ export function createNextDsfrIntegrationApi(
9188
Link,
9289
preloadFonts = [],
9390
doPersistDarkModePreferenceWithCookie = false,
94-
useLang,
95-
eulerianAnalytics
91+
useLang
9692
} = params;
9793

9894
let isAfterFirstEffect = false;
@@ -110,7 +106,6 @@ export function createNextDsfrIntegrationApi(
110106
start({
111107
defaultColorScheme,
112108
verbose,
113-
eulerianAnalytics,
114109
"nextParams": {
115110
doPersistDarkModePreferenceWithCookie,
116111
"registerEffectAction": action => {

src/spa.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
import type { ReactNode } from "react";
2-
import { start, type EulerianAnalytics } from "./start";
2+
import { start } from "./start";
33
import type { RegisterLink, RegisteredLinkProps } from "./link";
44
import { setLink } from "./link";
55
import { setUseLang } from "./i18n";
66
import type { ColorScheme } from "./useIsDark";
77

8-
export type { EulerianAnalytics };
9-
108
export type { RegisterLink, RegisteredLinkProps };
119

1210
export function startReactDsfr(params: {
@@ -17,9 +15,8 @@ export function startReactDsfr(params: {
1715
Link?: (props: RegisteredLinkProps & { children: ReactNode }) => ReturnType<React.FC>;
1816
/** Default: ()=> "fr" */
1917
useLang?: () => string;
20-
eulerianAnalytics?: EulerianAnalytics;
2118
}) {
22-
const { defaultColorScheme, verbose = false, Link, useLang, eulerianAnalytics } = params;
19+
const { defaultColorScheme, verbose = false, Link, useLang } = params;
2320

2421
if (Link !== undefined) {
2522
setLink({ Link });
@@ -32,7 +29,6 @@ export function startReactDsfr(params: {
3229
start({
3330
defaultColorScheme,
3431
verbose,
35-
eulerianAnalytics,
3632
"nextParams": undefined
3733
});
3834
}

src/start.ts

Lines changed: 15 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ import { isBrowser } from "./tools/isBrowser";
22
import { assert } from "tsafe/assert";
33
import type { ColorScheme } from "./useIsDark";
44
import { startClientSideIsDarkLogic } from "./useIsDark/client";
5+
import { Deferred } from "./tools/Deferred";
56

67
type Params = {
78
defaultColorScheme: ColorScheme | "system";
89
verbose: boolean;
9-
eulerianAnalytics: EulerianAnalytics | undefined;
1010
nextParams:
1111
| {
1212
doPersistDarkModePreferenceWithCookie: boolean;
@@ -18,7 +18,7 @@ type Params = {
1818
let isStarted = false;
1919

2020
export async function start(params: Params) {
21-
const { defaultColorScheme, verbose, nextParams, eulerianAnalytics } = params;
21+
const { defaultColorScheme, verbose, nextParams } = params;
2222

2323
assert(isBrowser);
2424

@@ -38,89 +38,23 @@ export async function start(params: Params) {
3838
registerEffectAction
3939
});
4040

41-
(window as any).dsfr = {
41+
// @ts-expect-error
42+
window.dsfr = {
4243
verbose,
43-
"mode": "react",
44-
"analytics": eulerianAnalytics
44+
"mode": "react"
4545
};
4646

47-
await import("./dsfr/dsfr.module" as any);
47+
// @ts-expect-error
48+
await import("./dsfr/dsfr.module.min");
4849

49-
if (eulerianAnalytics !== undefined) {
50-
await import("./dsfr/analytics/analytics.module.js" as any);
51-
}
52-
53-
const { dsfr } = window as unknown as { dsfr: { start: () => void } };
50+
dDsfrLoaded.resolve();
5451

55-
registerEffectAction(() => dsfr.start());
52+
registerEffectAction(() => {
53+
// @ts-expect-error
54+
window.dsfr.start();
55+
});
5656
}
5757

58-
export type EulerianAnalytics = {
59-
domain: string;
60-
/** default: false */
61-
enableRating?: boolean;
62-
page?: Partial<{
63-
path: string; // path for page tracking
64-
referrer: string; // referrer for virtual pages (not for real page, eulerian automatically collects document.referrer)
65-
id: string; // unique page id (string)
66-
title: string; // page title for virtual pages
67-
name: string; // equivalent to title if not defined
68-
author: string; // page author name
69-
date: string; // page creation date
70-
labels: string[];
71-
tags: string[]; // no tags limit
72-
template: string; // page template
73-
group: string; // page group. if not defined, fallback to template value
74-
segment: string; // site segment. if not defined, fallback to template value
75-
subtemplate: string; // page subtemplate
76-
theme: string; // page theme
77-
subtheme: string; // page subtheme
78-
related: string; // related page id
79-
depth: number; // page depth
80-
isError: boolean; // is this an error page (404, 500, 503...)
81-
current: number; // In case of pagination, current page number
82-
total: number; // In case of pagination, total pages number
83-
filters: string; // array of filters that were applied on the page (strings)
84-
}>;
85-
site?: Partial<{
86-
environment: "development" | "stage" | "production"; // by default development ['development', 'stage', 'production']
87-
entity: string; // Entity responsible for website
88-
language: string; // language of the website (ISO 639-1). default to html lang
89-
target: string; // site target
90-
type: string; // site type
91-
region: string; // region of the website (ISO 3166-2:FR)
92-
department: string; // department of the website (ISO 3166-2:FR)
93-
}>;
94-
user?: Partial<{
95-
connect: {
96-
uid: string; // user id - required when connected
97-
email: string; // encoded user email - required when connected
98-
isNew: boolean; // user just registered
99-
};
100-
profile: string; // user profile
101-
language: string;
102-
type: string;
103-
}>;
104-
search?: Partial<{
105-
engine: string;
106-
results: number;
107-
terms: string;
108-
category: string;
109-
theme: string;
110-
type: string;
111-
method: string;
112-
}>;
113-
funnel?: Partial<{
114-
id: string;
115-
type: string;
116-
name: string;
117-
step: string; // step name
118-
current: number; // step number
119-
total: number; // total number of steps
120-
objective: string; // form objective
121-
error: string; // form's error type
122-
}>;
123-
cmp?: Partial<{
124-
id: string;
125-
}>;
126-
};
58+
const dDsfrLoaded = new Deferred<void>();
59+
60+
export const prDsfrLoaded = dDsfrLoaded.pr;

src/tools/Deferred.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { overwriteReadonlyProp } from "tsafe/lab/overwriteReadonlyProp";
2+
3+
export class Deferred<T> {
4+
public readonly pr: Promise<T>;
5+
6+
/** NOTE: Does not need to be called bound to instance*/
7+
public readonly resolve: (value: T) => void;
8+
public readonly reject: (error: any) => void;
9+
10+
constructor() {
11+
let resolve!: (value: T) => void;
12+
let reject!: (error: any) => void;
13+
14+
this.pr = new Promise<T>((resolve_, reject_) => {
15+
resolve = value => {
16+
overwriteReadonlyProp(this, "isPending", false);
17+
resolve_(value);
18+
};
19+
20+
reject = error => {
21+
overwriteReadonlyProp(this, "isPending", false);
22+
reject_(error);
23+
};
24+
});
25+
26+
this.resolve = resolve;
27+
this.reject = reject;
28+
}
29+
30+
public readonly isPending: boolean = true;
31+
}
32+
33+
export namespace Deferred {
34+
export type Unpack<T extends Deferred<any>> = T extends Deferred<infer U> ? U : never;
35+
}
36+
37+
export class VoidDeferred extends Deferred<undefined> {
38+
public declare readonly resolve: () => void;
39+
}

0 commit comments

Comments
 (0)