@riosst100/pwa-marketplace 1.0.2 → 1.0.3

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 (28) hide show
  1. package/package.json +1 -1
  2. package/src/componentOverrideMapping.js +5 -1
  3. package/src/components/BecomeSeller/becomeSeller.js +181 -78
  4. package/src/components/BecomeSeller/becomeSeller.module.css +0 -1
  5. package/src/components/BecomeSellerLink/becomeSellerLink.js +21 -4
  6. package/src/components/BecomeSellerPage/becomeSellerPage.js +6 -11
  7. package/src/components/SellerAccountPage/index.js +1 -0
  8. package/src/components/SellerAccountPage/sellerAccountPage.js +138 -0
  9. package/src/components/SellerAccountPage/sellerAccountPage.module.css +55 -0
  10. package/src/components/SellerVerification/index.js +1 -0
  11. package/src/components/SellerVerification/sellerVerification.js +198 -0
  12. package/src/components/SellerVerification/sellerVerification.module.css +47 -0
  13. package/src/components/SellerVerificationPage/index.js +1 -0
  14. package/src/components/SellerVerificationPage/sellerVerificationPage.js +43 -0
  15. package/src/components/SellerVerificationPage/sellerVerificationPage.module.css +21 -0
  16. package/src/components/WebsiteSwitcher/websiteSwitcher.js +2 -2
  17. package/src/intercept.js +11 -1
  18. package/src/overwrites/peregrine/lib/store/actions/user/asyncActions.js +96 -0
  19. package/src/overwrites/peregrine/lib/talons/AccountMenu/useAccountMenuItems.js +65 -0
  20. package/src/overwrites/peregrine/lib/talons/SignIn/signIn.gql.js +56 -0
  21. package/src/overwrites/peregrine/lib/talons/SignIn/useSignIn.js +226 -0
  22. package/src/overwrites/venia-ui/lib/components/Header/storeSwitcher.js +2 -2
  23. package/src/talons/BecomeSeller/becomeSeller.gql.js +34 -124
  24. package/src/talons/BecomeSeller/useBecomeSeller.js +50 -192
  25. package/src/talons/BecomeSellerLink/useBecomeSellerLink.js +6 -8
  26. package/src/talons/BecomeSellerPage/useBecomeSellerPage.js +12 -14
  27. package/src/talons/SellerAccountPage/useSellerAccountPage.js +174 -0
  28. package/src/talons/WebsiteByIp/useWebsiteByIp.js +2 -0
@@ -2,60 +2,29 @@ import { useCallback, useMemo, useState } from 'react';
2
2
  import { useApolloClient, useMutation } from '@apollo/client';
3
3
 
4
4
  import mergeOperations from '@magento/peregrine/lib/util/shallowMerge';
5
- import { useUserContext } from '@magento/peregrine/lib/context/user';
6
- import { useCartContext } from '@magento/peregrine/lib/context/cart';
7
- import { useAwaitQuery } from '@magento/peregrine/lib/hooks/useAwaitQuery';
8
- import { retrieveCartId } from '@magento/peregrine/lib/store/actions/cart';
9
5
  import { useGoogleReCaptcha } from '@magento/peregrine/lib/hooks/useGoogleReCaptcha';
10
6
 
11
7
  import DEFAULT_OPERATIONS from './becomeSeller.gql';
12
8
  import { useEventingContext } from '@magento/peregrine/lib/context/eventing';
13
9
 
