@akinon/pz-theme 2.0.95-beta.1 → 2.0.95-rc.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/CHANGELOG.md +33 -15
- package/package.json +4 -4
- package/src/__tests__/auth-commerce-events.test.tsx +1 -5
- package/src/__tests__/auth-form-error-block.test.tsx +0 -2
- package/src/__tests__/auth-form-validation.test.tsx +0 -2
- package/src/__tests__/auth-slot-coverage.test.ts +1 -9
- package/src/__tests__/auth-step-title.test.tsx +0 -2
- package/src/__tests__/detached-submit-state.test.tsx +2 -80
- package/src/__tests__/forgot-password-composed.test.tsx +0 -2
- package/src/__tests__/otp-form-composed.test.tsx +0 -2
- package/src/__tests__/password-reset-step.test.tsx +0 -2
- package/src/__tests__/register-form-composed.test.tsx +4 -253
- package/src/__tests__/registry-parity.test.ts +0 -12
- package/src/auth/auth-field-errors.tsx +0 -31
- package/src/blocks/account-button-block.tsx +0 -25
- package/src/blocks/add-to-cart-block.tsx +0 -15
- package/src/blocks/auth-field-block.tsx +3 -13
- package/src/blocks/auth-flow-block.tsx +3 -45
- package/src/blocks/auth-form-block.tsx +54 -337
- package/src/blocks/block-renderer-registry.tsx +0 -8
- package/src/blocks/button-block.tsx +13 -43
- package/src/blocks/change-password-form-block.tsx +0 -15
- package/src/blocks/forgot-password-block.tsx +9 -132
- package/src/blocks/newsletter-form-block.tsx +0 -16
- package/src/blocks/otp-form-block.tsx +67 -161
- package/src/blocks/profile-form-block.tsx +0 -13
- package/src/blocks/register-form-block.tsx +110 -362
- package/src/chrome/__tests__/theme-config-source.test.ts +1 -2
- package/src/chrome/placeholder-slugs.ts +0 -3
- package/src/chrome/route-slug.ts +0 -11
- package/src/index.ts +0 -10
- package/src/overlays/__tests__/modal-registry.test.ts +1 -5
- package/src/overlays/modal-chrome-css.ts +1 -8
- package/src/overlays/modal-preview-host.tsx +2 -7
- package/src/overlays/modal-registry.ts +1 -38
- package/src/overlays/overlay-surface.tsx +0 -23
- package/src/overlays/overlay-tokens.ts +0 -12
- package/src/overlays/theme-modal-mount.tsx +6 -85
- package/src/utils/visibility-rules.ts +0 -114
- package/src/__tests__/auth-captcha.test.tsx +0 -261
- package/src/__tests__/auth-destination.test.tsx +0 -348
- package/src/__tests__/auth-error-reading.test.ts +0 -232
- package/src/__tests__/auth-flow-scope.test.tsx +0 -162
- package/src/__tests__/auth-form-success-block.test.tsx +0 -429
- package/src/__tests__/block-action-audience.test.ts +0 -154
- package/src/__tests__/form-state-composition.test.tsx +0 -484
- package/src/__tests__/modal-login-close.test.tsx +0 -366
- package/src/__tests__/reset-password-composed.test.tsx +0 -385
- package/src/auth/auth-captcha.tsx +0 -125
- package/src/auth/auth-destination.ts +0 -168
- package/src/auth/form-state-context.tsx +0 -170
- package/src/auth/form-success-context.tsx +0 -56
- package/src/auth/read-auth-error.ts +0 -332
- package/src/blocks/auth-success-block.tsx +0 -85
- package/src/blocks/captcha-block.tsx +0 -61
- package/src/blocks/form-state-block.tsx +0 -84
- package/src/blocks/reset-password-block.tsx +0 -717
- package/src/overlays/__tests__/modal-loading.test.tsx +0 -235
- package/src/overlays/modal-host-context.tsx +0 -66
- package/src/overlays/overlay-loading.tsx +0 -144
|
@@ -3,9 +3,7 @@
|
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import NextLink from 'next/link';
|
|
5
5
|
import { useSession } from 'next-auth/react';
|
|
6
|
-
import { usePathname } from 'next/navigation';
|
|
7
6
|
import { getResponsiveValue, partAttrs } from '../utils';
|
|
8
|
-
import { withReturnPath } from '../auth/auth-destination';
|
|
9
7
|
import useBlockAction from '../hooks/use-block-action';
|
|
10
8
|
import { BlockRendererProps } from './block-renderer-registry';
|
|
11
9
|
import { readToggle } from './product-block-utils';
|
|
@@ -52,31 +50,8 @@ const AccountButtonBlock = ({
|
|
|
52
50
|
getResponsiveValue(block.properties?.[key], currentBreakpoint, fallback)
|
|
53
51
|
);
|
|
54
52
|
|
|
55
|
-
/**
|
|
56
|
-
* Whether a guest click records where the shopper was standing.
|
|
57
|
-
*
|
|
58
|
-
* On by default, and it has to be here rather than in the form: this control
|
|
59
|
-
* is the only thing that knows the answer. pz's own route guard redirects to
|
|
60
|
-
* the auth page with no parameter at all, so a login PAGE had nothing to
|
|
61
|
-
* return to — which is why the form's "go back where they came from" mode
|
|
62
|
-
* was unbuildable. Appends `?callbackUrl=<current path>`, which is the key
|
|
63
|
-
* next-auth and the brands' own views already read; the form ignores
|
|
64
|
-
* anything that is not a path on this origin.
|
|
65
|
-
*
|
|
66
|
-
* Nothing changes for a drawer: it never navigates, so there is no href to
|
|
67
|
-
* record on. A brand that tracks its login links by url turns it off.
|
|
68
|
-
*/
|
|
69
|
-
const rememberReturn = readToggle(
|
|
70
|
-
block.properties?.rememberReturn,
|
|
71
|
-
currentBreakpoint,
|
|
72
|
-
true
|
|
73
|
-
);
|
|
74
|
-
const pathname = usePathname();
|
|
75
|
-
|
|
76
53
|
const href = isAuthenticated
|
|
77
54
|
? prop('accountHref', '/account')
|
|
78
|
-
: rememberReturn
|
|
79
|
-
? withReturnPath(prop('loginHref', '/auth'), pathname)
|
|
80
55
|
: prop('loginHref', '/auth');
|
|
81
56
|
const label = isAuthenticated
|
|
82
57
|
? prop('accountLabel', 'Account')
|
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
emitCommerceEvent,
|
|
11
11
|
readItemsCurrency
|
|
12
12
|
} from '../utils/analytics';
|
|
13
|
-
import { useHostModalCloser } from '../overlays/modal-host-context';
|
|
14
13
|
import { BlockRendererProps } from './block-renderer-registry';
|
|
15
14
|
import {
|
|
16
15
|
DesignerPlaceholder,
|
|
@@ -119,19 +118,6 @@ const AddToCartBlock = ({
|
|
|
119
118
|
getResponsiveValue(block.properties?.[key], currentBreakpoint, fallback)
|
|
120
119
|
);
|
|
121
120
|
|
|
122
|
-
/**
|
|
123
|
-
* Whether finishing closes the modal this block is inside. OFF by default
|
|
124
|
-
* here, because this block's success state is something the shopper is meant
|
|
125
|
-
* to read — see `useHostModalCloser`.
|
|
126
|
-
*/
|
|
127
|
-
const closeHostModalOnSuccess = readToggle(
|
|
128
|
-
block.properties?.closeHostModalOnSuccess,
|
|
129
|
-
currentBreakpoint,
|
|
130
|
-
false
|
|
131
|
-
);
|
|
132
|
-
const closeHostModal = useHostModalCloser(closeHostModalOnSuccess);
|
|
133
|
-
|
|
134
|
-
|
|
135
121
|
const label = prop('label', 'Add to Cart');
|
|
136
122
|
const addingLabel = prop('addingLabel', 'Adding…');
|
|
137
123
|
const addedLabel = prop('addedLabel', 'Added');
|
|
@@ -300,7 +286,6 @@ const AddToCartBlock = ({
|
|
|
300
286
|
// by the mini-basket chrome block) has to be refreshed explicitly.
|
|
301
287
|
dispatch(basketApi.util.invalidateTags(['Basket', 'MiniBasket']));
|
|
302
288
|
setFeedback('added');
|
|
303
|
-
closeHostModal();
|
|
304
289
|
emitCommerceEvent('add_to_cart', {
|
|
305
290
|
currency: readItemsCurrency(product),
|
|
306
291
|
items: [buildCommerceItem(product, { quantity })]
|
|
@@ -20,7 +20,7 @@ import { BlockRendererProps } from './block-renderer-registry';
|
|
|
20
20
|
* form owns those. Standalone (outside any form) it still renders, but
|
|
21
21
|
* nothing collects its value, which the designer sees immediately.
|
|
22
22
|
*
|
|
23
|
-
* Properties: fieldType, label, placeholder, showLabel, required,
|
|
23
|
+
* Properties: fieldType, label, placeholder, showLabel, required, and for
|
|
24
24
|
* a `gender` field the two option captions (femaleLabel, maleLabel).
|
|
25
25
|
* Parts: field, label, input, error.
|
|
26
26
|
*/
|
|
@@ -143,16 +143,6 @@ const AuthFieldBlock = ({
|
|
|
143
143
|
: preset.type;
|
|
144
144
|
|
|
145
145
|
const label = prop('label', preset.label);
|
|
146
|
-
/**
|
|
147
|
-
* What a password manager is told this box is for.
|
|
148
|
-
*
|
|
149
|
-
* The preset was compiled in, which made one screen wrong on purpose: the
|
|
150
|
-
* `password` preset says `current-password`, so a composed SIGN-UP or a
|
|
151
|
-
* reset screen told the manager to offer a saved password instead of
|
|
152
|
-
* generating a new one, and what the shopper then typed was never saved.
|
|
153
|
-
* Absent keeps the preset, so every published field is untouched.
|
|
154
|
-
*/
|
|
155
|
-
const autoComplete = prop('autoComplete', '').trim() || preset.autoComplete;
|
|
156
146
|
const placeholder = prop('placeholder', '');
|
|
157
147
|
const showLabel = readToggle(
|
|
158
148
|
block.properties?.showLabel,
|
|
@@ -226,7 +216,7 @@ const AuthFieldBlock = ({
|
|
|
226
216
|
*/
|
|
227
217
|
<select
|
|
228
218
|
name={controlName}
|
|
229
|
-
autoComplete={autoComplete}
|
|
219
|
+
autoComplete={preset.autoComplete}
|
|
230
220
|
defaultValue=""
|
|
231
221
|
aria-label={showLabel ? undefined : label}
|
|
232
222
|
aria-invalid={errorMessage ? true : undefined}
|
|
@@ -245,7 +235,7 @@ const AuthFieldBlock = ({
|
|
|
245
235
|
<input
|
|
246
236
|
type={controlType}
|
|
247
237
|
name={controlName}
|
|
248
|
-
autoComplete={autoComplete}
|
|
238
|
+
autoComplete={preset.autoComplete}
|
|
249
239
|
placeholder={placeholder || undefined}
|
|
250
240
|
aria-label={showLabel ? undefined : label}
|
|
251
241
|
aria-invalid={errorMessage ? true : undefined}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import React, { useEffect } from 'react';
|
|
4
|
-
import { useSession } from 'next-auth/react';
|
|
5
4
|
import { getResponsiveValue, partAttrs } from '../utils';
|
|
6
5
|
import {
|
|
7
6
|
ActiveAuthStepContext,
|
|
8
7
|
AuthFlowIdContext,
|
|
8
|
+
DEFAULT_AUTH_FLOW_ID,
|
|
9
9
|
goBackAuthStep,
|
|
10
10
|
registerAuthFlowMount,
|
|
11
11
|
useAuthFlowState
|
|
@@ -74,33 +74,9 @@ const AuthFlowBlock = ({
|
|
|
74
74
|
getResponsiveValue(block.properties?.[key], currentBreakpoint, fallback)
|
|
75
75
|
);
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
* The name this journey answers to on the bus.
|
|
79
|
-
*
|
|
80
|
-
* Authored, it is shared: two flows carrying the same name show the same step
|
|
81
|
-
* — deliberate for one journey rendered twice, and for a trigger outside the
|
|
82
|
-
* flow that names `<flowId>:<step>`.
|
|
83
|
-
*
|
|
84
|
-
* Empty, it is the BLOCK's own, because the alternative was a collision the
|
|
85
|
-
* moment a brand did what the composition invites: a journey in the header
|
|
86
|
-
* drawer and a second one in a tab or a page body both fell back to one
|
|
87
|
-
* shared name, so opening the drawer on "register" moved the page's journey
|
|
88
|
-
* with it, and closing the drawer reset it. `DEFAULT_AUTH_FLOW_ID` stays the
|
|
89
|
-
* fallback for controls that know no flow at all — see `resolveAuthStepTarget`
|
|
90
|
-
* — so a composition that wants to be reachable that way names itself.
|
|
91
|
-
*/
|
|
92
|
-
const flowId = prop('flowId', '').trim() || `flow-${block.id}`;
|
|
77
|
+
const flowId = prop('flowId', '').trim() || DEFAULT_AUTH_FLOW_ID;
|
|
93
78
|
const initialStep = prop('initialStep', '').trim();
|
|
94
79
|
const previewStep = prop('previewStep', '').trim();
|
|
95
|
-
/**
|
|
96
|
-
* The step a shopper who is ALREADY signed in lands on.
|
|
97
|
-
*
|
|
98
|
-
* The state picks the step, which is the flow's whole idea — so a member who
|
|
99
|
-
* opens the drawer gets "Hoş geldin / Hesabım / Çıkış" composed out of
|
|
100
|
-
* ordinary blocks instead of the login form they have no use for. Empty
|
|
101
|
-
* keeps the historical behaviour: the flow does not care about the session.
|
|
102
|
-
*/
|
|
103
|
-
const signedInStep = prop('signedInStep', '').trim();
|
|
104
80
|
const backLabel = prop('backLabel', 'Back');
|
|
105
81
|
const showBack = readToggle(
|
|
106
82
|
block.properties?.showBack,
|
|
@@ -116,13 +92,6 @@ const AuthFlowBlock = ({
|
|
|
116
92
|
);
|
|
117
93
|
|
|
118
94
|
const flowState = useAuthFlowState(isDesigner ? '' : flowId);
|
|
119
|
-
const { status } = useSession();
|
|
120
|
-
/**
|
|
121
|
-
* `loading` is not treated as signed in: the flow would open on the member
|
|
122
|
-
* step for a guest and then swap. The other way round — a member seeing the
|
|
123
|
-
* login step for a beat — is the state they are being moved out of anyway.
|
|
124
|
-
*/
|
|
125
|
-
const isSignedIn = status === 'authenticated' && !isDesigner;
|
|
126
95
|
|
|
127
96
|
useEffect(() => {
|
|
128
97
|
if (isDesigner) return undefined;
|
|
@@ -155,20 +124,9 @@ const AuthFlowBlock = ({
|
|
|
155
124
|
if (selected) return stepKeyOf(selected, currentBreakpoint);
|
|
156
125
|
}
|
|
157
126
|
|
|
158
|
-
/**
|
|
159
|
-
* A step the shopper NAVIGATED to still wins over the member step: a
|
|
160
|
-
* signed-in shopper who taps "change password" inside the journey is
|
|
161
|
-
* asking for that step, and answering with the welcome card would be the
|
|
162
|
-
* flow overruling them. The member step is the ENTRY, so it only leads
|
|
163
|
-
* while the bus has nothing to say.
|
|
164
|
-
*/
|
|
165
127
|
const candidates = isDesigner
|
|
166
128
|
? [previewStep, initialStep]
|
|
167
|
-
: [
|
|
168
|
-
flowState?.active ?? '',
|
|
169
|
-
...(isSignedIn ? [signedInStep] : []),
|
|
170
|
-
initialStep
|
|
171
|
-
];
|
|
129
|
+
: [flowState?.active ?? '', initialStep];
|
|
172
130
|
|
|
173
131
|
for (const candidate of candidates) {
|
|
174
132
|
if (candidate && stepKeys.includes(candidate)) return candidate;
|