@akinon/projectzero 1.126.20-v1-rc.17 → 1.126.20

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 (80) hide show
  1. package/CHANGELOG.md +1 -5
  2. package/app-template/.env.example +6 -0
  3. package/app-template/CHANGELOG.md +39 -35
  4. package/app-template/package.json +29 -28
  5. package/app-template/public/locales/en/checkout.json +50 -0
  6. package/app-template/public/locales/tr/checkout.json +50 -0
  7. package/app-template/src/app/[pz]/account/(dashboard)/layout.tsx +20 -0
  8. package/app-template/src/app/[pz]/account/account-page-slot.tsx +35 -0
  9. package/app-template/src/app/[pz]/account/address/layout.tsx +18 -0
  10. package/app-template/src/app/[pz]/account/change-email/layout.tsx +18 -0
  11. package/app-template/src/app/[pz]/account/change-password/layout.tsx +18 -0
  12. package/app-template/src/app/[pz]/account/contact/layout.tsx +18 -0
  13. package/app-template/src/app/[pz]/account/coupons/layout.tsx +18 -0
  14. package/app-template/src/app/[pz]/account/faq/layout.tsx +14 -0
  15. package/app-template/src/app/[pz]/account/favourite-products/layout.tsx +21 -0
  16. package/app-template/src/app/[pz]/account/layout.tsx +36 -3
  17. package/app-template/src/app/[pz]/account/orders/(list)/layout.tsx +20 -0
  18. package/app-template/src/app/[pz]/account/orders/[id]/(detail)/layout.tsx +40 -0
  19. package/app-template/src/app/[pz]/account/profile/layout.tsx +18 -0
  20. package/app-template/src/app/[pz]/auth/(login)/layout.tsx +37 -0
  21. package/app-template/src/app/[pz]/basket/layout.tsx +25 -0
  22. package/app-template/src/app/[pz]/client-root.tsx +2 -0
  23. package/app-template/src/app/[pz]/configure-page-context.ts +17 -0
  24. package/app-template/src/app/[pz]/layout.tsx +22 -3
  25. package/app-template/src/app/[pz]/orders/checkout/layout.tsx +47 -0
  26. package/app-template/src/app/[pz]/orders/checkout/page.tsx +75 -97
  27. package/app-template/src/app/[pz]/orders/completed/[token]/layout.tsx +24 -2
  28. package/app-template/src/app/[pz]/users/password/reset/layout.tsx +21 -0
  29. package/app-template/src/app/[pz]/users/reset/[[...id]]/layout.tsx +30 -0
  30. package/app-template/src/components/checkbox.tsx +22 -3
  31. package/app-template/src/components/route-handler.tsx +48 -0
  32. package/app-template/src/routes/index.ts +6 -6
  33. package/app-template/src/views/checkout/__tests__/part-style-reachability.test.ts +119 -0
  34. package/app-template/src/views/checkout/step-button.tsx +13 -2
  35. package/app-template/src/views/checkout/step-list.tsx +5 -1
  36. package/app-template/src/views/checkout/steps/payment/agreements.tsx +9 -1
  37. package/app-template/src/views/checkout/steps/payment/index.tsx +10 -2
  38. package/app-template/src/views/checkout/steps/payment/options/credit-card/index.tsx +2 -0
  39. package/app-template/src/views/checkout/steps/payment/options/funds-transfer.tsx +2 -0
  40. package/app-template/src/views/checkout/steps/payment/payment-header.tsx +5 -1
  41. package/app-template/src/views/checkout/steps/payment/payment-option-buttons.tsx +16 -4
  42. package/app-template/src/views/checkout/steps/shipping/addresses.tsx +2 -1
  43. package/app-template/src/views/checkout/steps/shipping/index.tsx +2 -0
  44. package/app-template/src/views/checkout/steps/shipping/shipping-options.tsx +2 -0
  45. package/app-template/src/views/checkout/summary.tsx +56 -18
  46. package/app-template/src/views/checkout/variants/__tests__/registry.test.tsx +82 -0
  47. package/app-template/src/views/checkout/variants/__tests__/use-resolved-config.test.tsx +208 -0
  48. package/app-template/src/views/checkout/variants/basket-and-checkout/basket-section.tsx +150 -0
  49. package/app-template/src/views/checkout/variants/basket-and-checkout/index.tsx +135 -0
  50. package/app-template/src/views/checkout/variants/multi-step/index.tsx +78 -0
  51. package/app-template/src/views/checkout/variants/one-page/accordion-section.tsx +165 -0
  52. package/app-template/src/views/checkout/variants/one-page/hooks/use-checkout-funnel-gtm.ts +60 -0
  53. package/app-template/src/views/checkout/variants/one-page/hooks/use-section-state.ts +103 -0
  54. package/app-template/src/views/checkout/variants/one-page/index.tsx +125 -0
  55. package/app-template/src/views/checkout/variants/one-page/mobile-summary-sheet.tsx +109 -0
  56. package/app-template/src/views/checkout/variants/one-page/one-page-summary.tsx +301 -0
  57. package/app-template/src/views/checkout/variants/one-page/payment-options-grid.tsx +220 -0
  58. package/app-template/src/views/checkout/variants/one-page/sections/address-section.tsx +320 -0
  59. package/app-template/src/views/checkout/variants/one-page/sections/contact-section.tsx +62 -0
  60. package/app-template/src/views/checkout/variants/one-page/sections/payment-section.tsx +73 -0
  61. package/app-template/src/views/checkout/variants/one-page/sections/shipping-section.tsx +328 -0
  62. package/app-template/src/views/checkout/variants/one-page/skeletons/address-skeleton.tsx +25 -0
  63. package/app-template/src/views/checkout/variants/one-page/skeletons/checkout-skeleton.tsx +27 -0
  64. package/app-template/src/views/checkout/variants/one-page/skeletons/index.ts +6 -0
  65. package/app-template/src/views/checkout/variants/one-page/skeletons/payment-skeleton.tsx +23 -0
  66. package/app-template/src/views/checkout/variants/one-page/skeletons/section-skeleton.tsx +47 -0
  67. package/app-template/src/views/checkout/variants/one-page/skeletons/shipping-skeleton.tsx +20 -0
  68. package/app-template/src/views/checkout/variants/one-page/skeletons/summary-skeleton.tsx +38 -0
  69. package/app-template/src/views/checkout/variants/one-page/trust-badges.tsx +35 -0
  70. package/app-template/src/views/checkout/variants/registry.ts +43 -0
  71. package/app-template/src/views/checkout/variants/types.ts +30 -0
  72. package/app-template/src/views/checkout/variants/use-resolved-config.ts +168 -0
  73. package/app-template/tailwind.config.js +3 -1
  74. package/dist/commands/plugins.js +23 -2
  75. package/package.json +1 -1
  76. package/app-template/src/app/[pz]/account/orders/[id]/layout.tsx +0 -5
  77. /package/app-template/src/app/[pz]/account/{page.tsx → (dashboard)/page.tsx} +0 -0
  78. /package/app-template/src/app/[pz]/account/orders/{page.tsx → (list)/page.tsx} +0 -0
  79. /package/app-template/src/app/[pz]/account/orders/[id]/{page.tsx → (detail)/page.tsx} +0 -0
  80. /package/app-template/src/app/[pz]/auth/{page.tsx → (login)/page.tsx} +0 -0
