@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 CHANGED
@@ -1,45 +1,150 @@
1
1
  # @akinon/pz-checkout-gift-pack
2
2
 
3
- ## 2.0.0-beta.9
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
- - 0fe7711: ZERO-3387: Upgrade nextjs, eslint-config-next
71
+ - 8bc82f0: ZERO-3405: Update Readme
72
+
73
+ ## 1.105.0
74
+
75
+ ## 1.104.0
8
76
 
9
- ## 2.0.0-beta.8
77
+ ## 1.103.0
10
78
 
11
- ## 2.0.0-beta.7
79
+ ## 1.102.0
12
80
 
13
- ## 2.0.0-beta.6
81
+ ## 1.101.0
82
+
83
+ ## 1.100.0
84
+
85
+ ## 1.99.0
14
86
 
15
87
  ### Minor Changes
16
88
 
17
- - 8f05f9b: ZERO-3250: Beta branch synchronized with Main branch
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
- ## 2.0.0-beta.5
101
+ ## 1.93.0
20
102
 
21
- ## 2.0.0-beta.4
103
+ ## 1.92.0
22
104
 
23
- ## 2.0.0-beta.3
105
+ ## 1.91.0
24
106
 
25
- ## 2.0.0-beta.2
107
+ ## 1.90.0
26
108
 
27
109
  ### Minor Changes
28
110
 
29
- - a006015: ZERO-3116: Add not-found page and update default middleware.
30
- - 1eeb3d8: ZERO-3116: Add not found page
111
+ - ec9ff89: ZERO-3368: Add customization to package
31
112
 
32
- ## 2.0.0-beta.1
113
+ ## 1.89.0
114
+
115
+ ## 1.88.0
33
116
 
34
117
  ### Minor Changes
35
118
 
36
- - ZERO-3091: Upgrade Next.js to v15 and React to v19
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
- ## 2.0.0-beta.0
143
+ ## 1.78.0
39
144
 
40
- ### Major Changes
145
+ ## 1.77.0
41
146
 
42
- - be6c09d: ZERO-3114: Create beta version.
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.0-beta.9",
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": "^22.10.2",
12
- "@types/react": "^19.0.2",
13
- "@types/react-dom": "^19.0.2",
14
- "react": "^19.0.0",
15
- "react-dom": "^19.0.0",
16
- "typescript": "^5.7.2"
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 { SubmitHandler, useForm } from 'react-hook-form';
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
- addGiftPackText: string;
24
- giftPackAdded: string;
25
- removeGiftPackText: string;
26
- informationText: string;
27
- updateNote: string;
28
- removeGiftNoteText: string;
29
- charactersLength: string;
30
- placeholderInput: string;
31
- accordionTitle: string;
32
- warningMessage: string;
33
- save: string;
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
- translations
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 defaultTranslations = {
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(160, _translations.warningMessage)
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
- const subscribeNote = watch('message');
99
- const noteLength = subscribeNote?.length ?? 0;
100
- const giftBox = preOrder?.gift_box;
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: noteLength > 0 ? data.message : DEFAULT_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
- <form
116
- className={clsx({
117
- hidden: !isNoteFormOpen
118
- })}
119
- onSubmit={handleSubmit(onSubmit)}
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-hidden text-[0.75rem]',
124
- noteLength > 160 ? 'border-[#e85150]' : 'border-[#7b9d75]'
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="text-[0.75rem]" data-testid="characters-length">
140
- {noteLength} / 160 {_translations.charactersLength}
141
- </div>
142
- <div className="flex justify-end items-end gap-2">
143
- {giftBox?.note !== DEFAULT_NOTE && (
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
- appearance="ghost"
146
- className="text-[0.75rem] underline cursor-pointer border-0 px-0 py-0 h-auto hover:bg-transparent hover:text-[#e95151]"
147
- onClick={removeGiftNote}
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.removeGiftNoteText}
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
- useEffect(() => {
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
- {giftBox ? (
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: !giftBox
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: !giftBox
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
- {giftBox?.note !== DEFAULT_NOTE ? giftBox?.note : ''}
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={() => setIsNoteFormOpen(true)}
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={isNoteFormOpen}
246
- setOpen={setIsNoteFormOpen}
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: !isNoteFormOpen })}>
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
  };