@riosst100/pwa-marketplace 2.8.9 → 2.9.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.
Files changed (20) hide show
  1. package/i18n/en_US.json +1 -1
  2. package/i18n/id_ID.json +1 -1
  3. package/package.json +1 -1
  4. package/src/components/FilterTop/FilterBlockList/filterBlockList.js +2 -0
  5. package/src/components/FilterTop/FilterBlockList/filterTopItemGroup.js +20 -2
  6. package/src/components/FilterTop/filterTop.js +4 -1
  7. package/src/components/FilterTop/filterTopBlock.js +2 -0
  8. package/src/overwrites/peregrine/lib/talons/FilterSidebar/useFilterSidebar.js +12 -10
  9. package/src/overwrites/venia-ui/lib/components/CheckoutPage/ItemsReview/item.js +1 -1
  10. package/src/overwrites/venia-ui/lib/components/CheckoutPage/ItemsReview/item.module.css +7 -2
  11. package/src/overwrites/venia-ui/lib/components/CheckoutPage/ItemsReview/showAllButton.js +1 -1
  12. package/src/overwrites/venia-ui/lib/components/CheckoutPage/ItemsReview/showAllButton.module.css +4 -3
  13. package/src/overwrites/venia-ui/lib/components/CheckoutPage/PaymentInformation/paymentInformation.js +4 -8
  14. package/src/overwrites/venia-ui/lib/components/CheckoutPage/PaymentInformation/paymentMethods.js +59 -2
  15. package/src/overwrites/venia-ui/lib/components/CheckoutPage/ShippingMethod/shippingRadios.js +3 -1
  16. package/src/overwrites/venia-ui/lib/components/CheckoutPage/ShippingMethod/shippingRadios.module.css +51 -2
  17. package/src/overwrites/venia-ui/lib/components/CheckoutPage/checkoutPage.js +11 -28
  18. package/src/overwrites/venia-ui/lib/components/CheckoutPage/checkoutPage.module.css +2 -1
  19. package/src/talons/FilterTop/filterTop.gql.js +1 -0
  20. package/src/talons/FilterTop/useFilterTop.js +2 -1
package/i18n/en_US.json CHANGED
@@ -98,7 +98,7 @@
98
98
  "checkoutPage.reviewOrder": "Review Order",
99
99
  "checkoutPage.setAPasswordAndSave": "Set a password and save your information for next time in one easy step!",
100
100
  "checkoutPage.shippingMethodStep": "Shipping Method",
101
- "checkoutPage.showAllItems": "SHOW ALL ITEMS",
101
+ "checkoutPage.showAllItems": "Show All Items",
102
102
  "checkoutPage.signInButton": "Sign In",
103
103
  "checkoutPage.signInLabel": "Sign in for Express Checkout",
104
104
  "checkoutPage.step0": "Loading Payment",
package/i18n/id_ID.json CHANGED
@@ -99,7 +99,7 @@
99
99
  "checkoutPage.reviewOrder": "Review Order",
100
100
  "checkoutPage.setAPasswordAndSave": "Set a password and save your information for next time in one easy step!",
101
101
  "checkoutPage.shippingMethodStep": "2. Shipping Method",
102
- "checkoutPage.showAllItems": "SHOW ALL ITEMS",
102
+ "checkoutPage.showAllItems": "Show All Items",
103
103
  "checkoutPage.signInButton": "Sign In",
104
104
  "checkoutPage.signInLabel": "Sign in for Express Checkout",
105
105
  "checkoutPage.step0": "Loading Payment",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@riosst100/pwa-marketplace",
3
3
  "author": "riosst100@gmail.com",
4
- "version": "2.8.9",
4
+ "version": "2.9.0",
5
5
  "main": "src/index.js",
