@lilaquadrat/design-core 0.2.2 → 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.
Files changed (78) hide show
  1. package/README.md +71 -3
  2. package/html/index.server.html +1 -8
  3. package/package.json +53 -53
  4. package/src/client-entry.ts +8 -8
  5. package/src/components/partials/error.partial.vue +19 -19
  6. package/src/components/partials/main-components.partial.vue +75 -70
  7. package/src/components/partials/qrcode.partial.vue +8 -8
  8. package/src/functions/AuthProviderFactory.ts +30 -0
  9. package/src/functions/PaymenyProviderFactory.ts +11 -11
  10. package/src/functions/auth0.provider.ts +75 -0
  11. package/src/functions/keycloak.provider.ts +228 -0
  12. package/src/functions/lila-dom.ts +50 -50
  13. package/src/functions/shopify.provider.ts +176 -154
  14. package/src/functions/stripe.provider.ts +120 -108
  15. package/src/globals.d.ts +1 -2
  16. package/src/index.ts +9 -7
  17. package/src/interfaces/AuthCallbackResult.interface.ts +5 -0
  18. package/src/interfaces/AuthConfig.interface.ts +13 -0
  19. package/src/interfaces/AuthProvider.interface.ts +15 -0
  20. package/src/interfaces/FrontendConfig.interface.ts +11 -40
  21. package/src/interfaces/GenericEvents.interface.ts +1 -1
  22. package/src/interfaces/IdTokenExtended.interface.ts +13 -4
  23. package/src/interfaces/PaymentProvider.interface.ts +2 -2
  24. package/src/interfaces/RenderOptions.interface.ts +12 -0
  25. package/src/libs/ActionNotice.ts +125 -125
  26. package/src/libs/Models.class.ts +219 -221
  27. package/src/main.ts +41 -36
  28. package/src/mixins/createCookieString.ts +50 -36
  29. package/src/mixins/createModelDeclaration.ts +22 -19
  30. package/src/mixins/createRouter.ts +12 -12
  31. package/src/mixins/date.ts +4 -2
  32. package/src/mixins/formatSize.ts +5 -5
  33. package/src/mixins/getAnchor.ts +1 -1
  34. package/src/mixins/getRoutes.ts +13 -25
  35. package/src/mixins/hasSlotContent.ts +22 -16
  36. package/src/mixins/hooks.ts +101 -60
  37. package/src/mixins/loadComponents.ts +60 -58
  38. package/src/mixins/logger.ts +17 -13
  39. package/src/mixins/replaceVariables.ts +10 -8
  40. package/src/mixins/scroll.ts +61 -45
  41. package/src/models/Address.model.ts +7 -7
  42. package/src/models/Contact.model.ts +14 -14
  43. package/src/plugins/analytics.ts +198 -0
  44. package/src/plugins/auth.ts +74 -60
  45. package/src/plugins/currency.ts +10 -10
  46. package/src/plugins/events.ts +101 -97
  47. package/src/plugins/filters.ts +21 -18
  48. package/src/plugins/replacer.ts +7 -6
  49. package/src/plugins/signupFlow.ts +45 -43
  50. package/src/plugins/traceable.ts +28 -26
  51. package/src/plugins/translations.ts +9 -9
  52. package/src/plugins/youtube.ts +39 -34
  53. package/src/routes.ts +108 -108
  54. package/src/server-entry.ts +75 -77
  55. package/src/stores/calls.store.ts +14 -14
  56. package/src/stores/cart.store.ts +116 -107
  57. package/src/stores/content.store.ts +87 -45
  58. package/src/stores/editor.store.ts +16 -16
  59. package/src/stores/files.store.ts +72 -72
  60. package/src/stores/main.store.ts +155 -109
  61. package/src/stores/user.store.ts +72 -68
  62. package/src/translations/de.ts +127 -127
  63. package/src/views/content.view.vue +81 -143
  64. package/src/views/download.view.vue +25 -23
  65. package/src/views/editor.view.vue +150 -125
  66. package/src/views/login.view.vue +35 -36
  67. package/src/views/signup-account.view.vue +14 -14
  68. package/tooling/cypress/config.ts +68 -54
  69. package/tooling/cypress/manifest-utils.mjs +34 -22
  70. package/tooling/cypress/run-parallel.mjs +41 -35
  71. package/tooling/cypress/support/commands.ts +458 -300
  72. package/tooling/eslint.config.js +1 -223
  73. package/tooling/preview.plugin.js +68 -68
  74. package/tooling/ssr-test/index.mjs +205 -203
  75. package/tooling/vite.d.ts +0 -6
  76. package/tooling/vite.js +170 -162
  77. package/src/interfaces/EditorConfiguration.interface.ts +0 -15
  78. package/tooling/stylelint.config.mjs +0 -24
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 (context: any, routes: readonly RouteRecordRaw[], isSSR: boolean, components: AppComponents) {
38
+ export function getAppInstance(context: Partial<WorkingContext>, routes: readonly RouteRecordRaw[], isSSR: boolean, components: AppComponents) {
37
39
 
38
- const app = isSSR
39
- ? createSSRApp(components.root)
40
- : createApp(components.root);
41
- const pinia = createPinia();
40
+ const app = isSSR
41
+ ? createSSRApp(components.root)
42
+ : createApp(components.root);
43
+ const pinia = createPinia();
42
44
 
43
- app.use(pinia);
45
+ app.use(pinia);
44
46
 
45
- if (isSSR) {
47
+ if (isSSR) {
46
48
 
47
- logger.ssr('set initial state');
48
- pinia.state.value = window.__INITIAL_STATE__ as Record<string, StateTree>;
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
- const mainStore = useMainStore();
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
- if(context.data?.target === 'mail') {
58
+ console.log(55, context);
62
59
 
63
- loadViaDeclarationSync(components.modulesMail, 'lila', 'module', app);
64
- loadViaDeclarationSync(components.partialsMail, 'lila', 'partial', app);
60
+ mainStore.setContext(context);
61
+ contentStore.setRender(context);
65
62
 
66
- } else {
63
+ }
67
64
 
68
- loadViaDeclarationSync(components.modules, 'lila', 'module', app);
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
- const router = createRouter(routes);
70
+ } else {
74
71
 
75
- app.use(i18n);
76
- app.use(HelpersPlugin);
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
- app.use(router);
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
- name: string,
31
- value: string,
32
- options: CookieOptions = {}
29
+ export function createCookieString(
30
+ name: string,
31
+ value: string,
32
+ options: CookieOptions = {}
33
33
  ): string {
34
- const {
35
- expires = { value: 2, unit: 'years' },
36
- dev = false,
37
- path = '/',
38
- domain
39
- } = options;
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
- const sameSite = options.sameSite ?? (dev ? 'Lax' : 'None');
43
- const secure = options.secure ?? !dev;
44
- const cookieParts = [`${name}=${value}`];
45
- let isIframe = false;
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
- try {
48
- isIframe = window.self !== window.top;
49
- } catch (e) {
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
- if (expires) {
55
- cookieParts.push(`expires=${dayjs().add(expires.value, expires.unit).toString()}`);
56
- }
73
+ cookieParts.push(`SameSite=${sameSite}`);
57
74
 
58
- cookieParts.push(`path=${path}`);
75
+ if (secure) {
59
76
 
60
- if (domain) {
61
- cookieParts.push(`domain=${domain}`);
62
- }
77
+ cookieParts.push('Secure');
78
+
79
+ }
63
80
 
64
- cookieParts.push(`SameSite=${sameSite}`);
81
+ if(isIframe) {
65
82
 
66
- if (secure) {
67
- cookieParts.push('Secure');
68
- }
83
+ cookieParts.push('Partitioned');
84
+
85
+ }
69
86
 
70
- if(isIframe) {
71
- cookieParts.push('Partitioned');
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 (structure: BasicData<Structure & {required: boolean}>): SingleDeclaration {
4
+ export default function createModelDeclaration(structure: BasicData<Structure & {required: boolean}>): SingleDeclaration {
5
5
 
6
- if(!structure) {
7
- throw new Error('Structure is required');
8
- }
6
+ if(!structure) {
9
7
 
10
- switch(structure.type) {
11
- case 'string':
12
- case 'text':
13
- return { type: 'string' };
8
+ throw new Error('Structure is required');
14
9
 
15
- case 'number':
16
- return { type: 'number' };
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
- case 'boolean':
19
- return { type: 'boolean' };
20
+ case 'boolean':
21
+ return { type: 'boolean' };
20
22
 
21
- case 'select':
22
- return structure.multiple
23
- ? { type: 'array', contains: { type: 'string' } }
24
- : { type: 'string' };
23
+ case 'select':
24
+ return structure.multiple
25
+ ? { type: 'array', contains: { type: 'string' } }
26
+ : { type: 'string' };
25
27
 
26
- default:
27
- return {} as SingleDeclaration;
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
- if(import.meta.env.SSR) return createMemoryHistory('/');
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
- if(__PREVIEW__) return createWebHashHistory();
13
+ if(__PREVIEW__) return createWebHashHistory();
14
14
 
15
- return createWebHistory('/');
15
+ return createWebHistory('/');
16
16
 
17
17
  }
18
18
 
19
19
  export default (routes: readonly RouteRecordRaw[]) => {
20
20
 
21
- const historyMode = getHistory();
22
- const router = createRouter({
23
- history : historyMode,
24
- routes,
25
- scrollBehavior: smartScrollBehavior
26
- });
21
+ const historyMode = getHistory();
22
+ const router = createRouter({
23
+ history: historyMode,
24
+ routes,
25
+ scrollBehavior: smartScrollBehavior
26
+ });
27
27
 
28
- return router;
28
+ return router;
29
29
 
30
30
  };
@@ -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 (date?: string | number | Date | dayjs.Dayjs) {
20
- return dayjs(date).tz('Europe/Berlin');
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;
@@ -1,11 +1,11 @@
1
- export function formatSize (size?: number): string {
1
+ export function formatSize(size?: number): string {
2
2
 
3
- if (!size) return '';
3
+ if (!size) return '';
4
4
 
5
- if (size < 1024) return `${size} B`;
6
- if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)} KB`;
5
+ if (size < 1024) return `${size} B`;
6
+ if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)} KB`;
7
7
 
8
- return `${(size / 1024 / 1024).toFixed(1)} MB`;
8
+ return `${(size / 1024 / 1024).toFixed(1)} MB`;
9
9
 
10
10
  }
11
11
 
@@ -11,4 +11,4 @@
11
11
  *
12
12
  */
13
13
  export default (input: string) => input?.toLowerCase().replace(/[^\w\s-]/g, '').trim().replace(/\s+/g, '-')
14
- .replace(/-+/g, '-');
14
+ .replace(/-+/g, '-');
@@ -9,42 +9,30 @@ export interface RouteSets {
9
9
 
10
10
  export default (routeSets: RouteSets) => {
11
11
 
12
- const config = __FRONTEND_CONFIG__;
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
- if(__PREVIEW__) {
18
+ if(__PREVIEW__) {
22
19
 
23
- logger.router('mode: preview routes (static build)');
24
- return routeSets.previewRoutes;
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
- if(isIframe) {
28
+ if(isIframe) {
32
29
 
33
- logger.router('mode: editor routes');
34
- return routeSets.editorRoutes;
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
- logger.router('mode: dynamic routes');
48
- return routeSets.dynamicRoutes;
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 (slot: Slot | undefined): boolean {
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
- // Call the slot function to retrieve an array of VNodes.
16
- const nodes: VNode[] = slot();
13
+ // If the slot function does not exist, consider the slot empty.
14
+ if (!slot) return false;
17
15
 
18
- if (!nodes || nodes.length === 0) return false;
16
+ // Call the slot function to retrieve an array of VNodes.
17
+ const nodes: VNode[] = slot();
19
18
 
20
- // Check if any of the VNodes contain meaningful content.
21
- return nodes.some((node: VNode) => {
22
- // Ignore comment nodes.
23
- if (node.type === Comment) return false;
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
- // If the node's children is a string, ignore it if it’s only whitespace.
26
- if (typeof node.children === 'string' && node.children.trim() === '') {
27
- return false;
28
- }
36
+ });
29
37
 
30
- return true;
31
- });
32
38
  }
@@ -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
- router.beforeEach(async (to, from, next) => {
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
- const mainStore = useMainStore();
13
- const userStore = useUserStore();
52
+ logger.startup('start');
14
53
 
15
- if (!mainStore.startupDone) {
54
+ if(target !== 'client' && options?.initAuth !== false && !mainStore.isEditor){
55
+
56
+ await userStore.initCustomer();
57
+
58
+ }
16
59
 
17
- logger.startup('start');
60
+ mainStore.startupDone = true;
18
61
 
19
- if(!mainStore.config) {
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
- mainStore.startupDone = true;
66
+ if(target === 'client' && !mainStore.clientOnlyStartupDone) {
34
67
 
35
- logger.startup('done');
68
+ if(options?.initAuth !== false && !mainStore.isEditor) {
36
69
 
37
- } else {
70
+ const authConfig = mainStore.auth ? toAuthConfig(mainStore.auth) : undefined;
38
71
 
39
- if(target === 'client') {
72
+ if (authConfig) {
40
73
 
41
- if(!mainStore.clientOnlyStartupDone) {
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
- if(mainStore.disabledLockUpdate) mainStore.disabledLockUpdate = false;
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
- const locked = userStore.locked;
69
- const toName = typeof to.name === 'string' ? to.name : '';
109
+ const locked = userStore.locked;
110
+ const toName = typeof to.name === 'string' ? to.name : '';
70
111
 
71
- if (locked) {
112
+ if (locked) {
72
113
 
73
- const stepRoute = routeForLock(locked);
114
+ const stepRoute = routeForLock(locked);
74
115
 
75
- // a locked user heading into members content (that isn't a signup step) → current step
76
- if (to.meta?.contentType === 'members' && !toName.startsWith('signup') && toName !== stepRoute.name) {
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
- return next(stepRoute);
119
+ return next(stepRoute);
79
120
 
80
- }
121
+ }
81
122
 
82
- // a locked user on any signup screen that isn't their current step → that step
83
- // (signup-account is the external account-creation trigger, leave it alone)
84
- if (toName.startsWith('signup') && toName !== 'signup-account' && toName !== stepRoute.name) {
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
- return next(stepRoute);
127
+ return next(stepRoute);
87
128
 
88
- }
129
+ }
89
130
 
90
- } else if (toName === 'signup' || toName === 'signup-connect' || toName === 'signup-verify') {
131
+ } else if (toName === 'signup' || toName === 'signup-connect' || toName === 'signup-verify') {
91
132
 
92
- // not locked: a fully set up (authenticated) user has nothing to do here → app
93
- if (auth.isAuth.value) return next({ name: 'members' });
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
- // a guest can only start at the register step
96
- if (toName !== 'signup') return next({ name: 'signup' });
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
- next();
141
+ next();
101
142
 
102
- });
143
+ });
103
144
 
104
- };
145
+ };