@@ -0,0 +1,168 @@
1
+ 'use client';
2
+
3
+ import {
4
+ useEffect,
5
+ useLayoutEffect,
6
+ useMemo,
7
+ useState,
8
+ useSyncExternalStore
9
+ } from 'react';
10
+ import settings from '@theme/settings';
11
+ import {
12
+ getCheckoutFlowVariantOverride,
13
+ isThemeEditorDesigner,
14
+ noFlowVariantOnServer,
15
+ subscribeCheckoutPieces,
16
+ type CheckoutFlowVariantPreference
17
+ } from '@akinon/pz-theme/src/chrome/checkout-pieces';
18
+ import { isKnownVariant } from './registry';
19
+ import type { CheckoutVariantId, CheckoutVariantOptions } from './types';
20
+
21
+ export interface ResolvedCheckoutConfig {
22
+ variantId: CheckoutVariantId;
23
+ options: CheckoutVariantOptions;
24
+ }
25
+
26
+ interface RawCheckoutConfig {
27
+ variant?: string;
28
+ options?: Record<string, unknown>;
29
+ }
30
+
31
+ const FALLBACK_VARIANT: CheckoutVariantId = 'multi-step';
32
+
33
+ /**
34
+ * The only two layouts a composition may steer to, mapped to variant ids. A
35
+ * closed record on purpose: an unknown preference resolves to `undefined` here
36
+ * and the storefront's configured variant survives — and the unified
37
+ * basket-and-checkout family stays unreachable from a composition, so the
38
+ * basket-to-checkout redirect pair can never be broken by a page edit.
39
+ */
40
+ const COMPOSITION_VARIANT_MAP: Record<
41
+ CheckoutFlowVariantPreference,
42
+ CheckoutVariantId
43
+ > = {
44
+ 'one-page': 'one-page',
45
+ 'step-by-step': 'multi-step'
46
+ };
47
+
48
+ const coerceOptions = (
49
+ raw: Record<string, unknown> | undefined
50
+ ): CheckoutVariantOptions => {
51
+ if (!raw) return {};
52
+ const cast = raw as Partial<CheckoutVariantOptions>;
53
+ const out: CheckoutVariantOptions = {};
54
+ if (typeof cast.enableEditMode === 'boolean')
55
+ out.enableEditMode = cast.enableEditMode;
56
+ if (typeof cast.autoAdvance === 'boolean') out.autoAdvance = cast.autoAdvance;
57
+ if (typeof cast.stickyMobileCta === 'boolean')
58
+ out.stickyMobileCta = cast.stickyMobileCta;
59
+ if (typeof cast.showOrderReview === 'boolean')
60
+ out.showOrderReview = cast.showOrderReview;
61
+ if (typeof cast.showTrustBadges === 'boolean')
62
+ out.showTrustBadges = cast.showTrustBadges;
63
+ if (typeof cast.gtmEnabled === 'boolean') out.gtmEnabled = cast.gtmEnabled;
64
+ if (typeof cast.compactMode === 'boolean') out.compactMode = cast.compactMode;
65
+ return out;
66
+ };
67
+
68
+ const readBaseFromSettings = (): ResolvedCheckoutConfig => {
69
+ const fromSettings = (settings as { checkout?: RawCheckoutConfig })?.checkout;
70
+ const variantId = isKnownVariant(fromSettings?.variant)
71
+ ? fromSettings.variant
72
+ : FALLBACK_VARIANT;
73
+ return {
74
+ variantId,
75
+ options: coerceOptions(fromSettings?.options)
76
+ };
77
+ };
78
+
79
+ const mergeOverride = (
80
+ base: ResolvedCheckoutConfig,
81
+ override: RawCheckoutConfig | undefined
82
+ ): ResolvedCheckoutConfig => {
83
+ if (!override) return base;
84
+ return {
85
+ variantId: isKnownVariant(override.variant)
86
+ ? override.variant
87
+ : base.variantId,
88
+ options: { ...base.options, ...coerceOptions(override.options) }
89
+ };
90
+ };
91
+
92
+ /**
93
+ * Resolves checkout config from three layers (each optional):
94
+ *
95
+ * 1. settings.js (sync, always available — baseline / fallback)
96
+ * 2. /api/theme-settings (backend theme-config widget — persistent override)
97
+ * 3. the composition's checkout flow outlet (`flowVariant`) — highest
98
+ *
99
+ * Layer 2 falls back silently if backend is unreachable or no config is saved.
100
+ * The editor is OPTIONAL — when no theme-config is saved, the storefront keeps
101
+ * using its built-in settings.js.
102
+ *
103
+ * Layer 3 only ever names a LAYOUT, never options, and only through the
104
+ * closed `COMPOSITION_VARIANT_MAP`. It is read ONCE, in a layout effect, so a
105
+ * composed checkout resolves its variant before first paint (the outlet's own
106
+ * registration layout effect runs in an earlier sibling subtree of the same
107
+ * hydration commit) and never flips mid-session — a late registration, or the
108
+ * theme-settings response landing afterwards, can no longer swap the flow out
109
+ * from under a shopper. On the designer canvas the live value is followed
110
+ * instead, so a `Checkout Type` edit previews immediately.
111
+ *
112
+ * With no outlet registered, nothing overrides: the resolution is exactly the
113
+ * two-layer result the storefront had before the bridge existed.
114
+ */
115
+ export const useResolvedCheckoutConfig = (): ResolvedCheckoutConfig => {
116
+ const [merged, setMerged] =
117
+ useState<ResolvedCheckoutConfig>(readBaseFromSettings);
118
+
119
+ useEffect(() => {
120
+ let cancelled = false;
121
+ fetch('/api/theme-settings', { cache: 'no-store' })
122
+ .then((res) => (res.ok ? res.json() : null))
123
+ .then((data: { checkout?: RawCheckoutConfig } | null) => {
124
+ if (cancelled) return;
125
+ if (!data?.checkout) return;
126
+ setMerged(() => mergeOverride(readBaseFromSettings(), data.checkout));
127
+ })
128
+ .catch(() => {
129
+ // Silent: backend not reachable or widget missing — keep settings.js baseline
130
+ });
131
+ return () => {
132
+ cancelled = true;
133
+ };
134
+ }, []);
135
+
136
+ const liveOverride = useSyncExternalStore(
137
+ subscribeCheckoutPieces,
138
+ getCheckoutFlowVariantOverride,
139
+ noFlowVariantOnServer
140
+ );
141
+
142
+ const [latchedOverride, setLatchedOverride] =
143
+ useState<CheckoutFlowVariantPreference | null>(null);
144
+
145
+ useLayoutEffect(() => {
146
+ setLatchedOverride(getCheckoutFlowVariantOverride());
147
+ }, []);
148
+
149
+ // The designer flag rides a postMessage and can arrive after mount; every
150
+ // claim change notifies the pieces store, which re-runs this render, so the
151
+ // canvas picks it up before an outlet edit could matter.
152
+ const composition = isThemeEditorDesigner() ? liveOverride : latchedOverride;
153
+ // Own-key lookup: an inherited member ('constructor', 'toString', …) would
154
+ // otherwise resolve to a truthy non-variant and lose the flow entirely.
155
+ const compositionVariant =
156
+ composition &&
157
+ Object.prototype.hasOwnProperty.call(COMPOSITION_VARIANT_MAP, composition)
158
+ ? COMPOSITION_VARIANT_MAP[composition]
159
+ : undefined;
160
+
161
+ return useMemo(
162
+ () =>
163
+ compositionVariant
164
+ ? { ...merged, variantId: compositionVariant }
165
+ : merged,
166
+ [merged, compositionVariant]
167
+ );
168
+ };
@@ -1,4 +1,4 @@
1
- const getAkinonNextContent = require("@akinon/next/tailwind/content");
1
+ const getAkinonNextContent = require('@akinon/next/tailwind/content');
2
2
  const deepMerge = require('@akinon/next/utils/deep-merge');