6
6
  "pwa-studio": {
7
7
  "targets": {
@@ -15,6 +15,7 @@ const FilterBlockList = props => {
15
15
  originalFilterState,
16
16
  search,
17
17
  setFilterBy,
18
+ customFiltersData,
18
19
  filterBy
19
20
  } = props;
20
21
 
@@ -23,6 +24,7 @@ const FilterBlockList = props => {
23
24
  return (
24
25
  <FilterTopItemGroup
25
26
  setFilterBy={setFilterBy}
27
+ customFiltersData={customFiltersData}
26
28
  filterBy={filterBy}
27
29
  filterApi={filterApi}
28
30
  filterState={filterState}
@@ -7,7 +7,7 @@ import defaultClasses from './filterTopItemGroup.module.css';
7
7
  import CurrentTopFilter from '@riosst100/pwa-marketplace/src/components/FilterTop/CurrentTopFilters/currentTopFilter';
8
8
 
9
9
  const FilterTopItemGroup = props => {
10
- const { setFilterBy, filterBy, filterApi, filterState, group, items, onApply, labels, filterNames, originalFilterState, search } = props;
10
+ const { customFiltersData, setFilterBy, filterBy, filterApi, filterState, group, items, onApply, labels, filterNames, originalFilterState, search } = props;
11
11
 
12
12
  const classes = useStyle(defaultClasses, props.classes);
13
13
 
@@ -83,11 +83,29 @@ const FilterTopItemGroup = props => {
83
83
  }
84
84
  }, [field, fieldApi, fieldState.value, fieldValue]);
85
85
 
86
+ // console.log(customFiltersData.filters)
87
+
88
+
89
+ const customFilterData = useMemo(() => {
90
+ const filtered = customFiltersData.filters.filter(item => item.attribute_code === group);
91
+ // console.log('filtered ' + group,filtered);
92
+ if (filtered) {
93
+ // console.log('filtered ' + group,filtered);
94
+ // console.log('show_all_btn 2 ' + group,isShowAllBtn);
95
+ return filtered[0];
96
+ }
97
+
98
+ return null;
99
+ }, [customFiltersData]);
100
+
86
101
  return (
87
102
  <div className={classes.root}>
88
103
  {radioItems}
89
104
  {filterElements && filterElements.length > 10 ? <span className={classes.item}><b>More Item</b></span> : ''}
90
- {filterElements && filterElements.length ? filterElements : group && group != "character" && group != "product_series" && group != "scale" && group != "product_line" && group != "trains" && group != "franchise" && group != "brands" && group != "bricks_categories" && group != "category" && group != "sc_sports_categories" && group != "card_game" && group != "filterby" && group != "shopby" && group != "cat_id" ? (<span className={classes.item}><b>All</b></span>) : ''}
105
+
106
+ {customFilterData && customFilterData.show_all_btn ? <span className={classes.item}><b>All</b></span> : ''}
107
+
108
+ {/* {filterElements && filterElements.length ? filterElements : group && group != "character" && group != "product_series" && group != "scale" && group != "product_line" && group != "trains" && group != "franchise" && group != "brands" && group != "bricks_categories" && group != "category" && group != "sc_sports_categories" && group != "card_game" && group != "filterby" && group != "shopby" && group != "cat_id" ? (<span className={classes.item}><b>All</b></span>) : ''} */}
91
109
  </div>
92
110
  );
93
111
  };
@@ -34,7 +34,8 @@ const FilterTop = props => {
34
34
  filterState,
35
35
  handleApply,
36
36
  handleReset,
37
- customFilters
37
+ customFilters,
38
+ customFiltersData
38
39
  } = talonProps;
39
40
 
40
41
  const classes = useStyle(defaultClasses, props.classes);
@@ -116,6 +117,7 @@ const FilterTop = props => {
116
117
  filterBy={filterBy}
117
118
  filterNames={filterNames}
118
119
  filterApi={filterApi}
120
+ customFiltersData={customFiltersData}
119
121
  filterState={blockState}
120
122
  originalFilterState={filterState}
121
123
  filterFrontendInput={frontendInput}
@@ -137,6 +139,7 @@ const FilterTop = props => {
137
139
  filterState,
138
140
  filterCountToOpen,
139
141
  customFilters,
142
+ customFiltersData,
140
143
  handleApplyFilter
141
144
  ]
142
145
  );
@@ -23,6 +23,7 @@ const FilterTopBlock = props => {
23
23
  name,
24
24
  onApply,
25
25
  filterNames,
26
+ customFiltersData,
26
27
  initialOpen,
27
28
  originalFilterState,
28
29
  search,
@@ -42,6 +43,7 @@ const FilterTopBlock = props => {
42
43
  setFilterBy={setFilterBy}
43
44
  filterBy={filterBy}
44
45
  filterApi={filterApi}
46
+ customFiltersData={customFiltersData}
45
47
  filterState={filterState}
46
48
  originalFilterState={originalFilterState}
47
49
  name={name}
@@ -36,16 +36,18 @@ export const useFilterSidebar = props => {
36
36
 
37
37
  const { data: introspectionData } = useQuery(getFilterInputsQuery);
38
38
 
39
- const {
40
- called: subFilterItemsCalled,
41
- data: subFilterItems,
42
- loading: subFilterItemsLoading,
43
- error: subFilterItemsError
44
- } = useQuery(getSubFiltersQuery,
45
- {
46
- fetchPolicy: 'cache-and-network',
47
- nextFetchPolicy: 'cache-first'
48
- });
39
+ // const {
40
+ // called: subFilterItemsCalled,
41
+ // data: subFilterItems,
42
+ // loading: subFilterItemsLoading,
43
+ // error: subFilterItemsError
44
+ // } = useQuery(getSubFiltersQuery,
45
+ // {
46
+ // fetchPolicy: 'cache-and-network',
47
+ // nextFetchPolicy: 'cache-first'
48
+ // });
49
+
50
+ const subFilterItems = [];
49
51
 
50
52
  const attributeCodes = useMemo(
51
53
  () => filters.map(({ attribute_code }) => attribute_code),
@@ -25,7 +25,7 @@ const Item = props => {
25
25
  <Image
26
26
  alt={product.name}
27
27
  classes={{ root: classes.thumbnail }}
28
- width={100}
28
+ width={50}
29
29
  resource={
30
30
  configurableThumbnailSource === 'itself' &&
31
31
  configured_variant
@@ -30,9 +30,9 @@
30
30
  }
31
31
 
32
32
  .thumbnail {
33
- composes: border from global;
33
+ /* composes: border from global;
34
34
  composes: border-solid from global;
35
- composes: border-subtle from global;
35
+ composes: border-subtle from global; */
36
36
  grid-column: 1 / span 1;
37
37
  grid-row: 1 / span 3;
38
38
  }
@@ -41,6 +41,11 @@
41
41
  composes: font-medium from global;
42
42
  grid-column: 2 / span 1;
43
43
  grid-row: 1 / span 1;
44
+ display: -webkit-box;
45
+ -webkit-line-clamp: 2;
46
+ -webkit-box-orient: vertical;
47
+ overflow: hidden;
48
+ word-break: break-word;
44
49
  }
45
50
 
46
51
  .quantity {
@@ -21,7 +21,7 @@ const ShowAllButton = props => {
21
21
  <span className={classes.text}>
22
22
  <FormattedMessage
23
23
  id={'checkoutPage.showAllItems'}
24
- defaultMessage={'SHOW ALL ITEMS'}
24
+ defaultMessage={'Show All Items'}
25
25
  />
26
26
  </span>
27
27
  <Icon
@@ -1,7 +1,8 @@
1
1
  .root {
2
2
  composes: border-t-2 from global;
3
3
  composes: border-solid from global;
4
- composes: border-subtle from global;
4
+ /* composes: border-subtle from global; */
5
+ border-color: #F2F2F2;
5
6
  composes: px-0 from global;
6
7
  composes: py-3 from global;
7
8
  composes: w-full from global;
@@ -19,10 +20,10 @@
19
20
  composes: font-medium from global;
20
21
  composes: text-brand-dark from global;
21
22
  composes: text-sm from global;
23
+ text-transform: capitalize;
22
24
  }
23
25
 
24
26
  .arrowDown {
25
27
  composes: root from '@magento/venia-ui/lib/components/Icon/icon.module.css';
26
-
27
- --stroke: rgb(var(--venia-brand-color-1-700));
28
+ --stroke: #f76b1c;
28
29
  }
@@ -55,9 +55,8 @@ const PaymentInformation = props => {
55
55
  );
56
56
  }
57
57
 
58
- const paymentInformation = doneEditing ? (
59
- <Summary onEdit={showEditModal} />
60
- ) : (
58
+ // Always show the full payment methods UI so users can switch/edit easily even after Review.
59
+ const paymentInformation = (
61
60
  <Form>
62
61
  <PaymentMethods
63
62
  onPaymentError={handlePaymentError}
@@ -68,11 +67,8 @@ const PaymentInformation = props => {
68
67
  </Form>
69
68
  );
70
69
 
71
- const editModal = doneEditing ? (
72
- <Suspense fallback={null}>
73
- <EditModal onClose={hideEditModal} isOpen={isEditModalActive} />
74
- </Suspense>
75
- ) : null;
70
+ // Do not render the edit modal; changes happen inline.
71
+ const editModal = null;
76
72
 
77
73
  return (
78
74
  <div className={classes.root} data-cy="PaymentInformation-root">
@@ -1,14 +1,20 @@
1
- import React from 'react';
1
+ import React, { useCallback } from 'react';
2
2
  import { shape, string, bool, func } from 'prop-types';
3
3
  import { useIntl } from 'react-intl';
4
+ import { useMutation, useQuery } from '@apollo/client';
4
5
 
5
6
  import { usePaymentMethods } from '@magento/peregrine/lib/talons/CheckoutPage/PaymentInformation/usePaymentMethods';
7
+ import { useCartContext } from '@magento/peregrine/lib/context/cart';
6
8
 
7
9
  import { useStyle } from '@magento/venia-ui/lib/classify';
8
10
  import RadioGroup from '@magento/venia-ui/lib/components/RadioGroup';
9
11
  import Radio from '@magento/venia-ui/lib/components/RadioGroup/radio';
10
12
  import defaultClasses from './paymentMethods.module.css';
11
13
  import payments from './paymentMethodCollection';
14
+ import {
15
+ GET_SHIPPING_ADDRESS,
16
+ SET_BILLING_ADDRESS
17
+ } from '@riosst100/pwa-marketplace/src/talons/Xendit/xendit';
12
18
 
13
19
  const PaymentMethods = props => {
14
20
  const {
@@ -33,6 +39,57 @@ const PaymentMethods = props => {
33
39
  isLoading
34
40
  } = talonProps;
35
41
 
42
+ const [{ cartId }] = useCartContext();
43
+
44
+ const { data: shippingData } = useQuery(GET_SHIPPING_ADDRESS, {
45
+ skip: !cartId,
46
+ variables: { cartId }
47
+ });
48
+
49
+ const [setBillingAddress] = useMutation(SET_BILLING_ADDRESS);
50
+
51
+ const getRegionValue = region => {
52
+ if (!region) return '';
53
+ return region.region_id || region.label || region.code || '';
54
+ };
55
+
56
+ const handleChangeAndSetBilling = useCallback(
57
+ async event => {
58
+ // First, run canonical selection logic (updates selected payment on cart)
59
+ handlePaymentMethodSelection(event);
60
+
61
+ // Then, proactively set billing address using the selected shipping address
62
+ try {
63
+ const shippingAddresses =
64
+ shippingData?.cart?.shippingAddresses || [];
65
+ const addr = shippingAddresses[0];
66
+ if (!addr || !cartId) return;
67
+
68
+ const street1 = Array.isArray(addr.street) ? addr.street[0] || '' : '';
69
+ const street2 = Array.isArray(addr.street) ? addr.street[1] || '' : '';
70
+ await setBillingAddress({
71
+ variables: {
72
+ cartId,
73
+ firstName: addr.firstName || '',
74
+ lastName: addr.lastName || '',
75
+ street1,
76
+ street2,
77
+ city: addr.city || '',
78
+ region: getRegionValue(addr.region),
79
+ postcode: addr.postcode || '',
80
+ country: addr.country?.code || '',
81
+ phoneNumber: addr.phoneNumber || ''
82
+ }
83
+ });
84
+ } catch (e) {
85
+ // Non-blocking; payment selection should still work even if billing sync fails
86
+ // eslint-disable-next-line no-console
87
+ console.warn('Gagal menyetel billing address saat memilih metode pembayaran:', e);
88
+ }
89
+ },
90
+ [cartId, handlePaymentMethodSelection, setBillingAddress, shippingData]
91
+ );
92
+
36
93
  if (isLoading) {
37
94
  return null;
38
95
  }
@@ -93,7 +150,7 @@ const PaymentMethods = props => {
93
150
  label: classes.radio_label
94
151
  }}
95
152
  checked={isSelected}
96
- onChange={handlePaymentMethodSelection}
153
+ onChange={handleChangeAndSetBilling}
97
154
  />
98
155
  {renderedComponent}
99
156
  </div>
@@ -26,7 +26,9 @@ const ShippingRadios = props => {
26
26
  const radioGroupClasses = {
27
27
  message: classes.radioMessage,
28
28
  radioLabel: classes.radioLabel,
29
- root: classes.radioRoot
29
+ root: classes.radioRoot,
30
+ // Ensure we can tweak the label container (the clickable row)
31
+ radioContainer: classes.radioContainer
30
32
  };
31
33
 
32
34
  const shippingRadios = shippingMethods.map(method => {
@@ -8,8 +8,9 @@
8
8
  composes: grid from global;
9
9
  composes: grid-cols-[100%] from global;
10
10
  composes: justify-start from global;
11
-
12
- composes: sm_grid-cols-autoAuto from global;
11
+ /* On small screens and up, make two columns: name grows, price auto */
12
+ composes: sm_grid-cols-[1fr,auto] from global;
13
+ composes: items-center from global;
13
14
  }
14
15
 
15
16
  .radioMessage {
@@ -20,3 +21,51 @@
20
21
  composes: leading-normal from global;
21
22
  composes: text-error from global;
22
23
  }
24
+
25
+ /* Fix alignment and visual of radio controls inside the modal */
26
+ .radioContainer {
27
+ /* Ensure consistent layout: control + content */
28
+ composes: justify-items-start from global;
29
+ display: grid;
30
+ grid-template-columns: min-content 1fr;
31
+ grid-template-areas: 'input label';
32
+ justify-content: flex-start !important;
33
+ align-items: flex-start;
34
+ }
35
+
36
+ /* Normalize the control size and overlaying layers so input and icon overlap */
37
+ .radioContainer :global([class*="radio-input-"]) {
38
+ width: 1.5rem; /* 24px default Venia size for harmony with icon */
39
+ height: 1.5rem;
40
+ box-shadow: none !important; /* remove active/focus blobs that appear offset */
41
+ }
42
+
43
+ .radioContainer :global([class*="radio-icon-"]) {
44
+ position: relative !important;
45
+ width: 1.5rem !important;
46
+ height: 1.5rem !important;
47
+ display: inline-block;
48
+ }
49
+
50
+ /* Prevent filled background bleed that can look like an offset dot */
51
+ .radioContainer :global([class*="radio-input-"]:checked) {
52
+ background-color: transparent !important; /* dot handled via icon ::after */
53
+ }
54
+
55
+ /* Draw an inner dot centered in the ring when checked */
56
+ .radioContainer :global([class*="radio-icon-"]) {
57
+ position: relative;
58
+ }
59
+
60
+ .radioContainer :global([class*="radio-input-"]:checked) + :global([class*="radio-icon-"])::after {
61
+ content: '';
62
+ position: absolute;
63
+ left: 30%;
64
+ top: 30%;
65
+ width: 0.6rem;
66
+ height: 0.6rem;
67
+ background: #f76b1c;
68
+ border-radius: 9999px;
69
+ transform: translate(-50%, -50%);
70
+ pointer-events: none;
71
+ }
@@ -244,36 +244,19 @@ const CheckoutPage = props => {
244
244
  </div>
245
245
  ) : null;
246
246
 
247
- const reviewOrderButton =
248
- checkoutStep === CHECKOUT_STEP.PAYMENT ? (
249
- <Button
250
- onClick={handleReviewOrder}
251
- onKeyDown={handleReviewOrderEnterKeyPress}
252
- priority="high"
253
- className={classes.review_order_button}
254
- data-cy="CheckoutPage-reviewOrderButton"
255
- disabled={
256
- reviewOrderButtonClicked ||
257
- isUpdating ||
258
- !isPaymentAvailable
259
- }
260
- >
261
- <FormattedMessage
262
- id={'checkoutPage.reviewOrder'}
263
- defaultMessage={'Review Order'}
264
- />
265
- </Button>
266
- ) : null;
247
+ // Remove Review Order button; flow uses only Place Order
248
+ const reviewOrderButton = null;
267
249
 
268
- const itemsReview =
269
- checkoutStep === CHECKOUT_STEP.REVIEW ? (
270
- <div className={classes.items_review_container}>
271
- <ItemsReview />
272
- </div>
273
- ) : null;
250
+ // Show ItemsReview from the beginning, not only at the REVIEW step
251
+ const itemsReview = (
252
+ <div className={classes.items_review_container}>
253
+ <ItemsReview />
254
+ </div>
255
+ );
274
256
 
257
+ // Allow placing order starting from the Payment step (no separate review action)
275
258
  const placeOrderButton =
276
- checkoutStep === CHECKOUT_STEP.REVIEW ? (
259
+ checkoutStep >= CHECKOUT_STEP.PAYMENT ? (
277
260
  <Button
278
261
  onClick={handlePlaceOrder}
279
262
  onKeyDown={handlePlaceOrderEnterKeyPress}
@@ -312,6 +295,7 @@ const CheckoutPage = props => {
312
295
  }
313
296
  >
314
297
  <OrderSummary isUpdating={isUpdating} />
298
+ {itemsReview}
315
299
  </div>
316
300
  );
317
301
 
@@ -394,7 +378,6 @@ const CheckoutPage = props => {
394
378
  </div>
395
379
  {priceAdjustmentsSection}
396
380
  {reviewOrderButton}
397
- {itemsReview}
398
381
  {orderSummary}
399
382
  {placeOrderButton}
400
383
  <GoogleReCaptcha {...recaptchaWidgetProps} />
@@ -124,6 +124,7 @@
124
124
 
125
125
  .items_review_container {
126
126
  grid-column: 1 / span 1;
127
+ margin-top: 2rem;
127
128
  }
128
129
 
129
130
  .summaryContainer {
@@ -132,7 +133,7 @@
132
133
  composes: lg_h-minContent from global;
133
134
  composes: lg_sticky from global;
134
135
  /* TODO @TW: review. Magic number. Slightly bigger than sticky header. */
135
- composes: lg_top-[9rem] from global;
136
+ composes: lg_top-[2.5rem] from global;
136
137
  }
137
138
 
138
139
  @media (min-width: 960px) {
@@ -7,6 +7,7 @@ export const GET_CUSTOM_FILTERS = gql`
7
7
  filters {
8
8
  label
9
9
  count
10
+ show_all_btn
10
11
  attribute_code
11
12
  options {
12
13
  label
@@ -307,6 +307,7 @@ export const useFilterTop = props => {
307
307
  handleReset,
308
308
  isApplying,
309
309
  isOpen,
310
- customFilters
310
+ customFilters,
311
+ customFiltersData
311
312
  };
312
313
  };