@akinon/pz-checkout-gift-pack 2.0.0-beta.9 → 2.0.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/CHANGELOG.md +122 -17
- package/README.md +121 -0
- package/package.json +9 -9
- package/src/index.tsx +192 -93
package/CHANGELOG.md
CHANGED
|
@@ -1,45 +1,150 @@
|
|
|
1
1
|
# @akinon/pz-checkout-gift-pack
|
|
2
2
|
|
|
3
|
-
## 2.0.
|
|
3
|
+
## 2.0.1
|
|
4
|
+
|
|
5
|
+
## 2.0.0
|
|
6
|
+
|
|
7
|
+
## 2.0.0-beta.27
|
|
8
|
+
|
|
9
|
+
## 2.0.0-beta.26
|
|
10
|
+
|
|
11
|
+
## 2.0.0-beta.25
|
|
12
|
+
|
|
13
|
+
## 2.0.0-beta.24
|
|
14
|
+
|
|
15
|
+
## 2.0.0-beta.23
|
|
16
|
+
|
|
17
|
+
## 2.0.0-beta.22
|
|
18
|
+
|
|
19
|
+
## 2.0.0-beta.21
|
|
20
|
+
|
|
21
|
+
## 2.0.0-beta.20
|
|
22
|
+
|
|
23
|
+
## 1.126.0
|
|
24
|
+
|
|
25
|
+
## 1.125.2
|
|
26
|
+
|
|
27
|
+
## 1.125.1
|
|
28
|
+
|
|
29
|
+
## 1.125.0
|
|
30
|
+
|
|
31
|
+
## 1.124.0
|
|
32
|
+
|
|
33
|
+
## 1.123.0
|
|
34
|
+
|
|
35
|
+
## 1.122.0
|
|
36
|
+
|
|
37
|
+
## 1.121.0
|
|
38
|
+
|
|
39
|
+
## 1.120.0
|
|
40
|
+
|
|
41
|
+
## 1.119.0
|
|
42
|
+
|
|
43
|
+
## 1.118.0
|
|
44
|
+
|
|
45
|
+
## 1.117.0
|
|
46
|
+
|
|
47
|
+
## 1.116.0
|
|
48
|
+
|
|
49
|
+
## 1.115.0
|
|
50
|
+
|
|
51
|
+
## 1.114.0
|
|
52
|
+
|
|
53
|
+
## 1.113.0
|
|
54
|
+
|
|
55
|
+
## 1.112.0
|
|
56
|
+
|
|
57
|
+
## 1.111.0
|
|
58
|
+
|
|
59
|
+
## 1.110.0
|
|
60
|
+
|
|
61
|
+
## 1.109.0
|
|
62
|
+
|
|
63
|
+
## 1.108.0
|
|
64
|
+
|
|
65
|
+
## 1.107.0
|
|
66
|
+
|
|
67
|
+
## 1.106.0
|
|
4
68
|
|
|
5
69
|
### Minor Changes
|
|
6
70
|
|
|
7
|
-
-
|
|
71
|
+
- 8bc82f0: ZERO-3405: Update Readme
|
|
72
|
+
|
|
73
|
+
## 1.105.0
|
|
74
|
+
|
|
75
|
+
## 1.104.0
|
|
8
76
|
|
|
9
|
-
##
|
|
77
|
+
## 1.103.0
|
|
10
78
|
|
|
11
|
-
##
|
|
79
|
+
## 1.102.0
|
|
12
80
|
|
|
13
|
-
##
|
|
81
|
+
## 1.101.0
|
|
82
|
+
|
|
83
|
+
## 1.100.0
|
|
84
|
+
|
|
85
|
+
## 1.99.0
|
|
14
86
|
|
|
15
87
|
### Minor Changes
|
|
16
88
|
|
|
17
|
-
-
|
|
89
|
+
- d58538b: ZERO-3638: Enhance RC pipeline: add fetch, merge, and pre-release setup with conditional commit
|
|
90
|
+
|
|
91
|
+
## 1.98.0
|
|
92
|
+
|
|
93
|
+
## 1.97.0
|
|
94
|
+
|
|
95
|
+
## 1.96.0
|
|
96
|
+
|
|
97
|
+
## 1.95.0
|
|
98
|
+
|
|
99
|
+
## 1.94.0
|
|
18
100
|
|
|
19
|
-
##
|
|
101
|
+
## 1.93.0
|
|
20
102
|
|
|
21
|
-
##
|
|
103
|
+
## 1.92.0
|
|
22
104
|
|
|
23
|
-
##
|
|
105
|
+
## 1.91.0
|
|
24
106
|
|
|
25
|
-
##
|
|
107
|
+
## 1.90.0
|
|
26
108
|
|
|
27
109
|
### Minor Changes
|
|
28
110
|
|
|
29
|
-
-
|
|
30
|
-
- 1eeb3d8: ZERO-3116: Add not found page
|
|
111
|
+
- ec9ff89: ZERO-3368: Add customization to package
|
|
31
112
|
|
|
32
|
-
##
|
|
113
|
+
## 1.89.0
|
|
114
|
+
|
|
115
|
+
## 1.88.0
|
|
33
116
|
|
|
34
117
|
### Minor Changes
|
|
35
118
|
|
|
36
|
-
- ZERO-
|
|
119
|
+
- ce64181: ZERO-3333: Add data-testid for checkout gift pack
|
|
120
|
+
|
|
121
|
+
## 1.87.0
|
|
122
|
+
|
|
123
|
+
## 1.86.0
|
|
124
|
+
|
|
125
|
+
## 1.85.0
|
|
126
|
+
|
|
127
|
+
## 1.84.0
|
|
128
|
+
|
|
129
|
+
### Minor Changes
|
|
130
|
+
|
|
131
|
+
- 624a4eb: ZERO-3276: Update installation instructions across multiple README files to standardize format and improve clarity
|
|
132
|
+
|
|
133
|
+
## 1.83.0
|
|
134
|
+
|
|
135
|
+
## 1.82.0
|
|
136
|
+
|
|
137
|
+
## 1.81.0
|
|
138
|
+
|
|
139
|
+
## 1.80.0
|
|
140
|
+
|
|
141
|
+
## 1.79.0
|
|
37
142
|
|
|
38
|
-
##
|
|
143
|
+
## 1.78.0
|
|
39
144
|
|
|
40
|
-
|
|
145
|
+
## 1.77.0
|
|
41
146
|
|
|
42
|
-
|
|
147
|
+
## 1.76.0
|
|
43
148
|
|
|
44
149
|
## 1.75.0
|
|
45
150
|
|
package/README.md
CHANGED
|
@@ -18,3 +18,124 @@ npx @akinon/projectzero@latest --plugins
|
|
|
18
18
|
| modalClassName | `string` | This prop is used to customize the overall style of the modal. |
|
|
19
19
|
| modalTitle | `string` | This prop sets the title of the modal. |
|
|
20
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.
|
|
3
|
+
"version": "2.0.1",
|
|
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,38 +114,88 @@ 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
|
-
'w-full border border-solid p-4 placeholder:text-[0.75rem] placeholder:text-[#9c9d9d] outline-
|
|
124
|
-
|
|
192
|
+
'w-full border border-solid p-4 placeholder:text-[0.75rem] placeholder:text-[#9c9d9d] outline-none text-[0.75rem]',
|
|
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')}
|
|
129
201
|
data-testid="gift-note-input"
|
|
@@ -133,48 +205,49 @@ export const CheckoutGiftPack = ({
|
|
|
133
205
|
className="text-sm text-[#d72a04] text-[0.875rem]"
|
|
134
206
|
data-testid="error-message"
|
|
135
207
|
>
|
|
136
|
-
{errors.message.message}
|
|
208
|
+
{String(errors.message.message)}
|
|
137
209
|
</span>
|
|
138
210
|
)}
|
|
139
|
-
<div className="
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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
|
+
)}
|
|
144
232
|
<Button
|
|
145
|
-
|
|
146
|
-
className="
|
|
147
|
-
|
|
148
|
-
data-testid="remove-gift-note-button"
|
|
233
|
+
type="submit"
|
|
234
|
+
className="w-[7rem] h-[1.75rem] font-[0.75rem] uppercase"
|
|
235
|
+
data-testid="save-gift-pack-button"
|
|
149
236
|
>
|
|
150
|
-
{_translations.
|
|
237
|
+
{_translations.save}
|
|
151
238
|
</Button>
|
|
152
|
-
|
|
153
|
-
<Button
|
|
154
|
-
type="submit"
|
|
155
|
-
className="w-[7rem] h-[1.75rem] font-[0.75rem] uppercase"
|
|
156
|
-
appearance="outlined"
|
|
157
|
-
data-testid="save-gift-pack-button"
|
|
158
|
-
>
|
|
159
|
-
{_translations.save}
|
|
160
|
-
</Button>
|
|
239
|
+
</div>
|
|
161
240
|
</div>
|
|
162
241
|
</form>
|
|
163
242
|
);
|
|
164
243
|
|
|
165
|
-
|
|
166
|
-
if (giftBox?.note !== DEFAULT_NOTE) {
|
|
167
|
-
setValue('message', giftBox?.note);
|
|
168
|
-
}
|
|
169
|
-
}, [giftBox]);
|
|
170
|
-
|
|
171
|
-
return (
|
|
244
|
+
const defaultRender = () => (
|
|
172
245
|
<div className={className}>
|
|
173
246
|
<div className="flex justify-between items-center py-2 px-5">
|
|
174
247
|
<div className="flex gap-2 items-center">
|
|
175
248
|
<Icon name="giftbox" size={16} className="fill-[#000000]" />
|
|
176
249
|
<span className="text-[1rem] font-light">
|
|
177
|
-
{
|
|
250
|
+
{preOrder?.gift_box ? (
|
|
178
251
|
_translations.giftPackAdded
|
|
179
252
|
) : (
|
|
180
253
|
<Button
|
|
@@ -193,12 +266,13 @@ export const CheckoutGiftPack = ({
|
|
|
193
266
|
className={clsx(
|
|
194
267
|
'text-[0.75rem] underline cursor-pointer border-0 px-0 py-0 h-auto hover:bg-transparent hover:text-[#e95151]',
|
|
195
268
|
{
|
|
196
|
-
hidden: !
|
|
269
|
+
hidden: !preOrder?.gift_box
|
|
197
270
|
}
|
|
198
271
|
)}
|
|
199
272
|
onClick={async () => {
|
|
200
273
|
await removeGiftPack().unwrap();
|
|
201
274
|
setIsNoteFormOpen(false);
|
|
275
|
+
setHasNote((prevstate) => ({ ...prevstate, state: false }));
|
|
202
276
|
}}
|
|
203
277
|
data-testid="remove-gift-pack-button"
|
|
204
278
|
>
|
|
@@ -209,7 +283,7 @@ export const CheckoutGiftPack = ({
|
|
|
209
283
|
className={clsx(
|
|
210
284
|
'flex flex-col gap-2 bg-[#f7f7f7] text-[#58585a] text-[0.875rem] py-2 px-5',
|
|
211
285
|
{
|
|
212
|
-
hidden: !
|
|
286
|
+
hidden: !preOrder?.gift_box
|
|
213
287
|
}
|
|
214
288
|
)}
|
|
215
289
|
>
|
|
@@ -221,12 +295,17 @@ export const CheckoutGiftPack = ({
|
|
|
221
295
|
</div>
|
|
222
296
|
<div className="flex justify-between items-center gap-8">
|
|
223
297
|
<span data-testid="saved-gift-note">
|
|
224
|
-
{
|
|
298
|
+
{preOrder?.gift_box?.note !== DEFAULT_NOTE
|
|
299
|
+
? preOrder?.gift_box?.note
|
|
300
|
+
: ''}
|
|
225
301
|
</span>
|
|
226
302
|
<Button
|
|
227
303
|
appearance="ghost"
|
|
228
|
-
className="underline cursor-pointer shrink-0 border-0 px-0 py-0 h-auto hover:bg-transparent hover:text-[#000000]"
|
|
229
|
-
onClick={() =>
|
|
304
|
+
className="underline cursor-pointer flex-shrink-0 border-0 px-0 py-0 h-auto hover:bg-transparent hover:text-[#000000]"
|
|
305
|
+
onClick={() => {
|
|
306
|
+
setIsNoteFormOpen(true);
|
|
307
|
+
setHasNote((prevstate) => ({ ...prevstate, state: true }));
|
|
308
|
+
}}
|
|
230
309
|
data-testid="update-gift-pack-button"
|
|
231
310
|
>
|
|
232
311
|
{_translations.updateNote}
|
|
@@ -242,15 +321,17 @@ export const CheckoutGiftPack = ({
|
|
|
242
321
|
'w-full sm:w-[28rem] max-h-[90vh] overflow-y-auto',
|
|
243
322
|
modalClassName
|
|
244
323
|
)}
|
|
245
|
-
open={
|
|
246
|
-
setOpen={
|
|
324
|
+
open={hasNote.state}
|
|
325
|
+
setOpen={(state) =>
|
|
326
|
+
setHasNote((prevstate) => ({ ...prevstate, state }))
|
|
327
|
+
}
|
|
247
328
|
>
|
|
248
329
|
<div className={twMerge('px-6 py-4', modalContentClassName)}>
|
|
249
330
|
{formContent}
|
|
250
331
|
</div>
|
|
251
332
|
</Modal>
|
|
252
333
|
) : (
|
|
253
|
-
<div className={clsx('py-2 px-5', { hidden: !
|
|
334
|
+
<div className={clsx('py-2 px-5', { hidden: !hasNote.state })}>
|
|
254
335
|
<Accordion
|
|
255
336
|
title={_translations.accordionTitle}
|
|
256
337
|
titleClassName="text-[0.75rem]"
|
|
@@ -262,4 +343,22 @@ export const CheckoutGiftPack = ({
|
|
|
262
343
|
)}
|
|
263
344
|
</div>
|
|
264
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();
|
|
265
364
|
};
|