3
3
  const defaultTheme = require('tailwindcss/defaultTheme');
4
4
  const plugins = require('./src/plugins');
@@ -20,6 +20,8 @@ if (themeName !== 'default' && fs.existsSync(themeConfigPath)) {
20
20
 
21
21
  const defaultConfig = {
22
22
  content: [
23
+ './node_modules/@akinon/pz-theme/src/**/*.{js,ts,jsx,tsx}',
24
+ '../../node_modules/@akinon/pz-theme/src/**/*.{js,ts,jsx,tsx}',
23
25
  './src/app/**/*.{js,ts,jsx,tsx}',
24
26
  './src/pages/**/*.{js,ts,jsx,tsx}',
25
27
  './src/components/**/*.{js,ts,jsx,tsx}',
@@ -50,7 +50,10 @@ function checkVersion(pkg) {
50
50
  const pkgInfo = (yield response.json());
51
51
  const latestVersion = pkgInfo['dist-tags'].latest;
52
52
  if (!semver_1.default.satisfies(pkg.dependencies['@akinon/next'], latestVersion)) {
53
- console.warn(`\x1b[43mWarning: The "${packageName}" package is currently at version ${pkg.dependencies['@akinon/next']}. Please upgrade it to the latest version (${latestVersion}) to ensure plugin compatibility.`, '\x1b[0m\n');
53
+ console.warn(`\x1b[43m Warning: The "${packageName}" package is currently at`, `\x1b[41m version ${pkg.dependencies['@akinon/next']}`, `\x1b[43m Please upgrade it to the latest version (${latestVersion}) to ensure plugin compatibility.`, '\x1b[0m\n');
54
+ }
55
+ else {
56
+ console.log(`\x1b[42m Info: The package "${packageName}" is currently in the current version (${latestVersion}).`, '\x1b[0m\n');
54
57
  }
55
58
  }
56
59
  catch (error) {
@@ -72,7 +75,25 @@ exports.default = () => __awaiter(void 0, void 0, void 0, function* () {
72
75
  throw new Error('plugins.js was not found in either of the expected locations.');
73
76
  }
74
77
  }
75
- const pkg = require(path_1.default.resolve(rootDir, './package.json'));
78
+ function findPackageJson() {
79
+ const packageJsonPaths = [
80
+ path_1.default.resolve(rootDir, './package.json'),
81
+ path_1.default.resolve(rootDir, './apps/projectzeronext/package.json')
82
+ ];
83
+ for (const packageJsonPath of packageJsonPaths) {
84
+ try {
85
+ const pkg = require(packageJsonPath);
86
+ if (pkg.dependencies['@akinon/next']) {
87
+ return pkg;
88
+ }
89
+ }
90
+ catch (error) {
91
+ continue;
92
+ }
93
+ }
94
+ throw new Error('Could not find package.json with @akinon/next dependency');
95
+ }
96
+ const pkg = findPackageJson();
76
97
  yield checkVersion(pkg);
77
98
  const pluginsFilePath = findPluginsFilePath();
78
99
  let installedPlugins = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akinon/projectzero",
3
- "version": "1.126.20-v1-rc.17",
3
+ "version": "1.126.20",
4
4
  "private": false,
5
5
  "description": "CLI tool to manage your Project Zero Next project",
6
6
  "bin": {
@@ -1,5 +0,0 @@
1
- import React from 'react';
2
-
3
- export default function Layout({ children }: { children: React.ReactNode }) {
4
- return <div>{children}</div>;
5
- }