@akinon/next 1.13.1 → 1.14.1

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/.editorconfig ADDED
@@ -0,0 +1,7 @@
1
+ [*]
2
+ indent_style = space
3
+ indent_size = 2
4
+ end_of_line = lf
5
+ charset = utf-8
6
+ trim_trailing_whitespace = true
7
+ insert_final_newline = true
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @akinon/next
2
2
 
3
+ ## 1.14.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Change EOL
8
+
9
+ ## 1.14.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 35bce31: ZERO-2356: Add Price component
14
+ - 35bce31: ZERO-2332: Add endpoints for credit payment
15
+ - 35bce31: ZERO-2359: Add Input component
16
+ - 35bce31: ZERO-2394: Add stock alert list and delete endpoints
17
+ - 35bce31: ZERO-2393: Limit error log message length
18
+ - 35bce31: ZERO-2352: Add Button component
19
+ - 35bce31: ZERO-2325: Fix funds transfer payment error
20
+ - 35bce31: ZERO-2354: Add Accordion component
21
+
3
22
  ## 1.13.1
4
23
 
5
24
  ### Patch Changes
@@ -1,29 +1,29 @@
1
- .checkout-payment-iframe-wrapper {
2
- position: fixed;
3
- top: 0;
4
- left: 0;
5
- width: 100%;
6
- height: 100%;
7
- border: none;
8
- z-index: 1000;
9
- background-color: white;
10
-
11
- iframe {
12
- width: 100%;
13
- height: 100%;
14
- border: none;
15
- background-color: white;
16
- }
17
-
18
- .close-button {
19
- position: fixed;
20
- top: 16px;
21
- right: 16px;
22
- width: 32px;
23
- height: 32px;
24
- display: flex;
25
- align-items: center;
26
- justify-content: center;
27
- z-index: 1001;
28
- }
1
+ .checkout-payment-iframe-wrapper {
2
+ position: fixed;
3
+ top: 0;
4
+ left: 0;
5
+ width: 100%;
6
+ height: 100%;
7
+ border: none;
8
+ z-index: 1000;
9
+ background-color: white;
10
+
11
+ iframe {
12
+ width: 100%;
13
+ height: 100%;
14
+ border: none;
15
+ background-color: white;
16
+ }
17
+
18
+ .close-button {
19
+ position: fixed;
20
+ top: 16px;
21
+ right: 16px;
22
+ width: 32px;
23
+ height: 32px;
24
+ display: flex;
25
+ align-items: center;
26
+ justify-content: center;
27
+ z-index: 1001;
28
+ }
29
29
  }
File without changes
File without changes
File without changes
package/bin/pz-postdev.js CHANGED
File without changes
File without changes
File without changes
File without changes
package/bin/pz-predev.js CHANGED
File without changes
File without changes
@@ -0,0 +1,52 @@
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+ import { Icon } from './icon';
5
+ import { twMerge } from 'tailwind-merge';
6
+ import { AccordionProps } from '../types';
7
+
8
+ export const Accordion = ({
9
+ isCollapse = false,
10
+ title,
11
+ subTitle,
12
+ icons = ['chevron-up', 'chevron-down'],
13
+ iconSize = 16,
14
+ iconColor = 'fill-[#000000]',
15
+ children,
16
+ className,
17
+ titleClassName,
18
+ dataTestId
19
+ }: AccordionProps) => {
20
+ const [collapse, setCollapse] = useState(isCollapse);
21
+
22
+ return (
23
+ <div
24
+ className={twMerge(
25
+ 'flex flex-col justify-center border-b pb-4 mb-4 last:border-none',
26
+ className
27
+ )}
28
+ >
29
+ <div
30
+ className="flex items-center justify-between cursor-pointer"
31
+ onClick={() => setCollapse(!collapse)}
32
+ data-testid={dataTestId}
33
+ >
34
+ <div className="flex flex-col">
35
+ {title && (
36
+ <h3 className={twMerge('text-sm', titleClassName)}>{title}</h3>
37
+ )}
38
+ {subTitle && <h4 className="text-xs text-gray-700">{subTitle}</h4>}
39
+ </div>
40
+
41
+ {icons && (
42
+ <Icon
43
+ name={collapse ? icons[0] : icons[1]}
44
+ size={iconSize}
45
+ className={`fill-[${iconColor}]}`}
46
+ />
47
+ )}
48
+ </div>
49
+ {collapse && <div className="mt-3 text-sm">{children}</div>}
50
+ </div>
51
+ );
52
+ };
@@ -0,0 +1,46 @@
1
+ 'use client';
2
+
3
+ import { ButtonProps } from '../types/index';
4
+ import clsx from 'clsx';
5
+ import { twMerge } from 'tailwind-merge';
6
+
7
+ export const Button = (props: ButtonProps) => {
8
+ return (
9
+ <button
10
+ {...props}
11
+ className={twMerge(
12
+ clsx(
13
+ [
14
+ 'px-4',
15
+ 'h-10',
16
+ 'text-xs',
17
+ 'bg-primary',
18
+ 'text-primary-foreground',
19
+ 'border',
20
+ 'border-primary',
21
+ 'transition-all',
22
+ 'hover:bg-white',
23
+ 'hover:border-primary',
24
+ 'hover:text-primary'
25
+ ],
26
+ props.appearance === 'outlined' && [
27
+ 'bg-transparent ',
28
+ 'text-primary ',
29
+ 'hover:bg-primary ',
30
+ 'hover:text-primary-foreground'
31
+ ],
32
+ props.appearance === 'ghost' && [
33
+ 'bg-transparent',
34
+ 'border-transparent',
35
+ 'text-primary',
36
+ 'hover:bg-primary',
37
+ 'hover:text-primary-foreground'
38
+ ]
39
+ ),
40
+ props.className
41
+ )}
42
+ >
43
+ {props.children}
44
+ </button>
45
+ );
46
+ };
@@ -1 +1,17 @@
1
- export * from './react-portal';
1
+ export * from './accordion';
2
+ export * from './button';
3
+ export * from './client-root';
4
+ export * from './icon';
5
+ export * from './image';
6
+ export * from './input';
7
+ export * from './lazy-component';
8
+ export * from './loader-spinner';
9
+ export * from './mobile-app-toggler';
10
+ export * from './oauth-login';
11
+ export * from './plugin-module';
12
+ export * from './price';
13
+ export * from './pz-providers';
14
+ export * from './radio';
15
+ export * from './react-portal';
16
+ export * from './selected-payment-option-view';
17
+ export * from './trans';
@@ -0,0 +1,110 @@
1
+ import clsx from 'clsx';
2
+ import { forwardRef, FocusEvent, useState } from 'react';
3
+ import { Controller } from 'react-hook-form';
4
+ import NumberFormat, { NumberFormatProps } from 'react-number-format';
5
+ import { InputProps } from '../types';
6
+ import { twMerge } from 'tailwind-merge';
7
+
8
+ export const Input = forwardRef<
9
+ HTMLInputElement,
10
+ InputProps &
11
+ Pick<
12
+ NumberFormatProps,
13
+ 'format' | 'mask' | 'allowEmptyFormatting' | 'onValueChange'
14
+ >
15
+ >((props, ref) => {
16
+ const [focused, setFocused] = useState(false);
17
+ const [hasValue, setHasValue] = useState(false);
18
+ const {
19
+ id,
20
+ label,
21
+ labelStyle,
22
+ error,
23
+ mask,
24
+ format,
25
+ required = false,
26
+ ...rest
27
+ } = props;
28
+ const hasFloatingLabel = label && labelStyle === 'floating';
29
+ const inputClass = twMerge(
30
+ clsx(
31
+ 'text-xs border px-2.5 h-10 placeholder:text-gray-600',
32
+ 'focus-visible:outline-none', // disable outline on focus
33
+ { 'pt-3': hasFloatingLabel },
34
+ error
35
+ ? 'border-error focus:border-error'
36
+ : 'border-gray-500 hover:border-black focus:border-black'
37
+ ),
38
+ props.className
39
+ );
40
+ const inputProps: any = {
41
+ id,
42
+ ref,
43
+ className: inputClass,
44
+ onFocus: () => setFocused(true),
45
+ onBlur: (event: FocusEvent<HTMLInputElement>) => {
46
+ setFocused(false);
47
+ setHasValue(!!event.target.value);
48
+ }
49
+ };
50
+
51
+ const Label = () => {
52
+ if (!label) return null;
53
+
54
+ return (
55
+ <label
56
+ htmlFor={id}
57
+ className={clsx(
58
+ 'text-xs text-gray-800',
59
+ {
60
+ 'absolute left-2.5 pointer-events-none transition-all transform -translate-y-1/2':
61
+ hasFloatingLabel
62
+ },
63
+ { 'mb-2': !hasFloatingLabel },
64
+ { 'top-1/3': hasFloatingLabel && (focused || hasValue) },
65
+ { 'top-1/2': !(hasFloatingLabel && (focused || hasValue)) }
66
+ )}
67
+ >
68
+ {label} {required && <span className="text-secondary">*</span>}
69
+ </label>
70
+ );
71
+ };
72
+
73
+ return (
74
+ <div className="flex flex-col">
75
+ <div className="relative flex flex-col">
76
+ {props.format ? (
77
+ <>
78
+ {labelStyle !== 'floating' && <Label />}
79
+ <Controller
80
+ name={props.name ?? ''}
81
+ control={props.control}
82
+ defaultValue={false}
83
+ render={({ field }) => (
84
+ <NumberFormat
85
+ format={format}
86
+ mask={mask ?? ''}
87
+ {...rest}
88
+ {...field}
89
+ {...inputProps}
90
+ />
91
+ )}
92
+ />
93
+ {labelStyle === 'floating' && <Label />}
94
+ </>
95
+ ) : (
96
+ <>
97
+ {labelStyle !== 'floating' && <Label />}
98
+ <input {...rest} {...inputProps} />
99
+ {labelStyle === 'floating' && <Label />}
100
+ </>
101
+ )}
102
+ </div>
103
+ {error && (
104
+ <span className="mt-1 text-sm text-error">{error.message}</span>
105
+ )}
106
+ </div>
107
+ );
108
+ });
109
+
110
+ Input.displayName = 'Input';
@@ -11,7 +11,8 @@ enum Plugin {
11
11
  CheckoutGiftPack = 'pz-checkout-gift-pack',
12
12
  GPay = 'pz-gpay',
13
13
  Otp = 'pz-otp',
14
- BKMExpress = 'pz-bkm'
14
+ BKMExpress = 'pz-bkm',
15
+ Masterpass = 'pz-masterpass'
15
16
  }
16
17
 
17
18
  export enum Component {
@@ -22,7 +23,8 @@ export enum Component {
22
23
  CheckoutGiftPack = 'CheckoutGiftPack',
23
24
  GPay = 'GPayOption',
24
25
  Otp = 'Otp',
25
- BKMExpress = 'BKMOption'
26
+ BKMExpress = 'BKMOption',
27
+ MasterpassCardList = 'MasterpassCardList'
26
28
  }
27
29
 
28
30
  const PluginComponents = new Map([
@@ -33,7 +35,8 @@ const PluginComponents = new Map([
33
35
  [Plugin.CheckoutGiftPack, [Component.CheckoutGiftPack]],
34
36
  [Plugin.GPay, [Component.GPay]],
35
37
  [Plugin.Otp, [Component.Otp]],
36
- [Plugin.BKMExpress, [Component.BKMExpress]]
38
+ [Plugin.BKMExpress, [Component.BKMExpress]],
39
+ [Plugin.Masterpass, [Component.MasterpassCardList]]
37
40
  ]);
38
41
 
39
42
  const getPlugin = (component: Component) => {
@@ -53,10 +56,6 @@ export default function PluginModule({
53
56
  }) {
54
57
  const plugin = getPlugin(component);
55
58
 
56
- if (!(plugins as string[]).includes(plugin)) {
57
- return null;
58
- }
59
-
60
59
  const Component = useMemo(
61
60
  () =>
62
61
  dynamic(
@@ -91,8 +90,12 @@ export default function PluginModule({
91
90
  },
92
91
  { ssr: false }
93
92
  ),
94
- [plugin]
93
+ [plugin, component]
95
94
  );
96
95
 
96
+ if (!(plugins as string[]).includes(plugin)) {
97
+ return null;
98
+ }
99
+
97
100
  return <Component {...props} />;
98
101
  }
@@ -0,0 +1,55 @@
1
+ import { useMemo } from 'react';
2
+ import NumberFormat, { NumberFormatProps } from 'react-number-format';
3
+ import { getCurrency } from '@akinon/next/utils';
4
+
5
+ import { useLocalization } from '@akinon/next/hooks';
6
+ import { PriceProps } from '../types';
7
+
8
+ export const Price = (props: NumberFormatProps & PriceProps) => {
9
+ const {
10
+ value,
11
+ currencyCode,
12
+ displayType = 'text',
13
+ useCurrencySymbol = false,
14
+ useCurrencyAfterPrice = true,
15
+ useCurrencySpace = true,
16
+ useNegative = false,
17
+ useNegativeSpace = true,
18
+ thousandSeparator = '.',
19
+ decimalScale = 2,
20
+ decimalSeparator = ',',
21
+ fixedDecimalScale = true,
22
+ ...rest
23
+ } = props;
24
+ const { currency: selectedCurrencyCode } = useLocalization();
25
+ const currencyCode_ = currencyCode || selectedCurrencyCode;
26
+
27
+ // TODO: This is very bad practice. It broke decimalScale.
28
+ const _value = value?.toString().replace('.', ',');
29
+
30
+ const currency = useMemo(
31
+ () =>
32
+ getCurrency({
33
+ currencyCode: currencyCode_,
34
+ useCurrencySymbol,
35
+ useCurrencyAfterPrice,
36
+ useCurrencySpace
37
+ }),
38
+ [currencyCode_, useCurrencySymbol, useCurrencyAfterPrice, useCurrencySpace]
39
+ );
40
+
41
+ return (
42
+ <NumberFormat
43
+ value={useNegative ? `-${useNegativeSpace}${_value}` : _value}
44
+ {...{
45
+ [useCurrencyAfterPrice ? 'suffix' : 'prefix']: currency
46
+ }}
47
+ displayType={displayType}
48
+ thousandSeparator={thousandSeparator}
49
+ decimalScale={decimalScale}
50
+ decimalSeparator={decimalSeparator}
51
+ fixedDecimalScale={fixedDecimalScale}
52
+ {...rest}
53
+ />
54
+ );
55
+ };
@@ -50,7 +50,14 @@ export default function SelectedPaymentOptionView() {
50
50
  );
51
51
  } else if (payment_option.payment_type === 'loyalty_money') {
52
52
  promise = import(`views/checkout/steps/payment/options/loyalty`);
53
+ } else if (payment_option.payment_type === 'masterpass') {
54
+ promise = import(
55
+ `views/checkout/steps/payment/options/credit-card`
56
+ );
53
57
  }
58
+ // else if (payment_option.payment_type === 'credit_payment') {
59
+ // promise = import(`views/checkout/steps/payment/options/credit-payment`);
60
+ // }
54
61
  // else if (payment_option.payment_type === 'gpay') {
55
62
  // promise = import(`views/checkout/steps/payment/options/gpay`);
56
63
  // }