@akinon/pz-checkout-gift-pack 2.0.0-beta.2 → 2.0.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +122 -6
- package/README.md +127 -3
- package/package.json +9 -9
- package/src/index.tsx +203 -91
package/CHANGELOG.md
CHANGED
|
@@ -1,18 +1,134 @@
|
|
|
1
1
|
# @akinon/pz-checkout-gift-pack
|
|
2
2
|
|
|
3
|
-
## 2.0.0-beta.
|
|
3
|
+
## 2.0.0-beta.21
|
|
4
4
|
|
|
5
|
-
## 2.0.0-beta.
|
|
5
|
+
## 2.0.0-beta.20
|
|
6
|
+
|
|
7
|
+
## 1.126.0
|
|
8
|
+
|
|
9
|
+
## 1.125.2
|
|
10
|
+
|
|
11
|
+
## 1.125.1
|
|
12
|
+
|
|
13
|
+
## 1.125.0
|
|
14
|
+
|
|
15
|
+
## 1.124.0
|
|
16
|
+
|
|
17
|
+
## 1.123.0
|
|
18
|
+
|
|
19
|
+
## 1.122.0
|
|
20
|
+
|
|
21
|
+
## 1.121.0
|
|
22
|
+
|
|
23
|
+
## 1.120.0
|
|
24
|
+
|
|
25
|
+
## 1.119.0
|
|
26
|
+
|
|
27
|
+
## 1.118.0
|
|
28
|
+
|
|
29
|
+
## 1.117.0
|
|
30
|
+
|
|
31
|
+
## 1.116.0
|
|
32
|
+
|
|
33
|
+
## 1.115.0
|
|
34
|
+
|
|
35
|
+
## 1.114.0
|
|
36
|
+
|
|
37
|
+
## 1.113.0
|
|
38
|
+
|
|
39
|
+
## 1.112.0
|
|
40
|
+
|
|
41
|
+
## 1.111.0
|
|
42
|
+
|
|
43
|
+
## 1.110.0
|
|
44
|
+
|
|
45
|
+
## 1.109.0
|
|
46
|
+
|
|
47
|
+
## 1.108.0
|
|
48
|
+
|
|
49
|
+
## 1.107.0
|
|
50
|
+
|
|
51
|
+
## 1.106.0
|
|
52
|
+
|
|
53
|
+
### Minor Changes
|
|
54
|
+
|
|
55
|
+
- 8bc82f0: ZERO-3405: Update Readme
|
|
56
|
+
|
|
57
|
+
## 1.105.0
|
|
58
|
+
|
|
59
|
+
## 1.104.0
|
|
60
|
+
|
|
61
|
+
## 1.103.0
|
|
62
|
+
|
|
63
|
+
## 1.102.0
|
|
64
|
+
|
|
65
|
+
## 1.101.0
|
|
66
|
+
|
|
67
|
+
## 1.100.0
|
|
68
|
+
|
|
69
|
+
## 1.99.0
|
|
70
|
+
|
|
71
|
+
### Minor Changes
|
|
72
|
+
|
|
73
|
+
- d58538b: ZERO-3638: Enhance RC pipeline: add fetch, merge, and pre-release setup with conditional commit
|
|
74
|
+
|
|
75
|
+
## 1.98.0
|
|
76
|
+
|
|
77
|
+
## 1.97.0
|
|
78
|
+
|
|
79
|
+
## 1.96.0
|
|
80
|
+
|
|
81
|
+
## 1.95.0
|
|
82
|
+
|
|
83
|
+
## 1.94.0
|
|
84
|
+
|
|
85
|
+
## 1.93.0
|
|
86
|
+
|
|
87
|
+
## 1.92.0
|
|
88
|
+
|
|
89
|
+
## 1.91.0
|
|
90
|
+
|
|
91
|
+
## 1.90.0
|
|
6
92
|
|
|
7
93
|
### Minor Changes
|
|
8
94
|
|
|
9
|
-
- ZERO-
|
|
95
|
+
- ec9ff89: ZERO-3368: Add customization to package
|
|
96
|
+
|
|
97
|
+
## 1.89.0
|
|
98
|
+
|
|
99
|
+
## 1.88.0
|
|
100
|
+
|
|
101
|
+
### Minor Changes
|
|
102
|
+
|
|
103
|
+
- ce64181: ZERO-3333: Add data-testid for checkout gift pack
|
|
104
|
+
|
|
105
|
+
## 1.87.0
|
|
106
|
+
|
|
107
|
+
## 1.86.0
|
|
108
|
+
|
|
109
|
+
## 1.85.0
|
|
110
|
+
|
|
111
|
+
## 1.84.0
|
|
112
|
+
|
|
113
|
+
### Minor Changes
|
|
114
|
+
|
|
115
|
+
- 624a4eb: ZERO-3276: Update installation instructions across multiple README files to standardize format and improve clarity
|
|
116
|
+
|
|
117
|
+
## 1.83.0
|
|
118
|
+
|
|
119
|
+
## 1.82.0
|
|
120
|
+
|
|
121
|
+
## 1.81.0
|
|
122
|
+
|
|
123
|
+
## 1.80.0
|
|
124
|
+
|
|
125
|
+
## 1.79.0
|
|
10
126
|
|
|
11
|
-
##
|
|
127
|
+
## 1.78.0
|
|
12
128
|
|
|
13
|
-
|
|
129
|
+
## 1.77.0
|
|
14
130
|
|
|
15
|
-
|
|
131
|
+
## 1.76.0
|
|
16
132
|
|
|
17
133
|
## 1.75.0
|
|
18
134
|
|
package/README.md
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
# @akinon/pz-checkout-gift-package
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Installation
|
|
4
|
+
|
|
5
|
+
You can use the following command to install the extension with the latest plugins:
|
|
4
6
|
|
|
5
7
|
```bash
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
|
|
9
|
+
npx @akinon/projectzero@latest --plugins
|
|
10
|
+
|
|
8
11
|
```
|
|
9
12
|
|
|
10
13
|
### Props
|
|
@@ -15,3 +18,124 @@ yarn add @akinon/pz-checkout-gift-package
|
|
|
15
18
|
| modalClassName | `string` | This prop is used to customize the overall style of the modal. |
|
|
16
19
|
| modalTitle | `string` | This prop sets the title of the modal. |
|
|
17
20
|
| modalContentClassName | `string` | This prop is used to customize the style of the modal content. |
|
|
21
|
+
| maxNoteLength? | `number` | Sets the maximum number of characters allowed for the gift note. If not provided, a default value is used. |
|
|
22
|
+
| customUIRender | `(props: { hasGiftPack: boolean; hasNote: { state: boolean }; note: string; onAddGiftPack: () => void; onRemoveGiftPack: () => void; onAddNote: () => void; formContent: React.ReactNode; translations: Record<string, string> }) => React.ReactNode` | A custom render function to fully override the default gift pack UI. This gives complete control over the display and interactions. |
|
|
23
|
+
| customGiftNoteFormUIRender | `(props: { register: any; errors: any; note: string; textAreaCount: number; onSubmit: (data: any) => void; removeNote: () => void; handleSubmit: any; translations: Record<string, string> }) => React.ReactNode` | A render function that replaces the default gift note form UI. Useful for providing a customized textarea, button layout, or validation display. |
|
|
24
|
+
|
|
25
|
+
### Default Usage
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
import PluginModule, { Component } from '@akinon/next/components/plugin-module';
|
|
29
|
+
|
|
30
|
+
<PluginModule
|
|
31
|
+
component={Component.CheckoutGiftPack}
|
|
32
|
+
props={{
|
|
33
|
+
className: 'flex flex-col w-full mb-4 border border-solid border-gray-400'
|
|
34
|
+
}}
|
|
35
|
+
/>;
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Customized sample code
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
import PluginModule, { Component } from '@akinon/next/components/plugin-module';
|
|
42
|
+
|
|
43
|
+
<PluginModule
|
|
44
|
+
component={Component.CheckoutGiftPack}
|
|
45
|
+
props={{
|
|
46
|
+
className: 'flex flex-col w-full mb-4 border border-solid border-gray-400',
|
|
47
|
+
translations: {
|
|
48
|
+
addGiftPackText: 'Add Gift Pack',
|
|
49
|
+
giftPackAdded: 'Gift Pack Added',
|
|
50
|
+
removeGiftPackText: 'Remove Gift Pack',
|
|
51
|
+
informationText: 'This order will be gift packaged*',
|
|
52
|
+
updateNote: 'Update Note',
|
|
53
|
+
removeGiftNoteText: 'Remove Gift Note',
|
|
54
|
+
charactersLength: 'characters left',
|
|
55
|
+
placeholderInput:
|
|
56
|
+
'You can leave empty this area. However it will be a gift package without note.',
|
|
57
|
+
accordionTitle: 'Gift Note',
|
|
58
|
+
warningMessage:
|
|
59
|
+
'Make sure that this field is not longer than the character limit.',
|
|
60
|
+
save: 'SAVE',
|
|
61
|
+
close: 'Close'
|
|
62
|
+
},
|
|
63
|
+
customUIRender: ({
|
|
64
|
+
hasGiftPack,
|
|
65
|
+
hasNote,
|
|
66
|
+
note,
|
|
67
|
+
onAddGiftPack,
|
|
68
|
+
onRemoveGiftPack,
|
|
69
|
+
onAddNote,
|
|
70
|
+
formContent,
|
|
71
|
+
translations
|
|
72
|
+
}) => (
|
|
73
|
+
<div className="custom-gift-pack">
|
|
74
|
+
{hasGiftPack ? (
|
|
75
|
+
<div className="gift-pack-added p-4 border border-gray-200">
|
|
76
|
+
<div className="flex justify-between items-center mb-4">
|
|
77
|
+
<span className="font-medium">{translations.giftPackAdded}</span>
|
|
78
|
+
<button
|
|
79
|
+
onClick={onRemoveGiftPack}
|
|
80
|
+
className="text-red-500 hover:text-red-700"
|
|
81
|
+
>
|
|
82
|
+
{translations.removeGiftPackText}
|
|
83
|
+
</button>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<div className="gift-note-info bg-gray-50 p-3 rounded">
|
|
87
|
+
<span className="text-sm text-gray-600">
|
|
88
|
+
{translations.informationText}
|
|
89
|
+
</span>
|
|
90
|
+
{note && <p className="mt-2 text-sm">{note}</p>}
|
|
91
|
+
<button
|
|
92
|
+
onClick={onAddNote}
|
|
93
|
+
className="mt-2 text-blue-500 hover:text-blue-700"
|
|
94
|
+
>
|
|
95
|
+
{translations.updateNote}
|
|
96
|
+
</button>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
{hasNote.state && <div className="mt-4">{formContent}</div>}
|
|
100
|
+
</div>
|
|
101
|
+
) : (
|
|
102
|
+
<button
|
|
103
|
+
onClick={onAddGiftPack}
|
|
104
|
+
className="w-full p-2 text-center border border-gray-200 hover:bg-gray-50"
|
|
105
|
+
>
|
|
106
|
+
{translations.addGiftPackText}
|
|
107
|
+
</button>
|
|
108
|
+
)}
|
|
109
|
+
</div>
|
|
110
|
+
),
|
|
111
|
+
customGiftNoteFormUIRender: ({
|
|
112
|
+
register,
|
|
113
|
+
errors,
|
|
114
|
+
note,
|
|
115
|
+
textAreaCount,
|
|
116
|
+
onSubmit,
|
|
117
|
+
removeNote,
|
|
118
|
+
handleSubmit,
|
|
119
|
+
translations: formTranslations
|
|
120
|
+
}) => (
|
|
121
|
+
<form onSubmit={handleSubmit(onSubmit)}>
|
|
122
|
+
<textarea
|
|
123
|
+
{...register('message')}
|
|
124
|
+
value={note}
|
|
125
|
+
placeholder={formTranslations.placeholderInput}
|
|
126
|
+
/>
|
|
127
|
+
{errors.message && <span>{errors.message.message}</span>}
|
|
128
|
+
<div className="character-count">
|
|
129
|
+
{textAreaCount}/160 {formTranslations.charactersLength}
|
|
130
|
+
</div>
|
|
131
|
+
<div className="buttons">
|
|
132
|
+
<button type="button" onClick={removeNote}>
|
|
133
|
+
{formTranslations.removeGiftNoteText}
|
|
134
|
+
</button>
|
|
135
|
+
<button type="submit">{formTranslations.save}</button>
|
|
136
|
+
</div>
|
|
137
|
+
</form>
|
|
138
|
+
)
|
|
139
|
+
}}
|
|
140
|
+
/>;
|
|
141
|
+
```
|
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akinon/pz-checkout-gift-pack",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.21",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "src/index.tsx",
|
|
6
6
|
"peerDependencies": {
|
|
7
|
-
"react": "^19.0.0",
|
|
8
|
-
"react-dom": "^19.0.0"
|
|
7
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
8
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
9
9
|
},
|
|
10
10
|
"devDependencies": {
|
|
11
|
-
"@types/node": "^
|
|
12
|
-
"@types/react": "^
|
|
13
|
-
"@types/react-dom": "^
|
|
14
|
-
"react": "
|
|
15
|
-
"react-dom": "
|
|
16
|
-
"typescript": "^
|
|
11
|
+
"@types/node": "^18.7.8",
|
|
12
|
+
"@types/react": "^18.0.17",
|
|
13
|
+
"@types/react-dom": "^18.0.6",
|
|
14
|
+
"react": "19.2.5",
|
|
15
|
+
"react-dom": "19.2.5",
|
|
16
|
+
"typescript": "^4.7.4"
|
|
17
17
|
}
|
|
18
18
|
}
|
package/src/index.tsx
CHANGED
|
@@ -1,37 +1,76 @@
|
|
|
1
|
+
import React from 'react';
|
|
1
2
|
import { useAppSelector } from '@akinon/next/redux/hooks';
|
|
2
3
|
import { yupResolver } from '@hookform/resolvers/yup';
|
|
3
4
|
import clsx from 'clsx';
|
|
4
5
|
import { twMerge } from 'tailwind-merge';
|
|
5
6
|
import { Accordion, Button, Icon, Modal } from '@akinon/next/components';
|
|
6
7
|
import { useEffect, useState } from 'react';
|
|
7
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
SubmitHandler,
|
|
10
|
+
useForm,
|
|
11
|
+
UseFormRegister,
|
|
12
|
+
FieldErrors,
|
|
13
|
+
UseFormHandleSubmit
|
|
14
|
+
} from 'react-hook-form';
|
|
8
15
|
import { RootState } from 'redux/store';
|
|
9
16
|
import * as yup from 'yup';
|
|
10
17
|
import { useAddGiftPackMutation, useRemoveGiftPackMutation } from './endpoints';
|
|
11
18
|
|
|
19
|
+
const DEFAULT_NOTE = 'NO-GIFT-MESSAGE';
|
|
20
|
+
|
|
21
|
+
const defaultTranslations = {
|
|
22
|
+
addGiftPackText: 'Add Gift Pack',
|
|
23
|
+
giftPackAdded: 'Gift Pack Added',
|
|
24
|
+
removeGiftPackText: 'Remove Gift Pack',
|
|
25
|
+
informationText: 'This order will be gift packaged*',
|
|
26
|
+
updateNote: 'Update Note',
|
|
27
|
+
removeGiftNoteText: 'Remove Gift Note',
|
|
28
|
+
charactersLength: 'characters left',
|
|
29
|
+
placeholderInput:
|
|
30
|
+
'You can leave empty this area. However it will be a gift package without note.',
|
|
31
|
+
accordionTitle: 'Gift Note',
|
|
32
|
+
warningMessage:
|
|
33
|
+
'Make sure that this field is not longer than the character limit.',
|
|
34
|
+
save: 'SAVE',
|
|
35
|
+
close: 'Close'
|
|
36
|
+
};
|
|
37
|
+
|
|
12
38
|
interface GiftPackForm {
|
|
13
39
|
message: string;
|
|
14
40
|
}
|
|
15
41
|
|
|
42
|
+
interface CustomUIRenderParams {
|
|
43
|
+
hasGiftPack: boolean;
|
|
44
|
+
hasNote: { title: string; state: boolean };
|
|
45
|
+
note: string;
|
|
46
|
+
textAreaCount: number;
|
|
47
|
+
onAddGiftPack: () => void;
|
|
48
|
+
onRemoveGiftPack: () => void;
|
|
49
|
+
onAddNote: () => void;
|
|
50
|
+
onRemoveNote: () => void;
|
|
51
|
+
formContent: React.ReactNode;
|
|
52
|
+
translations: typeof defaultTranslations;
|
|
53
|
+
}
|
|
54
|
+
|
|
16
55
|
interface CheckoutGiftPackProps {
|
|
17
56
|
className?: string;
|
|
18
57
|
useModal?: boolean;
|
|
19
58
|
modalClassName?: string;
|
|
20
59
|
modalTitle?: string;
|
|
60
|
+
maxNoteLength?: number;
|
|
21
61
|
modalContentClassName?: string;
|
|
22
|
-
translations
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
};
|
|
62
|
+
translations?: Partial<typeof defaultTranslations>;
|
|
63
|
+
customUIRender?: (params: CustomUIRenderParams) => React.ReactNode;
|
|
64
|
+
customGiftNoteFormUIRender?: (params: {
|
|
65
|
+
register: UseFormRegister<GiftPackForm>;
|
|
66
|
+
errors: FieldErrors<GiftPackForm>;
|
|
67
|
+
note: string;
|
|
68
|
+
textAreaCount: number;
|
|
69
|
+
onSubmit: () => void;
|
|
70
|
+
removeNote: () => void;
|
|
71
|
+
handleSubmit: UseFormHandleSubmit<GiftPackForm>;
|
|
72
|
+
translations: typeof defaultTranslations;
|
|
73
|
+
}) => React.ReactNode;
|
|
35
74
|
}
|
|
36
75
|
|
|
37
76
|
export const CheckoutGiftPack = ({
|
|
@@ -40,49 +79,32 @@ export const CheckoutGiftPack = ({
|
|
|
40
79
|
modalClassName,
|
|
41
80
|
modalContentClassName,
|
|
42
81
|
modalTitle = 'Gift Note',
|
|
43
|
-
|
|
82
|
+
maxNoteLength = 160,
|
|
83
|
+
translations,
|
|
84
|
+
customUIRender,
|
|
85
|
+
customGiftNoteFormUIRender
|
|
44
86
|
}: CheckoutGiftPackProps) => {
|
|
45
87
|
const [isNoteFormOpen, setIsNoteFormOpen] = useState(false);
|
|
88
|
+
const [hasNote, setHasNote] = useState({
|
|
89
|
+
title: translations?.updateNote || defaultTranslations.updateNote,
|
|
90
|
+
state: false
|
|
91
|
+
});
|
|
92
|
+
const [textAreaCount, setTextAreaCount] = useState(0);
|
|
93
|
+
const [note, setNote] = useState('');
|
|
46
94
|
|
|
47
95
|
const { preOrder, hasGiftBox } = useAppSelector(
|
|
48
96
|
(state: RootState) => state.checkout
|
|
49
97
|
);
|
|
50
98
|
|
|
51
|
-
const
|
|
52
|
-
addGiftPackText: 'Add Gift Pack',
|
|
53
|
-
giftPackAdded: 'Gift Pack Added',
|
|
54
|
-
removeGiftPackText: 'Remove Gift Pack',
|
|
55
|
-
informationText: 'This order will be gift packaged*',
|
|
56
|
-
updateNote: 'Update Note',
|
|
57
|
-
removeGiftNoteText: 'Remove Gift Note',
|
|
58
|
-
charactersLength: 'characters left',
|
|
59
|
-
placeholderInput:
|
|
60
|
-
'You can leave empty this area. However it will be a gift package without note.',
|
|
61
|
-
accordionTitle: 'Gift Note',
|
|
62
|
-
warningMessage: 'Ensure this field has no more than 160 characters.',
|
|
63
|
-
save: 'SAVE'
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const _translations = {
|
|
67
|
-
...defaultTranslations,
|
|
68
|
-
...translations
|
|
69
|
-
};
|
|
99
|
+
const _translations = { ...defaultTranslations, ...translations };
|
|
70
100
|
|
|
71
101
|
const giftPackFormSchema = () =>
|
|
72
102
|
yup.object().shape({
|
|
73
|
-
message: yup.string().max(
|
|
103
|
+
message: yup.string().max(maxNoteLength, _translations.warningMessage)
|
|
74
104
|
});
|
|
75
105
|
|
|
76
|
-
if (!hasGiftBox) {
|
|
77
|
-
console.warn(
|
|
78
|
-
'Gift box for checkout is disabled. Please enable it from Omnitron.'
|
|
79
|
-
);
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
106
|
const [addGiftPack] = useAddGiftPackMutation();
|
|
84
107
|
const [removeGiftPack] = useRemoveGiftPackMutation();
|
|
85
|
-
const DEFAULT_NOTE = 'NO-GIFT-MESSAGE';
|
|
86
108
|
|
|
87
109
|
const {
|
|
88
110
|
register,
|
|
@@ -92,89 +114,147 @@ export const CheckoutGiftPack = ({
|
|
|
92
114
|
setValue,
|
|
93
115
|
formState: { errors }
|
|
94
116
|
} = useForm<GiftPackForm>({
|
|
95
|
-
resolver: yupResolver(giftPackFormSchema())
|
|
117
|
+
resolver: yupResolver(giftPackFormSchema()) as any
|
|
96
118
|
});
|
|
97
119
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
if (preOrder?.gift_box?.note !== DEFAULT_NOTE) {
|
|
122
|
+
setValue('message', preOrder?.gift_box?.note);
|
|
123
|
+
setNote(preOrder?.gift_box?.note);
|
|
124
|
+
setTextAreaCount(preOrder?.gift_box?.note?.length || 0);
|
|
125
|
+
}
|
|
126
|
+
}, [preOrder?.gift_box]);
|
|
127
|
+
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
const subscription = watch(({ message }) => {
|
|
130
|
+
setNote(message);
|
|
131
|
+
setTextAreaCount(message?.length || 0);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
return () => subscription.unsubscribe();
|
|
135
|
+
}, [watch]);
|
|
136
|
+
|
|
137
|
+
if (!hasGiftBox) {
|
|
138
|
+
console.warn(
|
|
139
|
+
'Gift box for checkout is disabled. Please enable it from Omnitron.'
|
|
140
|
+
);
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
101
143
|
|
|
102
144
|
const onSubmit: SubmitHandler<GiftPackForm> = async (data) => {
|
|
103
145
|
await addGiftPack({
|
|
104
|
-
note:
|
|
146
|
+
note: textAreaCount > 0 ? data.message : DEFAULT_NOTE
|
|
105
147
|
}).unwrap();
|
|
148
|
+
|
|
106
149
|
setIsNoteFormOpen(false);
|
|
150
|
+
setHasNote((prevstate) => ({ ...prevstate, state: false }));
|
|
107
151
|
};
|
|
108
152
|
|
|
109
153
|
const removeGiftNote = async () => {
|
|
110
154
|
await addGiftPack({ note: DEFAULT_NOTE }).unwrap();
|
|
111
155
|
resetField('message');
|
|
156
|
+
setNote('');
|
|
157
|
+
setTextAreaCount(0);
|
|
112
158
|
};
|
|
113
159
|
|
|
114
|
-
const formContent = (
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
160
|
+
const formContent = customGiftNoteFormUIRender ? (
|
|
161
|
+
customGiftNoteFormUIRender({
|
|
162
|
+
register,
|
|
163
|
+
errors,
|
|
164
|
+
note,
|
|
165
|
+
textAreaCount,
|
|
166
|
+
onSubmit: () => handleSubmit(onSubmit)(),
|
|
167
|
+
removeNote: removeGiftNote,
|
|
168
|
+
handleSubmit,
|
|
169
|
+
translations: _translations
|
|
170
|
+
})
|
|
171
|
+
) : (
|
|
172
|
+
<form onSubmit={handleSubmit(onSubmit)}>
|
|
173
|
+
{!useModal && (
|
|
174
|
+
<div className="flex justify-between mb-3">
|
|
175
|
+
<span className="text-[0.75rem] font-bold">
|
|
176
|
+
{_translations.accordionTitle}
|
|
177
|
+
</span>
|
|
178
|
+
<Button
|
|
179
|
+
appearance="ghost"
|
|
180
|
+
className="text-[#000000] cursor-pointer border-0 px-0 py-0 text-[0.75rem] select-none underline h-auto hover:bg-transparent hover:text-[#000000]"
|
|
181
|
+
onClick={(e) => {
|
|
182
|
+
e.preventDefault();
|
|
183
|
+
setHasNote((prevstate) => ({ ...prevstate, state: false }));
|
|
184
|
+
}}
|
|
185
|
+
>
|
|
186
|
+
{_translations.close}
|
|
187
|
+
</Button>
|
|
188
|
+
</div>
|
|
189
|
+
)}
|
|
121
190
|
<textarea
|
|
122
191
|
className={clsx(
|
|
123
192
|
'w-full border border-solid p-4 placeholder:text-[0.75rem] placeholder:text-[#9c9d9d] outline-none text-[0.75rem]',
|
|
124
|
-
|
|
193
|
+
textAreaCount > maxNoteLength
|
|
194
|
+
? 'border-[#e85150]'
|
|
195
|
+
: 'border-[#7b9d75]'
|
|
125
196
|
)}
|
|
126
197
|
rows={4}
|
|
198
|
+
value={note !== DEFAULT_NOTE ? note : ' '}
|
|
127
199
|
placeholder={_translations.placeholderInput}
|
|
128
200
|
{...register('message')}
|
|
201
|
+
data-testid="gift-note-input"
|
|
129
202
|
/>
|
|
130
203
|
{errors.message && (
|
|
131
|
-
<span
|
|
132
|
-
|
|
204
|
+
<span
|
|
205
|
+
className="text-sm text-[#d72a04] text-[0.875rem]"
|
|
206
|
+
data-testid="error-message"
|
|
207
|
+
>
|
|
208
|
+
{String(errors.message.message)}
|
|
133
209
|
</span>
|
|
134
210
|
)}
|
|
135
|
-
<div className="
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
211
|
+
<div className="flex justify-between items-center mt-2">
|
|
212
|
+
<span
|
|
213
|
+
className={clsx(
|
|
214
|
+
'text-[0.75rem]',
|
|
215
|
+
textAreaCount > maxNoteLength ? 'text-[#e85150]' : 'text-[#82a27c]'
|
|
216
|
+
)}
|
|
217
|
+
data-testid="characters-length"
|
|
218
|
+
>
|
|
219
|
+
{textAreaCount}/{maxNoteLength} {_translations.charactersLength}
|
|
220
|
+
</span>
|
|
221
|
+
<div className="flex items-center gap-3">
|
|
222
|
+
{preOrder?.gift_box?.note !== DEFAULT_NOTE && (
|
|
223
|
+
<Button
|
|
224
|
+
appearance="ghost"
|
|
225
|
+
className="text-[0.75rem] underline cursor-pointer border-0 px-0 py-0 h-auto hover:bg-transparent hover:text-[#e95151]"
|
|
226
|
+
onClick={removeGiftNote}
|
|
227
|
+
data-testid="remove-gift-note-button"
|
|
228
|
+
>
|
|
229
|
+
{_translations.removeGiftNoteText}
|
|
230
|
+
</Button>
|
|
231
|
+
)}
|
|
140
232
|
<Button
|
|
141
|
-
|
|
142
|
-
className="
|
|
143
|
-
|
|
233
|
+
type="submit"
|
|
234
|
+
className="w-[7rem] h-[1.75rem] font-[0.75rem] uppercase"
|
|
235
|
+
data-testid="save-gift-pack-button"
|
|
144
236
|
>
|
|
145
|
-
{_translations.
|
|
237
|
+
{_translations.save}
|
|
146
238
|
</Button>
|
|
147
|
-
|
|
148
|
-
<Button
|
|
149
|
-
type="submit"
|
|
150
|
-
className="w-[7rem] h-[1.75rem] font-[0.75rem] uppercase"
|
|
151
|
-
appearance="outlined"
|
|
152
|
-
>
|
|
153
|
-
{_translations.save}
|
|
154
|
-
</Button>
|
|
239
|
+
</div>
|
|
155
240
|
</div>
|
|
156
241
|
</form>
|
|
157
242
|
);
|
|
158
243
|
|
|
159
|
-
|
|
160
|
-
if (giftBox?.note !== DEFAULT_NOTE) {
|
|
161
|
-
setValue('message', giftBox?.note);
|
|
162
|
-
}
|
|
163
|
-
}, [giftBox]);
|
|
164
|
-
|
|
165
|
-
return (
|
|
244
|
+
const defaultRender = () => (
|
|
166
245
|
<div className={className}>
|
|
167
246
|
<div className="flex justify-between items-center py-2 px-5">
|
|
168
247
|
<div className="flex gap-2 items-center">
|
|
169
248
|
<Icon name="giftbox" size={16} className="fill-[#000000]" />
|
|
170
249
|
<span className="text-[1rem] font-light">
|
|
171
|
-
{
|
|
250
|
+
{preOrder?.gift_box ? (
|
|
172
251
|
_translations.giftPackAdded
|
|
173
252
|
) : (
|
|
174
253
|
<Button
|
|
175
254
|
appearance="ghost"
|
|
176
255
|
className="cursor-pointer border-0 px-0 py-0 text-[1rem] font-light h-auto hover:bg-transparent hover:text-[#000000]"
|
|
177
256
|
onClick={() => addGiftPack({ note: DEFAULT_NOTE })}
|
|
257
|
+
data-testid="add-gift-pack-button"
|
|
178
258
|
>
|
|
179
259
|
{_translations.addGiftPackText}
|
|
180
260
|
</Button>
|
|
@@ -186,13 +266,15 @@ export const CheckoutGiftPack = ({
|
|
|
186
266
|
className={clsx(
|
|
187
267
|
'text-[0.75rem] underline cursor-pointer border-0 px-0 py-0 h-auto hover:bg-transparent hover:text-[#e95151]',
|
|
188
268
|
{
|
|
189
|
-
hidden: !
|
|
269
|
+
hidden: !preOrder?.gift_box
|
|
190
270
|
}
|
|
191
271
|
)}
|
|
192
272
|
onClick={async () => {
|
|
193
273
|
await removeGiftPack().unwrap();
|
|
194
274
|
setIsNoteFormOpen(false);
|
|
275
|
+
setHasNote((prevstate) => ({ ...prevstate, state: false }));
|
|
195
276
|
}}
|
|
277
|
+
data-testid="remove-gift-pack-button"
|
|
196
278
|
>
|
|
197
279
|
{_translations.removeGiftPackText}
|
|
198
280
|
</Button>
|
|
@@ -201,20 +283,30 @@ export const CheckoutGiftPack = ({
|
|
|
201
283
|
className={clsx(
|
|
202
284
|
'flex flex-col gap-2 bg-[#f7f7f7] text-[#58585a] text-[0.875rem] py-2 px-5',
|
|
203
285
|
{
|
|
204
|
-
hidden: !
|
|
286
|
+
hidden: !preOrder?.gift_box
|
|
205
287
|
}
|
|
206
288
|
)}
|
|
207
289
|
>
|
|
208
290
|
<div className="flex justify-between items-center">
|
|
209
|
-
<span>
|
|
291
|
+
<span data-testid="information-text">
|
|
292
|
+
{_translations.informationText}
|
|
293
|
+
</span>
|
|
210
294
|
<Icon name="giftbox" size={14} className="fill-[#58585a]" />
|
|
211
295
|
</div>
|
|
212
296
|
<div className="flex justify-between items-center gap-8">
|
|
213
|
-
<span
|
|
297
|
+
<span data-testid="saved-gift-note">
|
|
298
|
+
{preOrder?.gift_box?.note !== DEFAULT_NOTE
|
|
299
|
+
? preOrder?.gift_box?.note
|
|
300
|
+
: ''}
|
|
301
|
+
</span>
|
|
214
302
|
<Button
|
|
215
303
|
appearance="ghost"
|
|
216
304
|
className="underline cursor-pointer flex-shrink-0 border-0 px-0 py-0 h-auto hover:bg-transparent hover:text-[#000000]"
|
|
217
|
-
onClick={() =>
|
|
305
|
+
onClick={() => {
|
|
306
|
+
setIsNoteFormOpen(true);
|
|
307
|
+
setHasNote((prevstate) => ({ ...prevstate, state: true }));
|
|
308
|
+
}}
|
|
309
|
+
data-testid="update-gift-pack-button"
|
|
218
310
|
>
|
|
219
311
|
{_translations.updateNote}
|
|
220
312
|
</Button>
|
|
@@ -229,15 +321,17 @@ export const CheckoutGiftPack = ({
|
|
|
229
321
|
'w-full sm:w-[28rem] max-h-[90vh] overflow-y-auto',
|
|
230
322
|
modalClassName
|
|
231
323
|
)}
|
|
232
|
-
open={
|
|
233
|
-
setOpen={
|
|
324
|
+
open={hasNote.state}
|
|
325
|
+
setOpen={(state) =>
|
|
326
|
+
setHasNote((prevstate) => ({ ...prevstate, state }))
|
|
327
|
+
}
|
|
234
328
|
>
|
|
235
329
|
<div className={twMerge('px-6 py-4', modalContentClassName)}>
|
|
236
330
|
{formContent}
|
|
237
331
|
</div>
|
|
238
332
|
</Modal>
|
|
239
333
|
) : (
|
|
240
|
-
<div className={clsx('py-2 px-5', { hidden: !
|
|
334
|
+
<div className={clsx('py-2 px-5', { hidden: !hasNote.state })}>
|
|
241
335
|
<Accordion
|
|
242
336
|
title={_translations.accordionTitle}
|
|
243
337
|
titleClassName="text-[0.75rem]"
|
|
@@ -249,4 +343,22 @@ export const CheckoutGiftPack = ({
|
|
|
249
343
|
)}
|
|
250
344
|
</div>
|
|
251
345
|
);
|
|
346
|
+
|
|
347
|
+
return customUIRender
|
|
348
|
+
? customUIRender({
|
|
349
|
+
hasGiftPack: !!preOrder?.gift_box,
|
|
350
|
+
hasNote,
|
|
351
|
+
note,
|
|
352
|
+
textAreaCount,
|
|
353
|
+
onAddGiftPack: () => addGiftPack({ note: DEFAULT_NOTE }),
|
|
354
|
+
onRemoveGiftPack: () => removeGiftPack().unwrap(),
|
|
355
|
+
onAddNote: () => {
|
|
356
|
+
setIsNoteFormOpen(true);
|
|
357
|
+
setHasNote((prevstate) => ({ ...prevstate, state: true }));
|
|
358
|
+
},
|
|
359
|
+
onRemoveNote: removeGiftNote,
|
|
360
|
+
formContent,
|
|
361
|
+
translations: _translations
|
|
362
|
+
})
|
|
363
|
+
: defaultRender();
|
|
252
364
|
};
|