@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.
- package/CHANGELOG.md +1 -5
- package/app-template/.env.example +6 -0
- package/app-template/CHANGELOG.md +39 -35
- package/app-template/package.json +29 -28
- package/app-template/public/locales/en/checkout.json +50 -0
- package/app-template/public/locales/tr/checkout.json +50 -0
- package/app-template/src/app/[pz]/account/(dashboard)/layout.tsx +20 -0
- package/app-template/src/app/[pz]/account/account-page-slot.tsx +35 -0
- package/app-template/src/app/[pz]/account/address/layout.tsx +18 -0
- package/app-template/src/app/[pz]/account/change-email/layout.tsx +18 -0
- package/app-template/src/app/[pz]/account/change-password/layout.tsx +18 -0
- package/app-template/src/app/[pz]/account/contact/layout.tsx +18 -0
- package/app-template/src/app/[pz]/account/coupons/layout.tsx +18 -0
- package/app-template/src/app/[pz]/account/faq/layout.tsx +14 -0
- package/app-template/src/app/[pz]/account/favourite-products/layout.tsx +21 -0
- package/app-template/src/app/[pz]/account/layout.tsx +36 -3
- package/app-template/src/app/[pz]/account/orders/(list)/layout.tsx +20 -0
- package/app-template/src/app/[pz]/account/orders/[id]/(detail)/layout.tsx +40 -0
- package/app-template/src/app/[pz]/account/profile/layout.tsx +18 -0
- package/app-template/src/app/[pz]/auth/(login)/layout.tsx +37 -0
- package/app-template/src/app/[pz]/basket/layout.tsx +25 -0
- package/app-template/src/app/[pz]/client-root.tsx +2 -0
- package/app-template/src/app/[pz]/configure-page-context.ts +17 -0
- package/app-template/src/app/[pz]/layout.tsx +22 -3
- package/app-template/src/app/[pz]/orders/checkout/layout.tsx +47 -0
- package/app-template/src/app/[pz]/orders/checkout/page.tsx +75 -97
- package/app-template/src/app/[pz]/orders/completed/[token]/layout.tsx +24 -2
- package/app-template/src/app/[pz]/users/password/reset/layout.tsx +21 -0
- package/app-template/src/app/[pz]/users/reset/[[...id]]/layout.tsx +30 -0
- package/app-template/src/components/checkbox.tsx +22 -3
- package/app-template/src/components/route-handler.tsx +48 -0
- package/app-template/src/routes/index.ts +6 -6
- package/app-template/src/views/checkout/__tests__/part-style-reachability.test.ts +119 -0
- package/app-template/src/views/checkout/step-button.tsx +13 -2
- package/app-template/src/views/checkout/step-list.tsx +5 -1
- package/app-template/src/views/checkout/steps/payment/agreements.tsx +9 -1
- package/app-template/src/views/checkout/steps/payment/index.tsx +10 -2
- package/app-template/src/views/checkout/steps/payment/options/credit-card/index.tsx +2 -0
- package/app-template/src/views/checkout/steps/payment/options/funds-transfer.tsx +2 -0
- package/app-template/src/views/checkout/steps/payment/payment-header.tsx +5 -1
- package/app-template/src/views/checkout/steps/payment/payment-option-buttons.tsx +16 -4
- package/app-template/src/views/checkout/steps/shipping/addresses.tsx +2 -1
- package/app-template/src/views/checkout/steps/shipping/index.tsx +2 -0
- package/app-template/src/views/checkout/steps/shipping/shipping-options.tsx +2 -0
- package/app-template/src/views/checkout/summary.tsx +56 -18
- package/app-template/src/views/checkout/variants/__tests__/registry.test.tsx +82 -0
- package/app-template/src/views/checkout/variants/__tests__/use-resolved-config.test.tsx +208 -0
- package/app-template/src/views/checkout/variants/basket-and-checkout/basket-section.tsx +150 -0
- package/app-template/src/views/checkout/variants/basket-and-checkout/index.tsx +135 -0
- package/app-template/src/views/checkout/variants/multi-step/index.tsx +78 -0
- package/app-template/src/views/checkout/variants/one-page/accordion-section.tsx +165 -0
- package/app-template/src/views/checkout/variants/one-page/hooks/use-checkout-funnel-gtm.ts +60 -0
- package/app-template/src/views/checkout/variants/one-page/hooks/use-section-state.ts +103 -0
- package/app-template/src/views/checkout/variants/one-page/index.tsx +125 -0
- package/app-template/src/views/checkout/variants/one-page/mobile-summary-sheet.tsx +109 -0
- package/app-template/src/views/checkout/variants/one-page/one-page-summary.tsx +301 -0
- package/app-template/src/views/checkout/variants/one-page/payment-options-grid.tsx +220 -0
- package/app-template/src/views/checkout/variants/one-page/sections/address-section.tsx +320 -0
- package/app-template/src/views/checkout/variants/one-page/sections/contact-section.tsx +62 -0
- package/app-template/src/views/checkout/variants/one-page/sections/payment-section.tsx +73 -0
- package/app-template/src/views/checkout/variants/one-page/sections/shipping-section.tsx +328 -0
- package/app-template/src/views/checkout/variants/one-page/skeletons/address-skeleton.tsx +25 -0
- package/app-template/src/views/checkout/variants/one-page/skeletons/checkout-skeleton.tsx +27 -0
- package/app-template/src/views/checkout/variants/one-page/skeletons/index.ts +6 -0
- package/app-template/src/views/checkout/variants/one-page/skeletons/payment-skeleton.tsx +23 -0
- package/app-template/src/views/checkout/variants/one-page/skeletons/section-skeleton.tsx +47 -0
- package/app-template/src/views/checkout/variants/one-page/skeletons/shipping-skeleton.tsx +20 -0
- package/app-template/src/views/checkout/variants/one-page/skeletons/summary-skeleton.tsx +38 -0
- package/app-template/src/views/checkout/variants/one-page/trust-badges.tsx +35 -0
- package/app-template/src/views/checkout/variants/registry.ts +43 -0
- package/app-template/src/views/checkout/variants/types.ts +30 -0
- package/app-template/src/views/checkout/variants/use-resolved-config.ts +168 -0
- package/app-template/tailwind.config.js +3 -1
- package/dist/commands/plugins.js +23 -2
- package/package.json +1 -1
- package/app-template/src/app/[pz]/account/orders/[id]/layout.tsx +0 -5
- /package/app-template/src/app/[pz]/account/{page.tsx → (dashboard)/page.tsx} +0 -0
- /package/app-template/src/app/[pz]/account/orders/{page.tsx → (list)/page.tsx} +0 -0
- /package/app-template/src/app/[pz]/account/orders/[id]/{page.tsx → (detail)/page.tsx} +0 -0
- /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(
|
|
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}',
|
package/dist/commands/plugins.js
CHANGED
|
@@ -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[
|
|
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
|
-
|
|
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
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|