@sonic-equipment/ui 156.0.0 → 158.0.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/dist/algolia/algolia-sort-by.js +1 -1
- package/dist/buttons/add-to-cart-button/add-to-cart-button.js +8 -11
- package/dist/buttons/add-to-cart-button/add-to-cart-button.module.css.js +1 -1
- package/dist/cards/orderline-card/orderline-card.js +1 -2
- package/dist/cards/product-card/connected-product-card.d.ts +2 -2
- package/dist/cards/product-card/product-card.js +1 -2
- package/dist/cards/product-card/product-card.module.css.js +1 -1
- package/dist/cart-totals/cart-totals.js +1 -1
- package/dist/country-select/country-select.d.ts +1 -0
- package/dist/country-select/country-select.js +3 -3
- package/dist/exports.d.ts +13 -1
- package/dist/filters/pagination/pagination.js +3 -1
- package/dist/forms/checkbox/checkbox.d.ts +13 -4
- package/dist/forms/checkbox/checkbox.js +6 -2
- package/dist/forms/checkbox/checkbox.module.css.js +1 -1
- package/dist/forms/checkbox-field/checkbox-field.d.ts +10 -0
- package/dist/forms/checkbox-field/checkbox-field.js +16 -0
- package/dist/forms/checkbox-field/checkbox-field.module.css.js +3 -0
- package/dist/forms/color-checkbox/color-checkbox.d.ts +5 -3
- package/dist/forms/color-checkbox/color-checkbox.js +7 -3
- package/dist/forms/form/form-field-layout.d.ts +10 -0
- package/dist/forms/form/form-field-layout.js +10 -0
- package/dist/forms/form/form-field-layout.module.css.js +3 -0
- package/dist/forms/form/form-segment-group.d.ts +6 -0
- package/dist/forms/form/form-segment-group.js +13 -0
- package/dist/forms/form/form-segment-group.module.css.js +3 -0
- package/dist/forms/form/form-segment.d.ts +6 -0
- package/dist/forms/form/form-segment.js +9 -0
- package/dist/forms/form/form-segment.module.css.js +3 -0
- package/dist/forms/form/form.d.ts +16 -0
- package/dist/forms/form/form.js +27 -0
- package/dist/forms/form/form.module.css.js +3 -0
- package/dist/forms/input/input.d.ts +2 -0
- package/dist/forms/input/input.js +2 -2
- package/dist/forms/label/label.js +1 -1
- package/dist/forms/number-field/number-field.d.ts +9 -9
- package/dist/forms/number-field/number-field.js +18 -14
- package/dist/forms/number-field/number-field.module.css.js +1 -1
- package/dist/forms/select/select.js +3 -3
- package/dist/forms/select-field/select-field.d.ts +27 -0
- package/dist/forms/select-field/select-field.js +31 -0
- package/dist/forms/select-field/select-field.module.css.js +3 -0
- package/dist/forms/switch/switch.d.ts +12 -4
- package/dist/forms/switch/switch.js +6 -2
- package/dist/forms/switch/switch.module.css.js +1 -1
- package/dist/forms/switch-field/switch-field.d.ts +10 -0
- package/dist/forms/switch-field/switch-field.js +18 -0
- package/dist/forms/switch-field/switch-field.module.css.js +3 -0
- package/dist/forms/text-field/password-reveal-toggle/password-reveal-toggle.js +1 -1
- package/dist/forms/text-field/password-reveal-toggle/password-reveal-toggle.module.css.js +1 -1
- package/dist/forms/text-field/text-field.d.ts +32 -20
- package/dist/forms/text-field/text-field.js +13 -10
- package/dist/forms/text-field/text-field.module.css.js +1 -1
- package/dist/forms/textarea/textarea.d.ts +1 -0
- package/dist/index.js +14 -2
- package/dist/intl/translation-id.d.ts +1 -1
- package/dist/pages/account/components/create-account-form/create-account-form.d.ts +11 -0
- package/dist/pages/account/components/create-account-form/create-account-form.js +89 -0
- package/dist/pages/account/components/create-account-form/create-account-form.module.css.js +3 -0
- package/dist/{sign-in-form → pages/account/components/sign-in-form}/sign-in-form.d.ts +3 -3
- package/dist/pages/account/components/sign-in-form/sign-in-form.js +71 -0
- package/dist/pages/account/components/sign-in-form/sign-in-form.module.css.js +3 -0
- package/dist/pages/account/create-account-page/create-account-page.d.ts +3 -0
- package/dist/pages/account/create-account-page/create-account-page.js +45 -0
- package/dist/pages/account/layouts/sign-in-page-layout/sign-in-page-background-image.d.ts +6 -0
- package/dist/pages/account/layouts/sign-in-page-layout/sign-in-page-background-image.js +9 -0
- package/dist/pages/account/layouts/sign-in-page-layout/sign-in-page-layout.d.ts +1 -1
- package/dist/pages/account/layouts/sign-in-page-layout/sign-in-page-layout.js +2 -1
- package/dist/pages/account/sign-in-page/sign-in-page.js +3 -10
- package/dist/pages/checkout/order-confirmation-page/order-confirmation-page-content.js +1 -1
- package/dist/pages/checkout/payment-page/components/payment.js +6 -5
- package/dist/pages/checkout/shipping-page/shipping-page-content.js +1 -1
- package/dist/pages/checkout/shipping-page/shipping-page.js +1 -1
- package/dist/shared/api/storefront/hooks/authentication/use-create-account.d.ts +3 -0
- package/dist/shared/api/storefront/hooks/authentication/use-create-account.js +28 -0
- package/dist/shared/api/storefront/services/authentication-service.d.ts +23 -0
- package/dist/shared/api/storefront/services/authentication-service.js +40 -2
- package/dist/shared/hooks/use-script.d.ts +3 -3
- package/dist/shared/model/account.d.ts +19 -0
- package/dist/shared/model/account.js +4 -0
- package/dist/styles.css +844 -613
- package/dist/tooltip/tooltip.js +1 -1
- package/package.json +1 -1
- package/dist/sign-in-form/sign-in-form.js +0 -59
- package/dist/sign-in-form/sign-in-form.module.css.js +0 -3
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { Button } from '../../../../buttons/button/button.js';
|
|
5
|
+
import { CountrySelect } from '../../../../country-select/country-select.js';
|
|
6
|
+
import { useCountries } from '../../../../country-select/hooks/use-countries.js';
|
|
7
|
+
import { Form } from '../../../../forms/form/form.js';
|
|
8
|
+
import { FormSegment } from '../../../../forms/form/form-segment.js';
|
|
9
|
+
import { FormSegmentGroup } from '../../../../forms/form/form-segment-group.js';
|
|
10
|
+
import { SwitchField } from '../../../../forms/switch-field/switch-field.js';
|
|
11
|
+
import { TextField } from '../../../../forms/text-field/text-field.js';
|
|
12
|
+
import { isCountryCode } from '../../../../intl/types.js';
|
|
13
|
+
import { useFormattedMessage } from '../../../../intl/use-formatted-message.js';
|
|
14
|
+
import { validatePassword } from '../../../../shared/model/account.js';
|
|
15
|
+
import { validateEmail } from '../../../../shared/model/address.js';
|
|
16
|
+
import { Heading } from '../../../../typography/heading/heading.js';
|
|
17
|
+
import styles from './create-account-form.module.css.js';
|
|
18
|
+
|
|
19
|
+
function CreateAccountForm({ errorType, isDisabled: _isDisabled = false, isPendingCreateAccount, onSubmit, }) {
|
|
20
|
+
const t = useFormattedMessage();
|
|
21
|
+
const title = t('create account');
|
|
22
|
+
const isDisabled = isPendingCreateAccount || _isDisabled;
|
|
23
|
+
const [isPrivateAccount, setIsPrivateAccount] = useState(false);
|
|
24
|
+
const [password, setPassword] = useState('');
|
|
25
|
+
const [passwordConfirm, setPasswordConfirm] = useState('');
|
|
26
|
+
const [lastName, setLastName] = useState('');
|
|
27
|
+
const [companyName, setCompanyName] = useState('');
|
|
28
|
+
const errorMessages = {
|
|
29
|
+
'Unexpected error': t('An unexpected error occured. Please try again.'),
|
|
30
|
+
};
|
|
31
|
+
const { countries, currentCountry: defaultSelectedCountry, isFetching: isLoadingCountries, } = useCountries({ enabled: true });
|
|
32
|
+
// form submit handler
|
|
33
|
+
const handleSubmit = ({ formData }) => {
|
|
34
|
+
const companyName = formData.get('companyName')?.toString() || '';
|
|
35
|
+
const firstName = formData.get('firstName')?.toString();
|
|
36
|
+
const lastName = formData.get('lastName')?.toString() || '';
|
|
37
|
+
const email = formData.get('email')?.toString();
|
|
38
|
+
const password = formData.get('password')?.toString();
|
|
39
|
+
const isSubscribed = Boolean(formData.get('isSubscribed'));
|
|
40
|
+
const isPrivateAccount = Boolean(formData.get('isPrivateAccount'));
|
|
41
|
+
const countryId = formData.get('countrySelect')?.toString();
|
|
42
|
+
const countryCode = countries?.find(country => country.id === countryId)?.abbreviation;
|
|
43
|
+
if (!isCountryCode(countryCode))
|
|
44
|
+
throw new Error('CountryCode value is required');
|
|
45
|
+
if (!email)
|
|
46
|
+
throw new Error('Email value is required');
|
|
47
|
+
if (!password)
|
|
48
|
+
throw new Error('Password value is required');
|
|
49
|
+
if (!isPrivateAccount && !companyName)
|
|
50
|
+
throw new Error('CompanyName value is required');
|
|
51
|
+
if (isPrivateAccount && !lastName)
|
|
52
|
+
throw new Error('LastName value is required');
|
|
53
|
+
onSubmit({
|
|
54
|
+
data: {
|
|
55
|
+
companyName,
|
|
56
|
+
countryCode,
|
|
57
|
+
email,
|
|
58
|
+
firstName,
|
|
59
|
+
isPrivateAccount,
|
|
60
|
+
isSubscribed,
|
|
61
|
+
lastName,
|
|
62
|
+
password,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
const isMismatchingPasswords = () => {
|
|
67
|
+
if (!passwordConfirm)
|
|
68
|
+
return;
|
|
69
|
+
if (passwordConfirm === password)
|
|
70
|
+
return false;
|
|
71
|
+
return true;
|
|
72
|
+
};
|
|
73
|
+
// form header
|
|
74
|
+
const header = (jsx(Heading, { "data-test-selector": "PageTitle", italic: true, size: "m", tag: "h1", uppercase: true, children: title }));
|
|
75
|
+
// form footer
|
|
76
|
+
const footer = (jsx(FormSegment, { children: jsx(Button, { "data-test-selector": "createAccount_createButton", isDisabled: isDisabled, isLoading: isPendingCreateAccount && 'Creating account...', type: "submit", withArrow: true, children: t('create account') }) }));
|
|
77
|
+
return (jsxs(Form, { "aria-label": title, autoComplete: true, className: styles['create-account-form'], errorMessage: errorType && errorMessages[errorType], footer: footer, header: header, onSubmit: handleSubmit, title: title, children: [jsxs(FormSegmentGroup, { children: [jsx(FormSegment, { children: jsx(TextField, { autoComplete: "username", "data-test-selector": "createAccount_email", inputMode: "email", isDisabled: isDisabled, isRequired: true, label: t('Email'), name: "email", type: "email", validate: value => {
|
|
78
|
+
if (!value)
|
|
79
|
+
return value;
|
|
80
|
+
return (validateEmail(value) || t('Please enter a valid email address'));
|
|
81
|
+
} }) }), jsx(FormSegment, { children: jsx(TextField, { autoComplete: "new-password", "data-test-selector": "createAccount_password", info: "Password must be at least 8 characters long, include at least one number, at least one lowercase character, at least one uppercase character and at least one non-alphanumeric character.", isDisabled: isDisabled, isRequired: true, label: t('Password'), name: "password", onChange: setPassword, type: "password", validate: value => {
|
|
82
|
+
if (!value)
|
|
83
|
+
return;
|
|
84
|
+
return (validatePassword(value) ||
|
|
85
|
+
t('Password does not meet requirements'));
|
|
86
|
+
} }) }), jsx(FormSegment, { children: jsx(TextField, { autoComplete: "new-password", customErrorMessage: "Passwords do not match", "data-test-selector": "createAccount_passwordConfirm", isDisabled: isDisabled, isInvalid: isMismatchingPasswords(), isRequired: true, label: t('Confirm password'), onChange: setPasswordConfirm, type: "password", value: passwordConfirm }) })] }), jsxs(FormSegmentGroup, { children: [jsx(FormSegment, { children: jsx(SwitchField, { isDisabled: isDisabled, isSelected: isPrivateAccount, name: "isPrivateAccount", onChange: setIsPrivateAccount, children: t('Private account') }) }), jsx(FormSegment, { children: jsx(TextField, { autoComplete: "organization", "data-test-selector": "createAccount_companyName", isDisabled: isDisabled, isRequired: !isPrivateAccount, label: t('Company name'), name: "companyName", onChange: setCompanyName, value: companyName }, `companyName-${Boolean(isPrivateAccount)}`) }), jsx(FormSegment, { children: jsx(TextField, { autoComplete: "given-name", "data-test-selector": "createAccount_firstName", isDisabled: isDisabled, label: t('First name'), name: "firstName" }) }), jsx(FormSegment, { children: jsx(TextField, { autoComplete: "family-name", "data-test-selector": "createAccount_lastName", isDisabled: isDisabled, isRequired: isPrivateAccount, label: t('Last name'), name: "lastName", onChange: setLastName, value: lastName }, `lastname-${Boolean(isPrivateAccount)}`) }), jsx(FormSegment, { children: jsx(CountrySelect, { isRequired: true, countries: countries || [], "data-test-selector": "createAccount_countrySelect", defaultSelectedCountry: defaultSelectedCountry, isDisabled: isLoadingCountries || isDisabled, isLoading: isLoadingCountries, name: "countrySelect" }, defaultSelectedCountry?.id) })] }), jsx(FormSegmentGroup, { children: jsx(FormSegment, { children: jsx(SwitchField, { isDisabled: isDisabled, name: "isSubscribed", children: t('Sign me up for newsletters and product updates') }) }) })] }));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export { CreateAccountForm };
|
|
@@ -8,11 +8,11 @@ interface GuestLoginData {
|
|
|
8
8
|
guestSignIn: true;
|
|
9
9
|
}
|
|
10
10
|
export type SubmitData = LoginData | GuestLoginData;
|
|
11
|
-
export type
|
|
11
|
+
export type SignInErrorTypes = 'Access denied' | 'Unexpected error' | undefined;
|
|
12
12
|
export interface SignInFormProps {
|
|
13
13
|
allowGuestSignIn?: boolean;
|
|
14
14
|
createAccountPath: string;
|
|
15
|
-
|
|
15
|
+
errorType?: SignInErrorTypes;
|
|
16
16
|
initialEmail?: string;
|
|
17
17
|
initialRememberMe?: boolean;
|
|
18
18
|
isDisabled?: boolean;
|
|
@@ -23,5 +23,5 @@ export interface SignInFormProps {
|
|
|
23
23
|
data: SubmitData;
|
|
24
24
|
}) => void;
|
|
25
25
|
}
|
|
26
|
-
export declare function SignInForm({ allowGuestSignIn, createAccountPath,
|
|
26
|
+
export declare function SignInForm({ allowGuestSignIn, createAccountPath, errorType, initialEmail, initialRememberMe, isDisabled: _isDisabled, isPendingGuestSignIn, isPendingUserSignIn, onRecoverPasswordDialogOpen, onSubmit, }: SignInFormProps): import("react/jsx-runtime").JSX.Element;
|
|
27
27
|
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
|
+
import { Button } from '../../../../buttons/button/button.js';
|
|
4
|
+
import { Link } from '../../../../buttons/link/link.js';
|
|
5
|
+
import { Form } from '../../../../forms/form/form.js';
|
|
6
|
+
import { FormSegment } from '../../../../forms/form/form-segment.js';
|
|
7
|
+
import { FormSegmentGroup } from '../../../../forms/form/form-segment-group.js';
|
|
8
|
+
import { SwitchField } from '../../../../forms/switch-field/switch-field.js';
|
|
9
|
+
import { TextField } from '../../../../forms/text-field/text-field.js';
|
|
10
|
+
import { useFormattedMessage } from '../../../../intl/use-formatted-message.js';
|
|
11
|
+
import { validateEmail } from '../../../../shared/model/address.js';
|
|
12
|
+
import { voidFunction } from '../../../../shared/model/defaults.js';
|
|
13
|
+
import { RouteLink } from '../../../../shared/routing/route-link.js';
|
|
14
|
+
import { Heading } from '../../../../typography/heading/heading.js';
|
|
15
|
+
import styles from './sign-in-form.module.css.js';
|
|
16
|
+
|
|
17
|
+
const GUEST_SIGN_IN_BUTTON_NAME = 'guestSignin';
|
|
18
|
+
function SignInForm({ allowGuestSignIn = false, createAccountPath, errorType, initialEmail, initialRememberMe, isDisabled: _isDisabled = false, isPendingGuestSignIn = false, isPendingUserSignIn = false, onRecoverPasswordDialogOpen = voidFunction, onSubmit = voidFunction, }) {
|
|
19
|
+
const t = useFormattedMessage();
|
|
20
|
+
const title = t('sign in');
|
|
21
|
+
const isDisabled = isPendingUserSignIn || isPendingGuestSignIn || _isDisabled;
|
|
22
|
+
// form submit handler
|
|
23
|
+
const handleSubmit = ({ formData, submitter }) => {
|
|
24
|
+
// in case of guest sign-in submit
|
|
25
|
+
if (submitter?.name === GUEST_SIGN_IN_BUTTON_NAME) {
|
|
26
|
+
return onSubmit({
|
|
27
|
+
data: {
|
|
28
|
+
guestSignIn: true,
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
// regular sign-in
|
|
33
|
+
const email = formData.get('email')?.toString();
|
|
34
|
+
const password = formData.get('password')?.toString();
|
|
35
|
+
const rememberMe = Boolean(formData.get('rememberMe'));
|
|
36
|
+
if (!email)
|
|
37
|
+
throw new Error('Email value is required');
|
|
38
|
+
if (!password)
|
|
39
|
+
throw new Error('Password value is required');
|
|
40
|
+
onSubmit({
|
|
41
|
+
data: {
|
|
42
|
+
email,
|
|
43
|
+
guestSignIn: false,
|
|
44
|
+
password,
|
|
45
|
+
rememberMe,
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
// error message to display
|
|
50
|
+
const errorMessage = (function (type) {
|
|
51
|
+
switch (type) {
|
|
52
|
+
case undefined:
|
|
53
|
+
return;
|
|
54
|
+
case 'Access denied':
|
|
55
|
+
return t('Your email and password were not recognized.');
|
|
56
|
+
default:
|
|
57
|
+
return t('An unexpected error occured. Please try again.');
|
|
58
|
+
}
|
|
59
|
+
})(errorType);
|
|
60
|
+
// form header
|
|
61
|
+
const header = (jsx(Heading, { "data-test-selector": "PageTitle", italic: true, size: "m", tag: "h1", uppercase: true, children: title }));
|
|
62
|
+
// form footer
|
|
63
|
+
const footer = (jsxs(Fragment, { children: [jsx(FormSegment, { isFloating: true, children: jsx(SwitchField, { defaultSelected: initialRememberMe, isDisabled: isDisabled, name: "rememberMe", value: "true", children: t('Remember me') }) }), jsx(FormSegment, { children: jsx(Button, { "data-test-selector": "signIn_submit", isDisabled: isDisabled, isLoading: isPendingUserSignIn && t('Signing in…'), type: "submit", withArrow: true, children: t('sign in') }) }), jsxs(FormSegment, { children: [jsx("p", { className: styles['footer-options'], children: jsx(Link, { color: "primary", "data-test-selector": "signIn_forgotPassword", hasUnderline: true, isDisabled: isDisabled, onClick: onRecoverPasswordDialogOpen, children: t('Forgot password?') }) }), jsx("p", { className: styles['footer-options'], children: jsxs(Fragment, { children: [t('New user?'), ' ', jsx(RouteLink, { "data-test-selector": "signInCreateNewAccount_createNewAccount", hasUnderline: true, href: createAccountPath, isDisabled: isDisabled, children: t('create account') })] }) })] }), allowGuestSignIn && (jsx(FormSegment, { children: jsx(Button, { color: "secondary", isDisabled: isDisabled, isLoading: isPendingGuestSignIn && t('Signing in…'), isValidating: false, name: GUEST_SIGN_IN_BUTTON_NAME, type: "submit", value: "true", variant: "outline", children: t('Or continue as guest') }) }))] }));
|
|
64
|
+
return (jsx(Form, { autoComplete: true, className: styles['sign-in-form'], errorMessage: errorMessage, footer: footer, header: header, onSubmit: handleSubmit, title: title, children: jsxs(FormSegmentGroup, { children: [jsx(FormSegment, { children: jsx(TextField, { autoComplete: "username", "data-test-selector": "signIn_userName", defaultValue: initialEmail, inputMode: "email", isDisabled: isDisabled, isRequired: true, label: t('Email'), name: "email", showLabel: true, type: "email", validate: value => {
|
|
65
|
+
if (!value)
|
|
66
|
+
return value;
|
|
67
|
+
return (validateEmail(value) || t('Please enter a valid email address'));
|
|
68
|
+
} }) }), jsx(FormSegment, { children: jsx(TextField, { autoComplete: "current-password", "data-test-selector": "signIn_password", isDisabled: isDisabled, isRequired: true, label: t('Password'), name: "password", showLabel: true, type: "password" }) })] }) }));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export { SignInForm };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { FormattedMessage } from '../../../intl/formatted-message.js';
|
|
4
|
+
import { Dialog } from '../../../modals/dialog/dialog.js';
|
|
5
|
+
import { useCreateAccount } from '../../../shared/api/storefront/hooks/authentication/use-create-account.js';
|
|
6
|
+
import { useFetchSession } from '../../../shared/api/storefront/hooks/authentication/use-fetch-session.js';
|
|
7
|
+
import { ExistingAccountError } from '../../../shared/api/storefront/services/authentication-service.js';
|
|
8
|
+
import { RouteButton } from '../../../shared/routing/route-button.js';
|
|
9
|
+
import { useNavigate } from '../../../shared/routing/use-navigate.js';
|
|
10
|
+
import { Page } from '../../components/page/page.js';
|
|
11
|
+
import { LoadingPage } from '../../loading-page/loading-page.js';
|
|
12
|
+
import { PATHS } from '../../paths.js';
|
|
13
|
+
import { CreateAccountForm } from '../components/create-account-form/create-account-form.js';
|
|
14
|
+
import { SignInPageLayout } from '../layouts/sign-in-page-layout/sign-in-page-layout.js';
|
|
15
|
+
|
|
16
|
+
function CreateAccountPage({ returnUrl } = {}) {
|
|
17
|
+
const { navigate } = useNavigate();
|
|
18
|
+
const { data: session, isLoading: isLoadingSession } = useFetchSession();
|
|
19
|
+
const { error: errorCreateAccount, isPending: isPendingCreateAccount, isSuccess, mutate: createAccount, } = useCreateAccount();
|
|
20
|
+
const isExistingAccount = errorCreateAccount instanceof ExistingAccountError;
|
|
21
|
+
const isDisabled = isSuccess || isExistingAccount;
|
|
22
|
+
const continuePath = returnUrl && returnUrl !== PATHS.ACCOUNT_CREATE ? returnUrl : PATHS.ACCOUNT;
|
|
23
|
+
const isReturnToShipping = returnUrl === PATHS.CHECKOUT_SHIPPING;
|
|
24
|
+
const onSubmit = ({ data }) => {
|
|
25
|
+
createAccount(data, {
|
|
26
|
+
onSuccess() {
|
|
27
|
+
if (isReturnToShipping)
|
|
28
|
+
navigate(continuePath);
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
const errorType = useMemo(() => !errorCreateAccount || errorCreateAccount instanceof ExistingAccountError
|
|
33
|
+
? undefined
|
|
34
|
+
: 'Unexpected error', [errorCreateAccount]);
|
|
35
|
+
if (isLoadingSession)
|
|
36
|
+
return jsx(LoadingPage, {});
|
|
37
|
+
if (session && session.isAuthenticated && !isSuccess && !isExistingAccount) {
|
|
38
|
+
// A user is already signed in (either as guest or not), redirect them
|
|
39
|
+
navigate(continuePath);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
return (jsxs(Page, { fluid: true, fullHeight: true, "data-test-selector": "createAccountPage", children: [jsx(SignInPageLayout, { fullHeight: true, children: jsx(CreateAccountForm, { errorType: errorType, isDisabled: isDisabled, isPendingCreateAccount: isPendingCreateAccount, onSubmit: onSubmit }) }), jsx(Dialog, { footer: jsx(RouteButton, { color: "primary", href: continuePath, size: "md", withArrow: true, children: jsx(FormattedMessage, { id: "Continue" }) }), hasCloseButton: false, isDismissable: false, isKeyboardDismissDisabled: true, isOpen: isSuccess, title: "Account created", children: jsx("p", { children: jsx(FormattedMessage, { id: "Your new Sonic Equipment account was succesfully created. You should receive an email soon with further instructions on how to activate this account. If you do not receive this email, please contact Customer Support." }) }) }), jsx(Dialog, { footer: jsx(RouteButton, { color: "primary", href: `${PATHS.SIGN_IN}${returnUrl ? `?returnUrl=${returnUrl}` : ''}`, size: "md", withArrow: true, children: jsx(FormattedMessage, { id: "Continue to sign in" }) }), hasCloseButton: false, isDismissable: false, isKeyboardDismissDisabled: true, isOpen: isExistingAccount, title: "Existing account", children: jsx("p", { children: jsx(FormattedMessage, { id: "The email address you entered is already associated with an existing account. Please sign in to this account or contact Customer Support." }) }) })] }));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { CreateAccountPage };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// TODO: We need larger images
|
|
2
|
+
const SIGN_IN_PAGE_BACKGROUND_IMAGE = {
|
|
3
|
+
1: 'https://res.cloudinary.com/dkz9eknwh/image/upload/w_1658,h_1008/v1740665245/images/sign-in-page.webp',
|
|
4
|
+
2: 'https://res.cloudinary.com/dkz9eknwh/image/upload/w_1658,h_1008/v1740665245/images/sign-in-page.webp',
|
|
5
|
+
3: 'https://res.cloudinary.com/dkz9eknwh/image/upload/w_1658,h_1008/v1740665245/images/sign-in-page.webp',
|
|
6
|
+
altText: '',
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export { SIGN_IN_PAGE_BACKGROUND_IMAGE };
|
|
@@ -3,6 +3,6 @@ import { ImageType } from '../../../../shared/model/image';
|
|
|
3
3
|
export interface SignInPageLayoutProps {
|
|
4
4
|
children?: ReactNode;
|
|
5
5
|
fullHeight?: boolean;
|
|
6
|
-
image
|
|
6
|
+
image?: ImageType;
|
|
7
7
|
}
|
|
8
8
|
export declare function SignInPageLayout({ children, fullHeight, image, }: SignInPageLayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -2,9 +2,10 @@ import { jsxs, jsx } from 'react/jsx-runtime';
|
|
|
2
2
|
import clsx from 'clsx';
|
|
3
3
|
import { useIsBreakpoint } from '../../../../shared/hooks/use-is-breakpoint.js';
|
|
4
4
|
import { Image } from '../../../../media/image/image.js';
|
|
5
|
+
import { SIGN_IN_PAGE_BACKGROUND_IMAGE } from './sign-in-page-background-image.js';
|
|
5
6
|
import styles from './sign-in-page-layout.module.css.js';
|
|
6
7
|
|
|
7
|
-
function SignInPageLayout({ children, fullHeight, image, }) {
|
|
8
|
+
function SignInPageLayout({ children, fullHeight, image = SIGN_IN_PAGE_BACKGROUND_IMAGE, }) {
|
|
8
9
|
const isLg = useIsBreakpoint('lg');
|
|
9
10
|
return (jsxs("div", { className: clsx(styles['sign-in-page-layout'], fullHeight && styles['full-height']), children: [jsx("div", { className: styles.main, children: children }), isLg && (jsx("div", { className: styles.side, children: jsx("div", { className: styles.image, children: jsx(Image, { image: image, title: "" }) }) }))] }));
|
|
10
11
|
}
|
|
@@ -7,18 +7,11 @@ import { useSignIn } from '../../../shared/api/storefront/hooks/authentication/u
|
|
|
7
7
|
import { isRequestError } from '../../../shared/fetch/request.js';
|
|
8
8
|
import { useDisclosure } from '../../../shared/hooks/use-disclosure.js';
|
|
9
9
|
import { useNavigate } from '../../../shared/routing/use-navigate.js';
|
|
10
|
-
import { SignInForm } from '../../../sign-in-form/sign-in-form.js';
|
|
11
10
|
import { Page } from '../../components/page/page.js';
|
|
12
11
|
import { PATHS } from '../../paths.js';
|
|
12
|
+
import { SignInForm } from '../components/sign-in-form/sign-in-form.js';
|
|
13
13
|
import { SignInPageLayout } from '../layouts/sign-in-page-layout/sign-in-page-layout.js';
|
|
14
14
|
|
|
15
|
-
// TODO: We need larger images
|
|
16
|
-
const IMAGE = {
|
|
17
|
-
1: 'https://res.cloudinary.com/dkz9eknwh/image/upload/w_1658,h_1008/v1740665245/images/sign-in-page.webp',
|
|
18
|
-
2: 'https://res.cloudinary.com/dkz9eknwh/image/upload/w_1658,h_1008/v1740665245/images/sign-in-page.webp',
|
|
19
|
-
3: 'https://res.cloudinary.com/dkz9eknwh/image/upload/w_1658,h_1008/v1740665245/images/sign-in-page.webp',
|
|
20
|
-
altText: '',
|
|
21
|
-
};
|
|
22
15
|
function SignInPage({ returnUrl } = {}) {
|
|
23
16
|
const { navigate } = useNavigate();
|
|
24
17
|
const [isSuccess, setIsSuccess] = useState(false);
|
|
@@ -26,7 +19,7 @@ function SignInPage({ returnUrl } = {}) {
|
|
|
26
19
|
const { data: session } = useFetchSession();
|
|
27
20
|
const { error: errorSignIn, isPending: isPendingSignIn, mutate: signIn, reset: resetSignIn, } = useSignIn();
|
|
28
21
|
const { error: errorCreateGuest, isPending: isPendingCreateGuest, mutate: createGuest, reset: resetCreateGuest, } = useCreateGuestAccount();
|
|
29
|
-
const
|
|
22
|
+
const errorType = useMemo(() => {
|
|
30
23
|
const error = errorSignIn || errorCreateGuest;
|
|
31
24
|
if (!error)
|
|
32
25
|
return undefined;
|
|
@@ -63,7 +56,7 @@ function SignInPage({ returnUrl } = {}) {
|
|
|
63
56
|
const onRecoverPasswordDialogOpen = () => {
|
|
64
57
|
setRecoverPasswordDialogOpen(true);
|
|
65
58
|
};
|
|
66
|
-
return (jsxs(Fragment, { children: [jsx(Page, { fullHeight: true, "data-test-selector": "signInPage", fluid: true, children: jsx(SignInPageLayout, { fullHeight: true,
|
|
59
|
+
return (jsxs(Fragment, { children: [jsx(Page, { fullHeight: true, "data-test-selector": "signInPage", fluid: true, children: jsx(SignInPageLayout, { fullHeight: true, children: jsx(SignInForm, { allowGuestSignIn: allowGuestSignIn, createAccountPath: createAccountPath, errorType: errorType, initialEmail: session?.isGuest ? '' : session?.email, initialRememberMe: session?.rememberMe, isDisabled: !session || isSuccess, isPendingGuestSignIn: isPendingCreateGuest, isPendingUserSignIn: isPendingSignIn, onRecoverPasswordDialogOpen: onRecoverPasswordDialogOpen, onSubmit: onSubmit }) }) }), jsx(RecoverPasswordDialog, { isOpen: isRecoverPasswordDialogOpen, onOpenChange: isOpen => setRecoverPasswordDialogOpen(isOpen) })] }));
|
|
67
60
|
}
|
|
68
61
|
|
|
69
62
|
export { SignInPage };
|
|
@@ -55,7 +55,7 @@ function OrderConfirmationPageContent({ cart, }) {
|
|
|
55
55
|
secondary: (jsxs(Fragment, { children: [cart.canSaveOrder && (jsx(RouteButton, { color: "secondary", onClick: () => {
|
|
56
56
|
saveCartForLater.mutate({ cart });
|
|
57
57
|
}, variant: "outline", children: jsx(FormattedMessage, { id: "Save order" }) })), jsx(PrintButton, {})] })),
|
|
58
|
-
}, overview: jsx(CartTotals, { currencyCode: currencyCode, fulfillmentMethod:
|
|
58
|
+
}, overview: jsx(CartTotals, { currencyCode: currencyCode, fulfillmentMethod: cart.fulfillmentMethod, orderNumber: cart.orderNumber, shippingCost: cart.shippingAndHandling, subtotal: cart.orderSubTotal, tax: cart.totalTax, total: cart.orderGrandTotal, vatPercentage: cart.cartLines?.[0]?.pricing?.vatRate }), children: jsxs("div", { children: [jsx(CheckoutPageSection, { hasBorder: false, title: t('General'), children: jsx(CheckoutPageSectionContent, { children: jsxs("div", { className: styles['general-order-info'], children: [cart.orderDate && (jsx(InfoDisplay, { id: "order-date", label: t('Order date'), value: formatDateToLocaleString(new Date(cart.orderDate), cultureCode) })), cart.requestedDeliveryDateDisplay && (jsx(InfoDisplay, { id: "requested-delivery-date", label: t('Requested delivery date'), value: formatDateToLocaleString(new Date(cart.requestedDeliveryDateDisplay.toString()), cultureCode) })), cart.poNumber && (jsx(InfoDisplay, { id: "po-number", label: t('PO Number'), value: cart.poNumber }))] }) }) }), jsx(CheckoutPageSection, { hasBorder: false, title: t('Billing and shipping information'), children: jsx(CheckoutPageSectionContent, { children: jsx(BillingAndInvoiceInformation, { billToAddress: {
|
|
59
59
|
address1: cart.billTo?.address1,
|
|
60
60
|
address2: cart.billTo?.address2,
|
|
61
61
|
address3: cart.billTo?.address3,
|
|
@@ -33,6 +33,7 @@ function Payment({ atp, cart: _cart, form, isProcessing, onError: _onError, onPa
|
|
|
33
33
|
const { sendPurchaseEventFromPaymentPage } = useAlgoliaInsights();
|
|
34
34
|
const invalidateCurrentCart = useInvalidateCurrentCart();
|
|
35
35
|
const dropinRef = useRef(null);
|
|
36
|
+
const hasReturnedFromAdyen = useHasReturnedFromAdyen();
|
|
36
37
|
const [paymentError, setPaymentError] = useState();
|
|
37
38
|
const [apiError, setAPIError] = useState();
|
|
38
39
|
const invalidateAdyen = useInvalidateAdyen();
|
|
@@ -40,7 +41,7 @@ function Payment({ atp, cart: _cart, form, isProcessing, onError: _onError, onPa
|
|
|
40
41
|
const cartRef = useRef(_cart);
|
|
41
42
|
const cart = cartRef.current;
|
|
42
43
|
const hasAtp = atp.length > 1;
|
|
43
|
-
const [asSoonAsPossible, setAsSoonAsPossible] = useState(!hasAtp);
|
|
44
|
+
const [asSoonAsPossible, setAsSoonAsPossible] = useState(!hasAtp || (hasReturnedFromAdyen && !cart.requestedDeliveryDate));
|
|
44
45
|
const [deliveryDate, setDeliveryDate] = useState(cart.requestedDeliveryDateDisplay?.toString() || '');
|
|
45
46
|
const [selectedPaymentMethod, setSelectedPaymentMethod] = useState(cart.paymentOptions?.paymentMethods?.[0]?.name || 'ADY');
|
|
46
47
|
if (!isCountryCode(_cart.billTo?.country?.abbreviation))
|
|
@@ -54,7 +55,6 @@ function Payment({ atp, cart: _cart, form, isProcessing, onError: _onError, onPa
|
|
|
54
55
|
cart.paymentOptions &&
|
|
55
56
|
cart.billTo?.id &&
|
|
56
57
|
countryCode;
|
|
57
|
-
const hasReturnedFromAdyen = useHasReturnedFromAdyen();
|
|
58
58
|
const isDisabled = isProcessing;
|
|
59
59
|
useEffect(() => {
|
|
60
60
|
if (!hasReturnedFromAdyen)
|
|
@@ -187,6 +187,7 @@ function Payment({ atp, cart: _cart, form, isProcessing, onError: _onError, onPa
|
|
|
187
187
|
industry: formData.get('industry')?.toString() || '',
|
|
188
188
|
};
|
|
189
189
|
cart.requestedDeliveryDate = formData.get('deliveryDate')?.toString();
|
|
190
|
+
cart.requestedDeliveryDateDisplay = undefined;
|
|
190
191
|
if (cart.customerVatNumber &&
|
|
191
192
|
lastVATNumber.current !== cart.customerVatNumber &&
|
|
192
193
|
!(await validateVAT(cart.customerVatNumber)))
|
|
@@ -299,11 +300,11 @@ function Payment({ atp, cart: _cart, form, isProcessing, onError: _onError, onPa
|
|
|
299
300
|
return (jsxs(Form, { className: styles['payment-form'], "data-test-selector": "paymentForm", id: form, onSubmit: e => {
|
|
300
301
|
e.preventDefault();
|
|
301
302
|
onSubmit(e);
|
|
302
|
-
}, validationErrors: validationErrors, children: [Boolean(apiError) && (jsx("div", { className: styles['error-message'], children: jsx(FormattedMessage, { id: "An unexpected error occured" }) })), hasAtp && (jsxs("div", { className: styles['delivery-date'], children: [jsx(Select, { showLabel: true, "data-test-selector": "deliveryDateSelect", isDisabled: isDisabled || asSoonAsPossible, isRequired: !asSoonAsPossible, label: t('Select a desired delivery date'), name: "deliveryDate", onChange: setDeliveryDate, options: atpSelectOptions, selectedOption: deliveryDate, variant: "solid" }, String(asSoonAsPossible)), jsxs("div", { className: styles['asap-checkbox'], children: [jsx(Checkbox, { "data-test-selector": "asapCheckbox", isDisabled: isDisabled, isSelected: asSoonAsPossible, onChange: checked => {
|
|
303
|
+
}, validationErrors: validationErrors, children: [Boolean(apiError) && (jsx("div", { className: styles['error-message'], children: jsx(FormattedMessage, { id: "An unexpected error occured" }) })), hasAtp && (jsxs("div", { className: styles['delivery-date'], children: [jsx(Select, { showLabel: true, "data-test-selector": "deliveryDateSelect", defaultSelectedOption: deliveryDate, isDisabled: isDisabled || asSoonAsPossible, isRequired: !asSoonAsPossible, label: t('Select a desired delivery date'), name: "deliveryDate", onChange: setDeliveryDate, options: atpSelectOptions, selectedOption: deliveryDate, variant: "solid" }, String(asSoonAsPossible)), jsxs("div", { className: styles['asap-checkbox'], children: [jsx(Checkbox, { "data-test-selector": "asapCheckbox", isDisabled: isDisabled || Boolean(cart.requestedDeliveryDateDisplay), isSelected: asSoonAsPossible, onChange: checked => {
|
|
303
304
|
setAsSoonAsPossible(checked);
|
|
304
305
|
if (checked)
|
|
305
306
|
setDeliveryDate('');
|
|
306
|
-
}, children:
|
|
307
|
+
}, children: t('As soon as possible') }), jsx(InfoIconTooltip, { variant: "stroke", children: t('Selecting As Soon As Possible will enable us to send the products to you as they become available.') })] })] })), jsx(Select, { isRequired: true, "data-test-selector": "industrySelect", defaultSelectedOption: cart.properties.industry, isDisabled: isDisabled, label: t('Industry'), name: "industry", options: {
|
|
307
308
|
/* eslint-disable sort-keys-fix/sort-keys-fix */
|
|
308
309
|
PP: 'Private User',
|
|
309
310
|
AU: 'Automotive',
|
|
@@ -315,7 +316,7 @@ function Payment({ atp, cart: _cart, form, isProcessing, onError: _onError, onPa
|
|
|
315
316
|
MA: 'Maritime',
|
|
316
317
|
OT: 'Other',
|
|
317
318
|
/* eslint-enable sort-keys-fix/sort-keys-fix */
|
|
318
|
-
}, variant: "solid" }), jsx(TextField, { showLabel: true, isDisabled: isDisabled, label: t('VAT Number'), name: "customerVatNumber", onBlur: e => validateVAT(e.target.value), onChange: setCustomerVatNumber, validate: () => validationErrors.customerVatNumber ?? true, value: customerVatNumber }, `vat${Boolean(validationErrors.customerVatNumber)}`), jsx(TextField, { showLabel: true, defaultValue: cart.poNumber, isDisabled: isDisabled, isRequired: cart.requiresPoNumber, label: t('PO Number'), name: "poNumber" }), paymentMethodOptions && Object.keys(paymentMethodOptions).length > 1 && (jsx(Select, { "data-test-selector": "paymentMethodSelect", defaultSelectedOption: cart.paymentOptions?.paymentMethods?.[0]?.name || 'ADY', isDisabled: isDisabled, label: t('Payment method'), name: "paymentMethod", onChange: setSelectedPaymentMethod, options: paymentMethodOptions, selectedOption: selectedPaymentMethod, variant: "solid" })), isAdyenPayment && cart.billTo && (jsx(AdyenPayment, { amount: cart.orderGrandTotal, cartId: cart.trackId, countryCode: countryCode, currencyCode: currencyCode, customerId: cart.billTo.id, dropinRef: dropinRef, environment: environment === 'production' ? 'live' : 'test', isDisabled: isDisabled, onComplete: onComplete, onError: onError, orderAmount: cart.orderGrandTotal, returnUrl:
|
|
319
|
+
}, placeholder: t('Select an industry'), variant: "solid" }), jsx(TextField, { showLabel: true, isDisabled: isDisabled, label: t('VAT Number'), name: "customerVatNumber", onBlur: e => validateVAT(e.target.value), onChange: setCustomerVatNumber, validate: () => validationErrors.customerVatNumber ?? true, value: customerVatNumber }, `vat${Boolean(validationErrors.customerVatNumber)}`), jsx(TextField, { showLabel: true, defaultValue: cart.poNumber, isDisabled: isDisabled, isRequired: cart.requiresPoNumber, label: t('PO Number'), name: "poNumber" }), paymentMethodOptions && Object.keys(paymentMethodOptions).length > 1 && (jsx(Select, { "data-test-selector": "paymentMethodSelect", defaultSelectedOption: cart.paymentOptions?.paymentMethods?.[0]?.name || 'ADY', isDisabled: isDisabled, label: t('Payment method'), name: "paymentMethod", onChange: setSelectedPaymentMethod, options: paymentMethodOptions, selectedOption: selectedPaymentMethod, variant: "solid" })), isAdyenPayment && cart.billTo && (jsx(AdyenPayment, { amount: cart.orderGrandTotal, cartId: cart.trackId, countryCode: countryCode, currencyCode: currencyCode, customerId: cart.billTo.id, dropinRef: dropinRef, environment: environment === 'production' ? 'live' : 'test', isDisabled: isDisabled, onComplete: onComplete, onError: onError, orderAmount: cart.orderGrandTotal, returnUrl:
|
|
319
320
|
/* eslint-disable ssr-friendly/no-dom-globals-in-react-fc */
|
|
320
321
|
typeof window === 'undefined'
|
|
321
322
|
? ''
|
|
@@ -18,7 +18,7 @@ function ShippingPageContent({ cart, editAddress, errorPatchBillingAddress, fulf
|
|
|
18
18
|
const t = useFormattedMessage();
|
|
19
19
|
const fulfillmentMethodOptions = fulfillmentMethods?.reduce((acc, method) => ({
|
|
20
20
|
...acc,
|
|
21
|
-
[method]: t(`
|
|
21
|
+
[method]: t(`fulfillmentmethod.${method}`),
|
|
22
22
|
}), {});
|
|
23
23
|
const hasBillToAddress = Boolean(cart.billTo?.address1);
|
|
24
24
|
const currencyCode = getCurrencyCodeBySymbol(cart.currencySymbol);
|
|
@@ -39,7 +39,7 @@ function ShippingPage() {
|
|
|
39
39
|
const isAuthenticated = session?.isAuthenticated;
|
|
40
40
|
const isLoading = isLoadingCart || isLoadingCountries || isLoadingFulfillmentMethods;
|
|
41
41
|
const { isNavigating, navigate } = useNavigate();
|
|
42
|
-
const isPickup = cart?.fulfillmentMethod
|
|
42
|
+
const isPickup = Boolean(cart?.fulfillmentMethod.match(/pickup/i));
|
|
43
43
|
useEffect(() => {
|
|
44
44
|
/* Initial guards. When these are not met, we should not proceed */
|
|
45
45
|
if (isNavigating)
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { AccountModel } from 'shared/api/storefront/model/storefront.model';
|
|
2
|
+
import { CreateAccountRequestBody } from 'shared/api/storefront/services/authentication-service';
|
|
3
|
+
export declare function useCreateAccount(): import("@tanstack/react-query").UseMutationResult<AccountModel, Error, CreateAccountRequestBody, unknown>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { useQueryClient, useMutation } from '@tanstack/react-query';
|
|
2
|
+
import { createAccount, createSession } from '../../services/authentication-service.js';
|
|
3
|
+
|
|
4
|
+
function useCreateAccount() {
|
|
5
|
+
const queryClient = useQueryClient();
|
|
6
|
+
return useMutation({
|
|
7
|
+
mutationFn: async (account) => {
|
|
8
|
+
try {
|
|
9
|
+
const body = await createAccount(account);
|
|
10
|
+
const updatedSession = await createSession({
|
|
11
|
+
accessToken: '',
|
|
12
|
+
isGuest: false,
|
|
13
|
+
password: account.password,
|
|
14
|
+
rememberMe: false,
|
|
15
|
+
userName: body.userName,
|
|
16
|
+
});
|
|
17
|
+
queryClient.setQueriesData({ exact: true, queryKey: ['session'] }, updatedSession);
|
|
18
|
+
return body;
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
queryClient.resetQueries();
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { useCreateAccount };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RequestError } from '../../../fetch/request';
|
|
1
2
|
import { AccountModel, PatchSessionModel, SessionModel } from '../model/storefront.model';
|
|
2
3
|
export declare function fetchSession(): Promise<SessionModel>;
|
|
3
4
|
export declare function patchSession({ session, }: {
|
|
@@ -31,3 +32,25 @@ export declare function createGuestAccount({ defaultWarehouseId, }: {
|
|
|
31
32
|
export declare function recoverPassword({ userName, }: {
|
|
32
33
|
userName: string;
|
|
33
34
|
}): Promise<SessionModel>;
|
|
35
|
+
export declare class ExistingAccountError extends RequestError {
|
|
36
|
+
constructor(error: Error);
|
|
37
|
+
}
|
|
38
|
+
export interface CreateAccountRequestBase {
|
|
39
|
+
email: string;
|
|
40
|
+
firstName?: string;
|
|
41
|
+
isSubscribed: boolean;
|
|
42
|
+
lastName: string;
|
|
43
|
+
password: string;
|
|
44
|
+
}
|
|
45
|
+
export interface CreatePrivateAccountRequestBody extends CreateAccountRequestBase {
|
|
46
|
+
companyName?: string | undefined;
|
|
47
|
+
countryCode: string;
|
|
48
|
+
isPrivateAccount: true;
|
|
49
|
+
}
|
|
50
|
+
export interface CreateBusinessAccountRequestBody extends CreateAccountRequestBase {
|
|
51
|
+
companyName: string;
|
|
52
|
+
countryCode: string;
|
|
53
|
+
isPrivateAccount: false;
|
|
54
|
+
}
|
|
55
|
+
export type CreateAccountRequestBody = CreatePrivateAccountRequestBody | CreateBusinessAccountRequestBody;
|
|
56
|
+
export declare function createAccount({ companyName, countryCode, email, firstName, isPrivateAccount, isSubscribed, lastName, password, }: CreateAccountRequestBody): Promise<AccountModel>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { config } from '../../../../config.js';
|
|
2
|
-
import { request } from '../../../fetch/request.js';
|
|
2
|
+
import { request, RequestError, isRequestError } from '../../../fetch/request.js';
|
|
3
3
|
|
|
4
4
|
async function fetchSession() {
|
|
5
5
|
const { body } = await request({
|
|
@@ -92,5 +92,43 @@ async function recoverPassword({ userName, }) {
|
|
|
92
92
|
});
|
|
93
93
|
return body;
|
|
94
94
|
}
|
|
95
|
+
class ExistingAccountError extends RequestError {
|
|
96
|
+
constructor(error) {
|
|
97
|
+
super(error);
|
|
98
|
+
this.name = 'ExistingAccountError';
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async function createAccount({ companyName, countryCode, email, firstName, isPrivateAccount, isSubscribed, lastName, password, }) {
|
|
102
|
+
try {
|
|
103
|
+
const { body } = await request({
|
|
104
|
+
body: {
|
|
105
|
+
email,
|
|
106
|
+
firstName,
|
|
107
|
+
isSubscribed,
|
|
108
|
+
lastName,
|
|
109
|
+
password,
|
|
110
|
+
properties: {
|
|
111
|
+
PrivateAccount: isPrivateAccount,
|
|
112
|
+
companyName,
|
|
113
|
+
country: countryCode,
|
|
114
|
+
},
|
|
115
|
+
userName: '',
|
|
116
|
+
},
|
|
117
|
+
headers: {
|
|
118
|
+
'Content-Type': 'application/json',
|
|
119
|
+
},
|
|
120
|
+
method: 'POST',
|
|
121
|
+
url: `${config.SHOP_API_URL}/api/v1/accounts`,
|
|
122
|
+
});
|
|
123
|
+
return body;
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
if (isRequestError(error) &&
|
|
127
|
+
error.status === 400 &&
|
|
128
|
+
error.body?.message === 'Email Address already exists')
|
|
129
|
+
throw new ExistingAccountError(error);
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
95
133
|
|
|
96
|
-
export { createGuestAccount, createSession, fetchSession, patchSession, recoverPassword, signIn, signOut };
|
|
134
|
+
export { ExistingAccountError, createAccount, createGuestAccount, createSession, fetchSession, patchSession, recoverPassword, signIn, signOut };
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
interface
|
|
1
|
+
interface UseScriptCodePropsBase {
|
|
2
2
|
async?: boolean;
|
|
3
3
|
enabled?: boolean;
|
|
4
4
|
type?: 'module' | 'text/javascript';
|
|
5
5
|
}
|
|
6
|
-
interface UseScriptCodeProps extends
|
|
6
|
+
interface UseScriptCodeProps extends UseScriptCodePropsBase {
|
|
7
7
|
code: string;
|
|
8
8
|
nonce?: string;
|
|
9
9
|
}
|
|
10
|
-
interface UseScriptUrlProps extends
|
|
10
|
+
interface UseScriptUrlProps extends UseScriptCodePropsBase {
|
|
11
11
|
src: string;
|
|
12
12
|
}
|
|
13
13
|
type UseScriptProps = UseScriptUrlProps | UseScriptCodeProps;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const validatePassword: (value: string) => boolean;
|
|
2
|
+
export interface AccountBase {
|
|
3
|
+
email: string;
|
|
4
|
+
firstName?: string;
|
|
5
|
+
isSubscribed: boolean;
|
|
6
|
+
lastName: string;
|
|
7
|
+
password: string;
|
|
8
|
+
}
|
|
9
|
+
export interface PrivateAccount extends AccountBase {
|
|
10
|
+
companyName?: string | undefined;
|
|
11
|
+
countryCode: string;
|
|
12
|
+
isPrivateAccount: true;
|
|
13
|
+
}
|
|
14
|
+
export interface BusinessAccount extends AccountBase {
|
|
15
|
+
companyName: string;
|
|
16
|
+
countryCode: string;
|
|
17
|
+
isPrivateAccount: false;
|
|
18
|
+
}
|
|
19
|
+
export type Account = PrivateAccount | BusinessAccount;
|