14
- /**
15
- * Returns props necessary to render BecomeSeller component. In particular this
16
- * talon handles the submission flow by first doing a pre-submisson validation
17
- * and then, on success, invokes the `onSubmit` prop, which is usually the action.
18
- *
19
- * @param {BecomeSellerQueries} props.queries queries used by the talon
20
- * @param {BecomeSellerMutations} props.mutations mutations used by the talon
21
- * @param {InitialValues} props.initialValues initial values to sanitize and seed the form
22
- * @param {Function} props.onSubmit the post submit callback
23
- * @param {Function} props.onCancel the cancel callback
24
- *
25
- * @returns {BecomeSellerProps}
26
- *
27
- * @example <caption>Importing into your project</caption>
28
- * import { useForgotPassword } from '@magento/peregrine/lib/talons/BecomeSeller/useBecomeSeller.js';
29
- */
10
+ import { BrowserPersistence } from '@magento/peregrine/lib/util';
11
+
12
+ const storage = new BrowserPersistence();
13
+
30
14
  export const useBecomeSeller = props => {
31
15
  const { initialValues = {}, onSubmit, onCancel } = props;
32
16
 
33
17
  const operations = mergeOperations(DEFAULT_OPERATIONS, props.operations);
18
+
34
19
  const {
35
- becomeSellerMutation,
36
- createCartMutation,
37
- getCartDetailsQuery,
38
- getCustomerQuery,
39
- mergeCartsMutation,
40
- signInMutation
20
+ becomeSellerMutation
41
21
  } = operations;
42
- const apolloClient = useApolloClient();
22
+
43
23
  const [isSubmitting, setIsSubmitting] = useState(false);
44
- const [
45
- { cartId },
46
- { createCart, removeCart, getCartDetails }
47
- ] = useCartContext();
48
- const [
49
- { isGettingDetails },
50
- { getUserDetails, setToken }
51
- ] = useUserContext();
24
+ const [sellerType, setSellerType] = useState('individual');
52
25
 
53
26
  const [, { dispatch }] = useEventingContext();
54
27
 
55
- const [fetchCartId] = useMutation(createCartMutation);
56
-
57
- const [mergeCarts] = useMutation(mergeCartsMutation);
58
-
59
28
  // For create account and sign in mutations, we don't want to cache any
60
29
  // personally identifiable information (PII). So we set fetchPolicy to 'no-cache'.
61
30
  const [becomeSeller, { error: becomeSellerError }] = useMutation(
@@ -65,105 +34,66 @@ export const useBecomeSeller = props => {
65
34
  }
66
35
  );
67
36
 
68
- const [signIn, { error: signInError }] = useMutation(signInMutation, {
69
- fetchPolicy: 'no-cache'
70
- });
71
-
72
- const fetchUserDetails = useAwaitQuery(getCustomerQuery);
73
- const fetchCartDetails = useAwaitQuery(getCartDetailsQuery);
74
-
75
37
  const {
76
38
  generateReCaptchaData,
77
39
  recaptchaLoading,
78
40
  recaptchaWidgetProps
79
41
  } = useGoogleReCaptcha({
80
- currentForm: 'CUSTOMER_CREATE',
42
+ currentForm: 'BECOME_SELLER',
81
43
  formAction: 'becomeSeller'
82
44
  });
83
45
 
84
- const handleCancel = useCallback(() => {
85
- onCancel();
86
- }, [onCancel]);
87
-
88
- const handleCancelKeyPress = useCallback(() => {
89
- event => {
90
- if (event.key === 'Enter') {
91
- handleCancel();
46
+ const handleChange = useCallback(
47
+ async formValues => {
48
+ if (formValues.values.seller) {
49
+ setSellerType(formValues.values.seller.seller_type)
92
50
  }
93
- };
94
- }, [handleCancel]);
51
+ }
52
+ );
95
53
 
96
54
  const handleSubmit = useCallback(
97
55
  async formValues => {
98
56
  setIsSubmitting(true);
99
57
  try {
100
- // Get source cart id (guest cart id).
101
- const sourceCartId = cartId;
102
58
 
103
59
  // Get reCaptchaV3 Data for becomeSeller mutation
104
60
  const recaptchaDataForBecomeSeller = await generateReCaptchaData();
105
61
 
106
62
  // Create the account and then sign in.
107
- await becomeSeller({
63
+ const result = await becomeSeller({
108
64
  variables: {
109
- email: formValues.customer.email,
110
- firstname: formValues.customer.firstname,
111
- lastname: formValues.customer.lastname,
112
- password: formValues.password,
113
- is_subscribed: !!formValues.subscribe
65
+ seller_type: sellerType,
66
+ group_id: '',
67
+ url_key: formValues.seller.store_url,
68
+ name: formValues.seller.seller_profile_name,
69
+ company: formValues.seller.company_name,
70
+ company_registration_number: formValues.seller.company_registration_number,
71
+ country_id: formValues.seller.country_id,
72
+ address_line_1: formValues.seller.address_line_1,
73
+ address_line_2: formValues.seller.address_line_2,
74
+ city: formValues.seller.city,
75
+ region: formValues.seller.region,
76
+ region_id: formValues.seller.region_id,
77
+ postcode: formValues.seller.postcode,
78
+ contact_number: formValues.seller.contact_number
114
79
  },
115
80
  ...recaptchaDataForBecomeSeller
116
81
  });
117
82
 
118
- dispatch({
119
- type: 'USER_CREATE_ACCOUNT',
120
- payload: {
121
- email: formValues.customer.email,
122
- firstName: formValues.customer.firstname,
123
- lastName: formValues.customer.lastname,
124
- isSubscribed: !!formValues.subscribe
125
- }
126
- });
127
-
128
- // Get reCaptchaV3 Data for signIn mutation
129
- const recaptchaDataForSignIn = await generateReCaptchaData();
83
+ if (result.data.becomeSeller.code) {
84
+ storage.setItem('is_seller', true);
130
85
 
131
- const signInResponse = await signIn({
132
- variables: {
133
- email: formValues.customer.email,
134
- password: formValues.password
135
- },
136
- ...recaptchaDataForSignIn
137
- });
138
- const token = signInResponse.data.generateCustomerToken.token;
139
- await setToken(token);
140
-
141
- // Clear all cart/customer data from cache and redux.
142
- await apolloClient.clearCacheData(apolloClient, 'cart');
143
- await apolloClient.clearCacheData(apolloClient, 'customer');
144
- await removeCart();
145
-
146
- // Create and get the customer's cart id.
147
- await createCart({
148
- fetchCartId
149
- });
150
- const destinationCartId = await retrieveCartId();
86
+ globalThis.location.assign('/seller-account');
87
+ }
151
88
 
152
- // Merge the guest cart into the customer cart.
153
- await mergeCarts({
154
- variables: {
155
- destinationCartId,
156
- sourceCartId
89
+ dispatch({
90
+ type: 'BECOME_SELLER',
91
+ payload: {
92
+ group_id: 'basic',
93
+ url_key: formValues.seller.store_url
157
94
  }
158
95
  });
159
96
 
160
- // Ensure old stores are updated with any new data.
161
- await getUserDetails({ fetchUserDetails });
162
- await getCartDetails({
163
- fetchCartId,
164
- fetchCartDetails
165
- });
166
-
167
97
  // Finally, invoke the post-submission callback.
168
98
  if (onSubmit) {
169
99
  onSubmit();
@@ -177,30 +107,18 @@ export const useBecomeSeller = props => {
177
107
  },
178
108
 
179
109
  [
180
- cartId,
181
110
  generateReCaptchaData,
182
111
  becomeSeller,
183
- signIn,
184
- setToken,
185
- apolloClient,
186
- removeCart,
187
- createCart,
188
- fetchCartId,
189
- mergeCarts,
190
- getUserDetails,
191
- fetchUserDetails,
192
- getCartDetails,
193
- fetchCartDetails,
194
112
  onSubmit,
195
113
  dispatch
196
114
  ]
197
115
  );
198
116
 
199
117
  const sanitizedInitialValues = useMemo(() => {
200
- const { email, firstName, lastName, ...rest } = initialValues;
118
+ const { sellerProfileName, companyName, ...rest } = initialValues;
201
119
 
202
120
  return {
203
- customer: { email, firstname: firstName, lastname: lastName },
121
+ seller: { profile_name: sellerProfileName, company: companyName, country: "AF" },
204
122
  ...rest
205
123
  };
206
124
  }, [initialValues]);
@@ -208,81 +126,21 @@ export const useBecomeSeller = props => {
208
126
  const errors = useMemo(
209
127
  () =>
210
128
  new Map([
211
- ['becomeSellerQuery', becomeSellerError],
212
- ['signInMutation', signInError]
129
+ ['becomeSellerQuery', becomeSellerError]
213
130
  ]),
214
- [becomeSellerError, signInError]
131
+ [becomeSellerError]
215
132
  );
216
133
 
134
+ const isSeller = storage.getItem('is_seller') || false;
135
+
217
136
  return {
137
+ isSeller,
218
138
  errors,
219
- handleCancel,
220
139
  handleSubmit,
221
- handleCancelKeyPress,
140
+ sellerType,
141
+ handleChange,
222
142
  initialValues: sanitizedInitialValues,
223
- isDisabled: isSubmitting || isGettingDetails || recaptchaLoading,
143
+ isDisabled: isSubmitting || recaptchaLoading,
224
144
  recaptchaWidgetProps
225
145
  };
226
- };
227
-
228
- /** JSDocs type definitions */
229
-
230
- /**
231
- * GraphQL queries for the create account form.
232
- * This is a type used by the {@link useBecomeSeller} talon.
233
- *
234
- * @typedef {Object} BecomeSellerQueries
235
- *
236
- * @property {GraphQLAST} customerQuery query to fetch customer details
237
- * @property {GraphQLAST} getCartDetailsQuery query to get cart details
238
- */
239
-
240
- /**
241
- * GraphQL mutations for the create account form.
242
- * This is a type used by the {@link useBecomeSeller} talon.
243
- *
244
- * @typedef {Object} BecomeSellerMutations
245
- *
246
- * @property {GraphQLAST} becomeSellerMutation mutation for creating new account
247
- * @property {GraphQLAST} createCartMutation mutation for creating new cart
248
- * @property {GraphQLAST} mergeCartsMutation mutation for merging carts
249
- * @property {GraphQLAST} signInMutation mutation for signing
250
- */
251
-
252
- /**
253
- * Initial values for the create account form.
254
- * This is a type used by the {@link useBecomeSeller} talon.
255
- *
256
- * @typedef {Object} InitialValues
257
- *
258
- * @property {String} email email id of the user
259
- * @property {String} firstName first name of the user
260
- * @property {String} lastName last name of the user
261
- */
262
-
263
- /**
264
- * Sanitized initial values for the create account form.
265
- * This is a type used by the {@link useBecomeSeller} talon.
266
- *
267
- * @typedef {Object} SanitizedInitialValues
268
- *
269
- * @property {String} email email id of the user
270
- * @property {String} firstname first name of the user
271
- * @property {String} lastname last name of the user
272
- */
273
-
274
- /**
275
- * Object type returned by the {@link useBecomeSeller} talon.
276
- * It provides props data to use when rendering the create account form component.
277
- *
278
- * @typedef {Object} BecomeSellerProps
279
- *
280
- * @property {Map} errors a map of errors to their respective mutations
281
- * @property {Function} handleCancel callback function to handle form cancellations
282
- * @property {Function} handleSubmit callback function to handle form submission
283
- * @property {SanitizedInitialValues} initialValues initial values for the create account form
284
- * @property {Boolean} isDisabled true if either details are being fetched or form is being submitted. False otherwise.
285
- * @property {Object} recaptchaWidgetProps - Props for the GoogleReCaptcha component.
286
- * @property {Function} recaptchaWidgetProps.containerElement - Container reference callback.
287
- * @property {Boolean} recaptchaWidgetProps.shouldRender - Checks if component should be rendered.
288
- */
146
+ };
@@ -1,13 +1,11 @@
1
- import { useCallback, useMemo } from 'react';
1
+ import { BrowserPersistence } from '@magento/peregrine/lib/util';
2
2
 
3
- export const useWebsiteSwitcher = (props = {}) => {
4
- const handleTriggerClick = useCallback(() => {
5
- // Toggle Stores Menu.
6
- // setStoreMenuIsOpen(isOpen => !isOpen);
7
- // globalThis.location.assign(`${newPath || ''}`);
8
- }, []);
3
+ const storage = new BrowserPersistence();
4
+
5
+ export const useBecomeSellerLink = (props = {}) => {
6
+ const isSeller = storage.getItem('is_seller') || false;
9
7
 
10
8
  return {
11
- handleTriggerClick
9
+ isSeller
12
10
  };
13
11
  };
@@ -1,9 +1,10 @@
1
1
  import { useCallback, useEffect, useMemo } from 'react';
2
2
  import { useHistory, useLocation } from 'react-router-dom';
3
+ import { BrowserPersistence } from '@magento/peregrine/lib/util';
3
4
 
4
- import { useUserContext } from '@magento/peregrine/lib/context/user';
5
+ const validBecomeSellerParams = ['sellerUrl', 'companyName', 'sellerProfileName'];
5
6
 
6
- const validBecomeSellerParams = ['email', 'firstName', 'lastName'];
7
+ const storage = new BrowserPersistence();
7
8
 
8
9
  const getBecomeSellerInitialValues = search => {
9
10
  const params = new URLSearchParams(search);
@@ -27,24 +28,20 @@ const getBecomeSellerInitialValues = search => {
27
28
  export const useBecomeSellerPage = props => {
28
29
  const { signedInRedirectUrl, signInPageUrl } = props;
29
30
  const history = useHistory();
30
- const [{ isSignedIn }] = useUserContext();
31
31
  const { search } = useLocation();
32
32
 
33
+ const isSeller = storage.getItem('is_seller') || false;
34
+ useEffect(() => {
35
+ if (isSeller) {
36
+ history.push('/')
37
+ }
38
+ }, [isSeller, history])
39
+
33
40
  // Keep location state in memory when pushing history and redirect to
34
41
  // the `from` url instead when creating an account
35
42
  const historyState = useMemo(() => {
36
43
  return history && history.location.state ? history.location.state : {};
37
44
  }, [history]);
38
- const fromRedirectUrl = historyState.from || null;
39
-
40
- // Redirect if user is signed in
41
- useEffect(() => {
42
- if (isSignedIn) {
43
- if (fromRedirectUrl || signedInRedirectUrl) {
44
- history.push(fromRedirectUrl || signedInRedirectUrl);
45
- }
46
- }
47
- }, [fromRedirectUrl, history, isSignedIn, signedInRedirectUrl]);
48
45
 
49
46
  const handleOnCancel = useCallback(() => {
50
47
  if (signInPageUrl) {
@@ -59,7 +56,8 @@ export const useBecomeSellerPage = props => {
59
56
  const becomeSellerProps = {
60
57
  initialValues,
61
58
  isCancelButtonHidden: false,
62
- onCancel: handleOnCancel
59
+ onCancel: handleOnCancel,
60
+ isSeller: isSeller
63
61
  };
64
62
 
65
63
  return {
@@ -0,0 +1,174 @@
1
+ import { useCallback, useMemo, useState } from 'react';
2
+ import { useMutation, useQuery } from '@apollo/client';
3
+ import { useUserContext } from '@magento/peregrine/lib/context/user';
4
+ import { useGoogleReCaptcha } from '@magento/peregrine/lib/hooks/useGoogleReCaptcha';
5
+ import { useEventingContext } from '@magento/peregrine/lib/context/eventing';
6
+
7
+ export const useSellerAccountPage = props => {
8
+ const {
9
+ mutations: {
10
+ setCustomerInformationMutation,
11
+ changeCustomerPasswordMutation
12
+ },
13
+ queries: { getCustomerInformationQuery }
14
+ } = props;
15
+
16
+ const [{ isSignedIn }] = useUserContext();
17
+ const [shouldShowNewPassword, setShouldShowNewPassword] = useState(false);
18
+
19
+ const [isUpdateMode, setIsUpdateMode] = useState(false);
20
+
21
+ const [, { dispatch }] = useEventingContext();
22
+
23
+ // Use local state to determine whether to display errors or not.
24
+ // Could be replaced by a "reset mutation" function from apollo client.
25
+ // https://github.com/apollographql/apollo-feature-requests/issues/170
26
+ const [displayError, setDisplayError] = useState(false);
27
+
28
+ const { data: accountInformationData, error: loadDataError } = useQuery(
29
+ getCustomerInformationQuery,
30
+ {
31
+ skip: !isSignedIn,
32
+ fetchPolicy: 'cache-and-network',
33
+ nextFetchPolicy: 'cache-first'
34
+ }
35
+ );
36
+
37
+ const [
38
+ setCustomerInformation,
39
+ {
40
+ error: customerInformationUpdateError,
41
+ loading: isUpdatingCustomerInformation
42
+ }
43
+ ] = useMutation(setCustomerInformationMutation);
44
+
45
+ const [
46
+ changeCustomerPassword,
47
+ {
48
+ error: customerPasswordChangeError,
49
+ loading: isChangingCustomerPassword
50
+ }
51
+ ] = useMutation(changeCustomerPasswordMutation);
52
+
53
+ const {
54
+ generateReCaptchaData,
55
+ recaptchaLoading,
56
+ recaptchaWidgetProps
57
+ } = useGoogleReCaptcha({
58
+ currentForm: 'CUSTOMER_EDIT',
59
+ formAction: 'editCustomer'
60
+ });
61
+
62
+ const initialValues = useMemo(() => {
63
+ if (accountInformationData) {
64
+ return { customer: accountInformationData.customer };
65
+ }
66
+ }, [accountInformationData]);
67
+
68
+ const handleChangePassword = useCallback(() => {
69
+ setShouldShowNewPassword(true);
70
+ }, [setShouldShowNewPassword]);
71
+
72
+ const handleCancel = useCallback(() => {
73
+ setIsUpdateMode(false);
74
+ setShouldShowNewPassword(false);
75
+ }, [setIsUpdateMode]);
76
+
77
+ const showUpdateMode = useCallback(() => {
78
+ setIsUpdateMode(true);
79
+
80
+ // If there were errors from removing/updating info, hide them
81
+ // when we open the modal.
82
+ setDisplayError(false);
83
+ }, [setIsUpdateMode]);
84
+
85
+ const handleSubmit = useCallback(
86
+ async ({ email, firstname, lastname, password, newPassword }) => {
87
+ try {
88
+ email = email.trim();
89
+ firstname = firstname.trim();
90
+ lastname = lastname.trim();
91
+ password = password.trim();
92
+ newPassword = newPassword ? newPassword.trim() : newPassword;
93
+
94
+ if (
95
+ initialValues.customer.email !== email ||
96
+ initialValues.customer.firstname !== firstname ||
97
+ initialValues.customer.lastname !== lastname
98
+ ) {
99
+ await setCustomerInformation({
100
+ variables: {
101
+ customerInput: {
102
+ email,
103
+ firstname,
104
+ lastname,
105
+ // You must send password because it is required
106
+ // when changing email.
107
+ password
108
+ }
109
+ }
110
+ });
111
+ }
112
+ if (password && newPassword) {
113
+ const recaptchaDataForChangeCustomerPassword = await generateReCaptchaData();
114
+ await changeCustomerPassword({
115
+ variables: {
116
+ currentPassword: password,
117
+ newPassword: newPassword
118
+ },
119
+ ...recaptchaDataForChangeCustomerPassword
120
+ });
121
+ }
122
+
123
+ dispatch({
124
+ type: 'USER_ACCOUNT_UPDATE',
125
+ payload: {
126
+ email,
127
+ firstName: firstname,
128
+ lastName: lastname
129
+ }
130
+ });
131
+
132
+ // After submission, close the form if there were no errors.
133
+ handleCancel(false);
134
+ } catch {
135
+ // Make sure any errors from the mutation are displayed.
136
+ setDisplayError(true);
137
+
138
+ // we have an onError link that logs errors, and FormError
139
+ // already renders this error, so just return to avoid
140
+ // triggering the success callback
141
+ return;
142
+ }
143
+ },
144
+ [
145
+ initialValues,
146
+ handleCancel,
147
+ setCustomerInformation,
148
+ generateReCaptchaData,
149
+ changeCustomerPassword,
150
+ dispatch
151
+ ]
152
+ );
153
+
154
+ const errors = displayError
155
+ ? [customerInformationUpdateError, customerPasswordChangeError]
156
+ : [];
157
+
158
+ return {
159
+ handleCancel,
160
+ formErrors: errors,
161
+ handleSubmit,
162
+ handleChangePassword,
163
+ initialValues,
164
+ isDisabled:
165
+ isUpdatingCustomerInformation ||
166
+ isChangingCustomerPassword ||
167
+ recaptchaLoading,
168
+ isUpdateMode,
169
+ loadDataError,
170
+ shouldShowNewPassword,
171
+ showUpdateMode,
172
+ recaptchaWidgetProps
173
+ };
174
+ };
@@ -24,6 +24,8 @@ export const useWebsiteByIp = websiteCodeInUrl => {
24
24
  const getWebsiteByUserIp = useMemo(() => {
25
25
  if (websiteByUserIpData) {
26
26
  return websiteByUserIpData;
27
+ } else {
28
+ return null;
27
29
  }
28
30
  }, [websiteByUserIpData]);
29
31