@lilaquadrat/design-core 0.2.1 → 0.3.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 +76 -3
- package/html/index.server.html +1 -8
- package/package.json +54 -54
- package/src/client-entry.ts +8 -8
- package/src/components/partials/error.partial.vue +19 -19
- package/src/components/partials/main-components.partial.vue +75 -70
- package/src/components/partials/qrcode.partial.vue +8 -8
- package/src/functions/AuthProviderFactory.ts +30 -0
- package/src/functions/PaymenyProviderFactory.ts +11 -11
- package/src/functions/auth0.provider.ts +75 -0
- package/src/functions/keycloak.provider.ts +228 -0
- package/src/functions/lila-dom.ts +50 -50
- package/src/functions/shopify.provider.ts +176 -154
- package/src/functions/stripe.provider.ts +120 -108
- package/src/globals.d.ts +1 -2
- package/src/index.ts +9 -7
- package/src/interfaces/AuthCallbackResult.interface.ts +5 -0
- package/src/interfaces/AuthConfig.interface.ts +13 -0
- package/src/interfaces/AuthProvider.interface.ts +15 -0
- package/src/interfaces/FrontendConfig.interface.ts +11 -40
- package/src/interfaces/GenericEvents.interface.ts +1 -1
- package/src/interfaces/IdTokenExtended.interface.ts +13 -4
- package/src/interfaces/PaymentProvider.interface.ts +2 -2
- package/src/interfaces/RenderOptions.interface.ts +12 -0
- package/src/libs/ActionNotice.ts +125 -125
- package/src/libs/Models.class.ts +219 -221
- package/src/main.ts +41 -36
- package/src/mixins/createCookieString.ts +50 -36
- package/src/mixins/createModelDeclaration.ts +22 -19
- package/src/mixins/createRouter.ts +12 -12
- package/src/mixins/date.ts +4 -2
- package/src/mixins/formatSize.ts +5 -5
- package/src/mixins/getAnchor.ts +1 -1
- package/src/mixins/getRoutes.ts +13 -25
- package/src/mixins/hasSlotContent.ts +22 -16
- package/src/mixins/hooks.ts +101 -60
- package/src/mixins/loadComponents.ts +60 -58
- package/src/mixins/logger.ts +17 -13
- package/src/mixins/replaceVariables.ts +10 -8
- package/src/mixins/scroll.ts +61 -45
- package/src/models/Address.model.ts +7 -7
- package/src/models/Contact.model.ts +14 -14
- package/src/plugins/analytics.ts +198 -0
- package/src/plugins/auth.ts +74 -60
- package/src/plugins/currency.ts +10 -10
- package/src/plugins/events.ts +101 -97
- package/src/plugins/filters.ts +21 -18
- package/src/plugins/replacer.ts +7 -6
- package/src/plugins/signupFlow.ts +45 -43
- package/src/plugins/traceable.ts +28 -26
- package/src/plugins/translations.ts +9 -9
- package/src/plugins/youtube.ts +39 -34
- package/src/routes.ts +108 -108
- package/src/server-entry.ts +75 -77
- package/src/stores/calls.store.ts +14 -14
- package/src/stores/cart.store.ts +116 -107
- package/src/stores/content.store.ts +87 -45
- package/src/stores/editor.store.ts +16 -16
- package/src/stores/files.store.ts +72 -72
- package/src/stores/main.store.ts +155 -109
- package/src/stores/user.store.ts +72 -68
- package/src/translations/de.ts +127 -127
- package/src/views/content.view.vue +81 -143
- package/src/views/download.view.vue +25 -23
- package/src/views/editor.view.vue +150 -125
- package/src/views/login.view.vue +35 -36
- package/src/views/signup-account.view.vue +14 -14
- package/tooling/cypress/config.ts +68 -54
- package/tooling/cypress/manifest-utils.mjs +34 -22
- package/tooling/cypress/run-parallel.mjs +41 -35
- package/tooling/cypress/support/commands.ts +458 -300
- package/tooling/eslint.config.js +1 -223
- package/tooling/preview.plugin.js +132 -0
- package/tooling/ssr-test/index.mjs +205 -203
- package/tooling/vite.d.ts +36 -0
- package/tooling/vite.js +234 -0
- package/src/interfaces/EditorConfiguration.interface.ts +0 -15
- package/tooling/preview.plugin.ts +0 -134
- package/tooling/stylelint.config.mjs +0 -24
- package/tooling/vite.ts +0 -260
package/src/main.ts
CHANGED
|
@@ -17,8 +17,10 @@ import currencyPlugin from './plugins/currency';
|
|
|
17
17
|
import eventsPlugin from './plugins/events';
|
|
18
18
|
import './models';
|
|
19
19
|
import type { RouteRecordRaw } from 'vue-router';
|
|
20
|
+
import type { WorkingContext } from '@lilaquadrat/interfaces';
|
|
20
21
|
import logger from './mixins/logger';
|
|
21
22
|
import useMainStore from './stores/main.store';
|
|
23
|
+
import useContentStore from './stores/content.store';
|
|
22
24
|
|
|
23
25
|
/**
|
|
24
26
|
* everything the project owns and the package cannot know: the root component
|
|
@@ -33,55 +35,58 @@ export interface AppComponents {
|
|
|
33
35
|
partialsMail: { name: string, component: Component }[]
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
export function getAppInstance
|
|
38
|
+
export function getAppInstance(context: Partial<WorkingContext>, routes: readonly RouteRecordRaw[], isSSR: boolean, components: AppComponents) {
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
const app = isSSR
|
|
41
|
+
? createSSRApp(components.root)
|
|
42
|
+
: createApp(components.root);
|
|
43
|
+
const pinia = createPinia();
|
|
42
44
|
|
|
43
|
-
|
|
45
|
+
app.use(pinia);
|
|
44
46
|
|
|
45
|
-
|
|
47
|
+
if (isSSR) {
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
} else {
|
|
49
|
+
logger.ssr('set initial state');
|
|
50
|
+
pinia.state.value = window.__INITIAL_STATE__ as Record<string, StateTree>;
|
|
51
|
+
console.log(window.__INITIAL_STATE__);
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
mainStore.data = context.data;
|
|
55
|
-
mainStore.layout = context.layout;
|
|
56
|
-
mainStore.target = context.data?.target || 'browser';
|
|
57
|
-
mainStore.configuration = context.settings;
|
|
53
|
+
} else {
|
|
58
54
|
|
|
59
|
-
|
|
55
|
+
const mainStore = useMainStore();
|
|
56
|
+
const contentStore = useContentStore();
|
|
60
57
|
|
|
61
|
-
|
|
58
|
+
console.log(55, context);
|
|
62
59
|
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
mainStore.setContext(context);
|
|
61
|
+
contentStore.setRender(context);
|
|
65
62
|
|
|
66
|
-
|
|
63
|
+
}
|
|
67
64
|
|
|
68
|
-
|
|
69
|
-
loadViaDeclarationSync(components.partials, 'lila', 'partial', app);
|
|
65
|
+
if(context.content?.target === 'mail') {
|
|
70
66
|
|
|
71
|
-
|
|
67
|
+
loadViaDeclarationSync(components.modulesMail, 'lila', 'module', app);
|
|
68
|
+
loadViaDeclarationSync(components.partialsMail, 'lila', 'partial', app);
|
|
72
69
|
|
|
73
|
-
|
|
70
|
+
} else {
|
|
74
71
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
app.use(youtubePlugin);
|
|
78
|
-
app.use(traceablePlugin);
|
|
79
|
-
app.use(authPlugin);
|
|
80
|
-
app.use(replacerPlugin);
|
|
81
|
-
app.use(currencyPlugin);
|
|
82
|
-
app.use(eventsPlugin);
|
|
72
|
+
loadViaDeclarationSync(components.modules, 'lila', 'module', app);
|
|
73
|
+
loadViaDeclarationSync(components.partials, 'lila', 'partial', app);
|
|
83
74
|
|
|
84
|
-
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const router = createRouter(routes);
|
|
78
|
+
|
|
79
|
+
app.use(i18n);
|
|
80
|
+
app.use(HelpersPlugin);
|
|
81
|
+
app.use(youtubePlugin);
|
|
82
|
+
app.use(traceablePlugin);
|
|
83
|
+
app.use(authPlugin);
|
|
84
|
+
app.use(replacerPlugin);
|
|
85
|
+
app.use(currencyPlugin);
|
|
86
|
+
app.use(eventsPlugin);
|
|
87
|
+
|
|
88
|
+
app.use(router);
|
|
89
|
+
|
|
90
|
+
return { app, router, pinia };
|
|
85
91
|
|
|
86
|
-
return { app, router, pinia };
|
|
87
92
|
}
|
|
@@ -26,53 +26,67 @@ interface CookieOptions {
|
|
|
26
26
|
* expires: { value: 2, unit: 'years' }
|
|
27
27
|
* });
|
|
28
28
|
*/
|
|
29
|
-
export function createCookieString
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
export function createCookieString(
|
|
30
|
+
name: string,
|
|
31
|
+
value: string,
|
|
32
|
+
options: CookieOptions = {}
|
|
33
33
|
): string {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
|
|
35
|
+
const {
|
|
36
|
+
expires = { value: 2, unit: 'years' },
|
|
37
|
+
dev = false,
|
|
38
|
+
path = '/',
|
|
39
|
+
domain
|
|
40
|
+
} = options;
|
|
40
41
|
// Set sameSite and secure based on dev mode
|
|
41
42
|
// Can be overridden by explicitly setting these values in options
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
const sameSite = options.sameSite ?? (dev ? 'Lax' : 'None');
|
|
44
|
+
const secure = options.secure ?? !dev;
|
|
45
|
+
const cookieParts = [`${name}=${value}`];
|
|
46
|
+
let isIframe = false;
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
|
|
50
|
+
isIframe = window.self !== window.top;
|
|
51
|
+
|
|
52
|
+
} catch (e) {
|
|
53
|
+
|
|
54
|
+
// If an error occurs, assume the page is in an iframe.
|
|
55
|
+
isIframe = true;
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (expires) {
|
|
60
|
+
|
|
61
|
+
cookieParts.push(`expires=${dayjs().add(expires.value, expires.unit).toString()}`);
|
|
62
|
+
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
cookieParts.push(`path=${path}`);
|
|
66
|
+
|
|
67
|
+
if (domain) {
|
|
46
68
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
// If an error occurs, assume the page is in an iframe.
|
|
51
|
-
isIframe = true;
|
|
52
|
-
}
|
|
69
|
+
cookieParts.push(`domain=${domain}`);
|
|
70
|
+
|
|
71
|
+
}
|
|
53
72
|
|
|
54
|
-
|
|
55
|
-
cookieParts.push(`expires=${dayjs().add(expires.value, expires.unit).toString()}`);
|
|
56
|
-
}
|
|
73
|
+
cookieParts.push(`SameSite=${sameSite}`);
|
|
57
74
|
|
|
58
|
-
|
|
75
|
+
if (secure) {
|
|
59
76
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
77
|
+
cookieParts.push('Secure');
|
|
78
|
+
|
|
79
|
+
}
|
|
63
80
|
|
|
64
|
-
|
|
81
|
+
if(isIframe) {
|
|
65
82
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
83
|
+
cookieParts.push('Partitioned');
|
|
84
|
+
|
|
85
|
+
}
|
|
69
86
|
|
|
70
|
-
|
|
71
|
-
cookieParts.
|
|
72
|
-
}
|
|
87
|
+
console.log(cookieParts.join('; ').trim());
|
|
88
|
+
return cookieParts.join('; ').trim();
|
|
73
89
|
|
|
74
|
-
console.log(cookieParts.join('; ').trim());
|
|
75
|
-
return cookieParts.join('; ').trim();
|
|
76
90
|
}
|
|
77
91
|
|
|
78
92
|
export default createCookieString;
|
|
@@ -1,29 +1,32 @@
|
|
|
1
1
|
import type { SingleDeclaration } from '../libs/Models.class';
|
|
2
2
|
import type { BasicData, Structure } from '@lilaquadrat/interfaces';
|
|
3
3
|
|
|
4
|
-
export default function createModelDeclaration
|
|
4
|
+
export default function createModelDeclaration(structure: BasicData<Structure & {required: boolean}>): SingleDeclaration {
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
throw new Error('Structure is required');
|
|
8
|
-
}
|
|
6
|
+
if(!structure) {
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
case 'string':
|
|
12
|
-
case 'text':
|
|
13
|
-
return { type: 'string' };
|
|
8
|
+
throw new Error('Structure is required');
|
|
14
9
|
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
switch(structure.type) {
|
|
13
|
+
case 'string':
|
|
14
|
+
case 'text':
|
|
15
|
+
return { type: 'string' };
|
|
16
|
+
|
|
17
|
+
case 'number':
|
|
18
|
+
return { type: 'number' };
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
case 'boolean':
|
|
21
|
+
return { type: 'boolean' };
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
case 'select':
|
|
24
|
+
return structure.multiple
|
|
25
|
+
? { type: 'array', contains: { type: 'string' } }
|
|
26
|
+
: { type: 'string' };
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
default:
|
|
29
|
+
return {} as SingleDeclaration;
|
|
30
|
+
}
|
|
31
|
+
|
|
29
32
|
}
|
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
import { createMemoryHistory, createRouter, createWebHashHistory, createWebHistory, type RouteRecordRaw } from 'vue-router';
|
|
2
2
|
import { smartScrollBehavior } from './scroll';
|
|
3
3
|
|
|
4
|
-
function getHistory
|
|
4
|
+
function getHistory() {
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
if(import.meta.env.SSR) return createMemoryHistory('/');
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
9
|
* the shareable static preview is opened straight from disk, where pushState
|
|
10
10
|
* is blocked and no server exists to rewrite deep links - so the route has
|
|
11
11
|
* to live in the hash
|
|
12
12
|
*/
|
|
13
|
-
|
|
13
|
+
if(__PREVIEW__) return createWebHashHistory();
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
return createWebHistory('/');
|
|
16
16
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export default (routes: readonly RouteRecordRaw[]) => {
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
const historyMode = getHistory();
|
|
22
|
+
const router = createRouter({
|
|
23
|
+
history: historyMode,
|
|
24
|
+
routes,
|
|
25
|
+
scrollBehavior: smartScrollBehavior
|
|
26
|
+
});
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
return router;
|
|
29
29
|
|
|
30
30
|
};
|
package/src/mixins/date.ts
CHANGED
|
@@ -16,8 +16,10 @@ dayjs.locale('de');
|
|
|
16
16
|
* @param date Optional date parameter to initialize the dayjs instance with
|
|
17
17
|
* @returns A dayjs instance with Berlin timezone
|
|
18
18
|
*/
|
|
19
|
-
export function useDate
|
|
20
|
-
|
|
19
|
+
export function useDate(date?: string | number | Date | dayjs.Dayjs) {
|
|
20
|
+
|
|
21
|
+
return dayjs(date).tz('Europe/Berlin');
|
|
22
|
+
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
export default useDate;
|
package/src/mixins/formatSize.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export function formatSize
|
|
1
|
+
export function formatSize(size?: number): string {
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
if (!size) return '';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
if (size < 1024) return `${size} B`;
|
|
6
|
+
if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)} KB`;
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
return `${(size / 1024 / 1024).toFixed(1)} MB`;
|
|
9
9
|
|
|
10
10
|
}
|
|
11
11
|
|
package/src/mixins/getAnchor.ts
CHANGED
package/src/mixins/getRoutes.ts
CHANGED
|
@@ -9,42 +9,30 @@ export interface RouteSets {
|
|
|
9
9
|
|
|
10
10
|
export default (routeSets: RouteSets) => {
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
const mode = import.meta.env.MODE;
|
|
14
|
-
const isIframe = window !== window.top;
|
|
15
|
-
const isDynamic = config.dynamic === true;
|
|
12
|
+
const isIframe = window !== window.top;
|
|
16
13
|
|
|
17
|
-
|
|
14
|
+
/**
|
|
18
15
|
* the shareable static build (yarn build:preview) is always the module
|
|
19
16
|
* gallery - it has no backend and no editor parent to talk to
|
|
20
17
|
*/
|
|
21
|
-
|
|
18
|
+
if(__PREVIEW__) {
|
|
22
19
|
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
logger.router('mode: preview routes (static build)');
|
|
21
|
+
return routeSets.previewRoutes;
|
|
25
22
|
|
|
26
|
-
|
|
23
|
+
}
|
|
27
24
|
|
|
28
|
-
|
|
25
|
+
/**
|
|
29
26
|
* running in an iframe indicates that we are in the STUDIO editor
|
|
30
27
|
*/
|
|
31
|
-
|
|
28
|
+
if(isIframe) {
|
|
32
29
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* no iframe but development mode indicates that the design is started locally
|
|
39
|
-
*/
|
|
40
|
-
if(mode === 'development' && !isDynamic) {
|
|
41
|
-
|
|
42
|
-
logger.router('mode: preview routes');
|
|
43
|
-
return routeSets.previewRoutes
|
|
30
|
+
logger.router('mode: editor routes');
|
|
31
|
+
return routeSets.editorRoutes;
|
|
44
32
|
|
|
45
|
-
|
|
33
|
+
}
|
|
46
34
|
|
|
47
|
-
|
|
48
|
-
|
|
35
|
+
logger.router('mode: dynamic routes');
|
|
36
|
+
return routeSets.dynamicRoutes;
|
|
49
37
|
|
|
50
38
|
}
|
|
@@ -8,25 +8,31 @@ import { Comment } from 'vue';
|
|
|
8
8
|
* @param slot - The slot function to check.
|
|
9
9
|
* @returns True if the slot has meaningful content, false otherwise.
|
|
10
10
|
*/
|
|
11
|
-
export function hasSlotContent
|
|
12
|
-
// If the slot function does not exist, consider the slot empty.
|
|
13
|
-
if (!slot) return false;
|
|
11
|
+
export function hasSlotContent(slot: Slot | undefined): boolean {
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
// If the slot function does not exist, consider the slot empty.
|
|
14
|
+
if (!slot) return false;
|
|
17
15
|
|
|
18
|
-
|
|
16
|
+
// Call the slot function to retrieve an array of VNodes.
|
|
17
|
+
const nodes: VNode[] = slot();
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
//
|
|
23
|
-
|
|
19
|
+
if (!nodes || nodes.length === 0) return false;
|
|
20
|
+
|
|
21
|
+
// Check if any of the VNodes contain meaningful content.
|
|
22
|
+
return nodes.some((node: VNode) => {
|
|
23
|
+
|
|
24
|
+
// Ignore comment nodes.
|
|
25
|
+
if (node.type === Comment) return false;
|
|
26
|
+
|
|
27
|
+
// If the node's children is a string, ignore it if it’s only whitespace.
|
|
28
|
+
if (typeof node.children === 'string' && node.children.trim() === '') {
|
|
29
|
+
|
|
30
|
+
return false;
|
|
31
|
+
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return true;
|
|
24
35
|
|
|
25
|
-
|
|
26
|
-
if (typeof node.children === 'string' && node.children.trim() === '') {
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
36
|
+
});
|
|
29
37
|
|
|
30
|
-
return true;
|
|
31
|
-
});
|
|
32
38
|
}
|
package/src/mixins/hooks.ts
CHANGED
|
@@ -1,104 +1,145 @@
|
|
|
1
1
|
import { useMainStore } from '../stores/main.store'
|
|
2
|
-
import type { Router } from 'vue-router';
|
|
2
|
+
import type { RouteLocationRaw, Router } from 'vue-router';
|
|
3
|
+
import type { WorkingAuth } from '@lilaquadrat/interfaces';
|
|
4
|
+
import type AuthConfig from '../interfaces/AuthConfig.interface';
|
|
3
5
|
import logger from './logger';
|
|
4
6
|
import { auth } from '../plugins/auth';
|
|
5
7
|
import useUserStore from '../stores/user.store';
|
|
6
8
|
import { routeForLock } from '../plugins/signupFlow';
|
|
7
9
|
|
|
10
|
+
/**
|
|
11
|
+
* the working context carries only what the frontend needs to log in; the
|
|
12
|
+
* provider factories still expect their own config shape
|
|
13
|
+
*/
|
|
14
|
+
function toAuthConfig(workingAuth: WorkingAuth): AuthConfig | undefined {
|
|
15
|
+
|
|
16
|
+
if (workingAuth.provider === 'auth0') {
|
|
17
|
+
|
|
18
|
+
if (!workingAuth.domain || !workingAuth.clientId) return undefined;
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
type: 'auth0',
|
|
22
|
+
options: {
|
|
23
|
+
domain: workingAuth.domain,
|
|
24
|
+
clientId: workingAuth.clientId,
|
|
25
|
+
authorizationParams: { audience: workingAuth.audience },
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
type: 'keycloak',
|
|
33
|
+
url: workingAuth.url,
|
|
34
|
+
realm: workingAuth.realm,
|
|
35
|
+
clientId: workingAuth.clientId,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
|
|
8
40
|
export default (router: Router, options?: {initAuth?: boolean}, target: 'server' | 'client' = 'server') => {
|
|
9
41
|
|
|
10
|
-
|
|
42
|
+
router.beforeEach(async (to, from, next) => {
|
|
43
|
+
|
|
44
|
+
const mainStore = useMainStore();
|
|
45
|
+
const userStore = useUserStore();
|
|
46
|
+
let startupRedirect: RouteLocationRaw | undefined;
|
|
47
|
+
|
|
48
|
+
if (target === 'client') mainStore.isEditor = window !== window.top;
|
|
49
|
+
|
|
50
|
+
if (!mainStore.startupDone) {
|
|
11
51
|
|
|
12
|
-
|
|
13
|
-
const userStore = useUserStore();
|
|
52
|
+
logger.startup('start');
|
|
14
53
|
|
|
15
|
-
|
|
54
|
+
if(target !== 'client' && options?.initAuth !== false && !mainStore.isEditor){
|
|
55
|
+
|
|
56
|
+
await userStore.initCustomer();
|
|
57
|
+
|
|
58
|
+
}
|
|
16
59
|
|
|
17
|
-
|
|
60
|
+
mainStore.startupDone = true;
|
|
18
61
|
|
|
19
|
-
|
|
20
|
-
mainStore.config = __FRONTEND_CONFIG__;
|
|
21
|
-
}
|
|
62
|
+
logger.startup('done');
|
|
22
63
|
|
|
23
|
-
if(options?.initAuth !== false && !mainStore.isEditor){
|
|
24
|
-
if (mainStore.config?.auth0Options) {
|
|
25
|
-
|
|
26
|
-
await auth.init(mainStore.config.auth0Options);
|
|
27
|
-
|
|
28
64
|
}
|
|
29
|
-
|
|
30
|
-
await userStore.initCustomer();
|
|
31
|
-
}
|
|
32
65
|
|
|
33
|
-
|
|
66
|
+
if(target === 'client' && !mainStore.clientOnlyStartupDone) {
|
|
34
67
|
|
|
35
|
-
|
|
68
|
+
if(options?.initAuth !== false && !mainStore.isEditor) {
|
|
36
69
|
|
|
37
|
-
|
|
70
|
+
const authConfig = mainStore.auth ? toAuthConfig(mainStore.auth) : undefined;
|
|
38
71
|
|
|
39
|
-
|
|
72
|
+
if (authConfig) {
|
|
40
73
|
|
|
41
|
-
|
|
74
|
+
const locationBeforeAuth = window.location.href;
|
|
75
|
+
await auth.init(authConfig);
|
|
76
|
+
|
|
77
|
+
if (window.location.href !== locationBeforeAuth) {
|
|
78
|
+
|
|
79
|
+
// The SDK cleaned its callback, but the pending router navigation still has the old query.
|
|
80
|
+
const location = new URL(window.location.href);
|
|
81
|
+
const cleanedRoute = router.resolve(location.pathname + location.search + location.hash);
|
|
82
|
+
|
|
83
|
+
if (cleanedRoute.fullPath !== to.fullPath) {
|
|
84
|
+
|
|
85
|
+
startupRedirect = { path: cleanedRoute.path, query: cleanedRoute.query, hash: cleanedRoute.hash, replace: true };
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
await userStore.initCustomer();
|
|
42
94
|
|
|
43
|
-
if(options?.initAuth !== false) {
|
|
44
|
-
|
|
45
|
-
if (mainStore.config?.auth0Options) {
|
|
46
|
-
|
|
47
|
-
await auth.init(mainStore.config.auth0Options);
|
|
48
|
-
|
|
49
95
|
}
|
|
50
|
-
|
|
51
|
-
await userStore.initCustomer();
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
mainStore.clientOnlyStartupDone = true;
|
|
55
96
|
|
|
56
|
-
|
|
97
|
+
mainStore.clientOnlyStartupDone = true;
|
|
57
98
|
|
|
58
|
-
|
|
99
|
+
}
|
|
59
100
|
|
|
60
|
-
|
|
101
|
+
if (startupRedirect) return next(startupRedirect);
|
|
61
102
|
|
|
62
|
-
|
|
103
|
+
if(mainStore.disabledLockUpdate) mainStore.disabledLockUpdate = false;
|
|
63
104
|
|
|
64
|
-
|
|
105
|
+
/**
|
|
65
106
|
* signup gate: locked users are forced through the signup steps before they can
|
|
66
107
|
* reach any members area. public pages stay reachable.
|
|
67
108
|
*/
|
|
68
|
-
|
|
69
|
-
|
|
109
|
+
const locked = userStore.locked;
|
|
110
|
+
const toName = typeof to.name === 'string' ? to.name : '';
|
|
70
111
|
|
|
71
|
-
|
|
112
|
+
if (locked) {
|
|
72
113
|
|
|
73
|
-
|
|
114
|
+
const stepRoute = routeForLock(locked);
|
|
74
115
|
|
|
75
|
-
|
|
76
|
-
|
|
116
|
+
// a locked user heading into members content (that isn't a signup step) → current step
|
|
117
|
+
if (to.meta?.contentType === 'members' && !toName.startsWith('signup') && toName !== stepRoute.name) {
|
|
77
118
|
|
|
78
|
-
|
|
119
|
+
return next(stepRoute);
|
|
79
120
|
|
|
80
|
-
|
|
121
|
+
}
|
|
81
122
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
123
|
+
// a locked user on any signup screen that isn't their current step → that step
|
|
124
|
+
// (signup-account is the external account-creation trigger, leave it alone)
|
|
125
|
+
if (toName.startsWith('signup') && toName !== 'signup-account' && toName !== stepRoute.name) {
|
|
85
126
|
|
|
86
|
-
|
|
127
|
+
return next(stepRoute);
|
|
87
128
|
|
|
88
|
-
|
|
129
|
+
}
|
|
89
130
|
|
|
90
|
-
|
|
131
|
+
} else if (toName === 'signup' || toName === 'signup-connect' || toName === 'signup-verify') {
|
|
91
132
|
|
|
92
|
-
|
|
93
|
-
|
|
133
|
+
// not locked: a fully set up (authenticated) user has nothing to do here → app
|
|
134
|
+
if (auth.isAuth.value) return next({ name: 'members' });
|
|
94
135
|
|
|
95
|
-
|
|
96
|
-
|
|
136
|
+
// a guest can only start at the register step
|
|
137
|
+
if (toName !== 'signup') return next({ name: 'signup' });
|
|
97
138
|
|
|
98
|
-
|
|
139
|
+
}
|
|
99
140
|
|
|
100
|
-
|
|
141
|
+
next();
|
|
101
142
|
|
|
102
|
-
|
|
143
|
+
});
|
|
103
144
|
|
|
104
|
-
};
|
|
145
|
+
};
|