PluginProbe
Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO / 1.4.10
Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO v1.4.10
1.4.19 1.4.18 1.4.17 1.4.16 1.4.15 1.4.14 1.4.13 1.4.12 1.4.11 1.4.10 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.54 1.3.53 1.3.52 1.3.51 1.3.50 All 182 releases
disco / backend / views / components / Main / features / discount / discountSlice.js

discountSlice.js in Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO 1.4.10, at backend/views/components/Main/features/discount/discountSlice.js

648 lines 16.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { createSlice } from '@reduxjs/toolkit';
2 import { v4 as uuidv4 } from 'uuid';
3 import { DEFAULT_COUNTDOWN_DESIGN } from '../../utilities/count-down';
4 import { DEFAULT_TEXT_HIGHLIGHT_DESIGN } from '../../utilities/text-highlight-design';
5 import { DEFAULT_PRODUCT_BADGE_DESIGN } from '../../utilities/product-badge-design';
6
7 const initialState = {
8 name: '',
9 discount_intent: '',
10
11 discount_method: 'automated',
12 discount_coupon: '',
13
14 priority: '1',
15 status: '1',
16
17 show_discount_on_cart_page: false,
18
19 bogo_type: 'all',
20 discount_based_on: 'item_quantity',
21 count_quantity_as: 'separate',
22 free_item_selection: 'cart_order',
23
24 discount_rules: [
25 {
26 id: uuidv4(),
27 min: '',
28 max: '',
29 get_quantity: '',
30 get_ids: [],
31 discount_type: 'percent',
32 discount_value: '',
33 discount_label: '',
34 recursive: 'no',
35 },
36 ],
37
38 discount_max_user: '0',
39 discount_valid_from: '',
40 discount_valid_to: '',
41
42 products: ['all'],
43 conditions: [],
44
45 ui: [0, 0],
46
47 design_blocks: {
48 badge: {
49 enable: false,
50 badge_type: 'editable',
51 selected_design: DEFAULT_PRODUCT_BADGE_DESIGN,
52 position: 'top_left',
53 hasSeparator: false,
54 singleContainer: false,
55
56 // Main container styles
57 container: {
58 position: 'absolute',
59 left: '0px',
60 top: '0px',
61 width: '100px',
62 height: '30px',
63 padding: '5px 10px',
64 background: 'rgb(7, 200, 131)',
65 'clip-path':
66 'polygon(0% 0%, 100% 0%, 85% 49%, 100% 100%, 0% 100%)',
67 },
68 // Title styles
69 title: {
70 text: '[discounted_percentage] OFF',
71 color: '#FFFFFF',
72 'font-family': 'Manrope, sans-serif',
73 'font-size': '14px',
74 'font-weight': 700,
75 },
76 },
77
78 // 🧾 Text highlight (single product page)
79 text_highlight: {
80 enable: false,
81 badge_type: 'editable',
82 selected_design: DEFAULT_TEXT_HIGHLIGHT_DESIGN,
83 position: 'after_add_to_cart',
84
85 // Main container styles
86 container: {
87 width: '150px',
88 height: '40px',
89 display: 'flex',
90 padding: '5px 20px',
91 alignItems: 'center',
92 justifyContent: 'center',
93 'background-color': 'rgb(146, 81, 227)',
94 'border-color': '#fff',
95 'border-width': '0px',
96 radius: {
97 'top-left': '0px',
98 'top-right': '0px',
99 'bottom-right': '0px',
100 'bottom-left': '0px',
101 },
102 'border-style': 'solid',
103 clipPath:
104 'polygon(100% 0%, 90% 50%, 100% 100%, 0% 100%, 10% 50%, 0% 0%)',
105 },
106 // Title styles
107 title: {
108 text: 'Big savings: [discounted_amount]',
109 color: '#FFFFFF',
110 'font-family': 'Manrope, sans-serif',
111 'font-size': '14px',
112 'font-weight': 600,
113 'text-align': 'center',
114 },
115 },
116
117 // ⏳ Countdown timer
118 countdown: {
119 enable: false,
120 selected_design: DEFAULT_COUNTDOWN_DESIGN,
121 position: 'after_add_to_cart',
122
123 // Primary Text (Title)
124 title: {
125 text: 'Exclusive Deals',
126 'font-family': '',
127 'font-size': '14px',
128 'font-weight': 600,
129 'font-style': 'normal',
130 'text-decoration': 'none',
131 color: '#FFFFFF',
132 },
133
134 // Secondary Text (Subtitle)
135 subtitle: {
136 text: 'Available for a limited time only!',
137 'font-family': '',
138 'font-size': '12px',
139 'font-weight': 400,
140 'font-style': 'normal',
141 'text-decoration': 'none',
142 color: '#FFFFFF',
143 },
144
145 // Container (Area) styles
146 container: {
147 background:
148 'linear-gradient(90deg, #F39177 0%, #F61F48 35.5%, #A758EE 69%, #86C5FE 100%)',
149 'border-radius': '6px',
150 padding: '12px 16px 12px 16px',
151 'max-width': '370px',
152 border: 0,
153 'border-color': 'rgba(0, 0, 0, 0)',
154 isChain: false,
155 radius: {
156 'top-left': '6px',
157 'top-right': '6px',
158 'bottom-right': '6px',
159 'bottom-left': '6px',
160 },
161 },
162
163 // Counter Box styles
164 box: {
165 background: '#FFFFFF',
166 'border-radius': '2px',
167 padding: '8px 12px 8px 12px',
168 'min-width': '50px',
169 border: 0,
170 'border-color': 'rgba(0, 0, 0, 0)',
171 isChain: false,
172 radius: {
173 'top-left': '2px',
174 'top-right': '2px',
175 'bottom-right': '2px',
176 'bottom-left': '2px',
177 },
178 },
179
180 // Number styles (countdown digits)
181 number: {
182 'font-family': '',
183 'font-size': '20px',
184 'font-weight': 700,
185 color: '#FF4133',
186 },
187
188 // Label styles (DAYS, HOURS, etc.)
189 label: {
190 'font-family': '',
191 'font-size': '9px',
192 'font-weight': 400,
193 color: '#1A1D1F',
194 },
195
196 // Separator styles
197 separator: {
198 color: '#FFFFFF',
199 'font-size': '20px',
200 'font-weight': 700,
201 },
202
203 // Design metadata
204 hasSeparator: false,
205 singleContainer: false,
206 },
207 cart: {
208 enable: false,
209 design_type: 'notice',
210 selected_design: 'banner1',
211
212 // Banner Customization (includes text, styling, and button)
213 banner: {
214 text: '[discounted_percentage] OFF - Limited Time!',
215 'font-family': '',
216 'font-size': '14px',
217 'font-weight': 600,
218 'font-style': 'normal',
219 'text-decoration': 'none',
220 color: '#ffffff',
221 background: '#07C889',
222 'border-color': '#07C889',
223 icon_color: '#ffffff',
224 border: 0,
225 height: '45px',
226 isChain: false,
227 radius: {
228 'top-left': '8px',
229 'top-right': '8px',
230 'bottom-right': '8px',
231 'bottom-left': '8px',
232 },
233 // Success Message (shown once the customer has claimed the discount)
234 success: {
235 enable: true,
236 text: 'Congratulations! You claimed [discounted_percentage] discount',
237 'font-family': '',
238 'font-size': '14px',
239 'font-weight': 600,
240 'font-style': 'normal',
241 'text-decoration': 'none',
242 },
243
244 // Banner Button (Shop Now inside banner)
245 button: {
246 enable: true,
247 text: 'Shop Now',
248 url: '',
249 'font-family': '',
250 'font-size': '12px',
251 'font-weight': 600,
252 'font-style': 'normal',
253 'text-decoration': 'none',
254 color: '#07C889',
255 background: '#ffffff',
256 'border-color': '#ffffff',
257 border: 0,
258 height: '35px',
259 width: '100px',
260 isChain: false,
261 radius: {
262 'top-left': '4px',
263 'top-right': '4px',
264 'bottom-right': '4px',
265 'bottom-left': '4px',
266 },
267 },
268 },
269
270 // Checkout Message Customization
271 checkout_message: {
272 enable: true,
273 text: 'You have saved [Discount Amount] on this order',
274 'font-family': '',
275 'font-size': '14px',
276 'font-weight': 400,
277 'font-style': 'normal',
278 'text-decoration': 'none',
279 color: '#16a34a',
280 },
281
282 // Product Item Savings Badge
283 savings_badge: {
284 enable: true,
285 text: 'SAVE [Amount]',
286 bg_color: '#ef4444',
287 text_color: '#ffffff',
288 'font-size': '12px',
289 },
290 },
291 // 📊 Bulk, Bundle discount table
292 table: {
293 enable: false,
294 position: 'after_add_to_cart',
295 table_style: 'style1',
296
297 heading: {
298 title: 'Title',
299 discount: 'Discount',
300 range: 'Ranges',
301 buy_now: 'Buy Now',
302 },
303
304 // ========================
305 // Heading Text (Used for header font styles)
306 // ========================
307 heading_customization: {
308 'font-family': '',
309 'font-size': '14px',
310 'font-weight': 400,
311 color: '#FFFFFF',
312 background: '#283142',
313 'border-color': '#F3F4F6',
314 height: '45px',
315 'border-right': '1px solid',
316 'border-bottom': '1px solid',
317 },
318
319 // ========================
320 // Cell Customization (Used for body font styles)
321 // ========================
322 cell_customization: {
323 'font-family': '',
324 'font-size': '14px',
325 'font-weight': 400,
326 color: '#374151',
327 background: '#ffffff',
328 'border-color': '#e5e7eb',
329 height: '45px',
330 'border-right': '1px solid',
331 'border-bottom': '1px solid',
332 },
333
334 // ========================
335 // Button Customization (Using the vibrant purple from original component)
336 // ========================
337 button: {
338 enable: true,
339 text: 'Buy Now',
340 'font-family': '',
341 'font-size': '14px',
342 'font-weight': 400,
343 height: '35px',
344 color: '#ffffff',
345 background: '#07C889',
346 border: '1px solid',
347 'border-color': '#ffffff',
348 'padding-top': '4px',
349 'padding-right': '8px',
350 'padding-bottom': '4px',
351 'padding-left': '8px',
352 isChain: false,
353 radius: {
354 'top-left': '6px',
355 'top-right': '6px',
356 'bottom-right': '6px',
357 'bottom-left': '6px',
358 },
359 },
360 },
361 },
362 };
363
364 export const discountSlice = createSlice({
365 name: 'discount',
366 initialState,
367 reducers: {
368 reset: () => initialState,
369 editCampaign: (state, action) => {
370 return { ...initialState, ...action.payload };
371 },
372 updateOption: (state, action) => {
373 state[action.payload.option] = action.payload.value;
374 },
375
376 updateProducts: (state, action) => {
377 if (
378 state.products.find(
379 (_product) => _product.id === action.payload.id
380 )
381 ) {
382 state.products = state.products.filter(
383 (_product) => _product.id !== action.payload.id
384 );
385 } else {
386 state.products.push(action.payload);
387 }
388 },
389
390 removeProduct: (state, action) => {
391 state.products = state.products.filter(
392 (_product) => _product.id !== action.payload.id
393 );
394 },
395
396 // *! Condition's Reducers
397
398 addCondition: (state, action) => {
399 const condition_group_index = state.conditions.findIndex(
400 (filter) => filter.id === action.payload
401 );
402 if (condition_group_index !== -1) {
403 state.conditions[condition_group_index].base_filters.push({
404 id: uuidv4(),
405 compare_with: '',
406 operator: 'and',
407 });
408 }
409 },
410
411 addConditionGroup: (state) => {
412 state.conditions.push({
413 id: uuidv4(),
414 base_operator: 'and',
415 base_filters: [
416 {
417 id: uuidv4(),
418 compare_with: '',
419 operator: 'and',
420 },
421 ],
422 });
423 },
424
425 updateConditionGroup: (state, action) => {
426 const condition_group_index = state.conditions.findIndex(
427 (filter) => filter.id === action.payload.id
428 );
429 if (condition_group_index !== -1) {
430 state.conditions[condition_group_index].base_operator =
431 action.payload.operator;
432 }
433 },
434
435 deleteConditionGroup: (state, action) => {
436 state.conditions = state.conditions.filter(
437 (conditionGroup) => conditionGroup.id !== action.payload
438 );
439 },
440
441 updateConditionValues: (state, action) => {
442 const condition_group_index = state.conditions.findIndex(
443 (filter) => filter.id === action.payload.group_id
444 );
445
446 if (condition_group_index !== -1) {
447 const condition_index = state.conditions[
448 condition_group_index
449 ].base_filters.findIndex(
450 (filter) => filter.id === action.payload.values.id
451 );
452
453 if (condition_index !== -1) {
454 state.conditions[condition_group_index].base_filters[
455 condition_index
456 ] = action.payload.values;
457 }
458 }
459 },
460
461 deleteCondition: (state, action) => {
462 const condition_group_index = state.conditions.findIndex(
463 (filter) => filter.id === action.payload.group_id
464 );
465 if (condition_group_index !== -1) {
466 if (
467 state.conditions[condition_group_index].base_filters
468 .length === 1
469 ) {
470 state.conditions = state.conditions.filter(
471 (conditionGroup) =>
472 conditionGroup.id !== action.payload.group_id
473 );
474 } else {
475 state.conditions[condition_group_index].base_filters =
476 state.conditions[
477 condition_group_index
478 ].base_filters.filter(
479 (condition) =>
480 condition.id !== action.payload.condition_id
481 );
482 }
483 }
484 },
485
486 // *! UI Tab Reducers
487
488 setTab: (state, action) => {
489 state.ui[0] = action.payload;
490 if (state.ui[1] < state.ui[0]) {
491 state.ui[1] = state.ui[0];
492 }
493 },
494
495 // *! Discount Rules Reducers
496
497 changeBOGOType: (state, action) => {
498 if (state.bogo_type !== action.payload) {
499 state.bogo_type = action.payload;
500 state.discount_rules = state.discount_rules.map((rule) => ({
501 ...rule,
502 get_ids: [],
503 }));
504 }
505 },
506
507 changeDiscountIntention: (state, action) => {
508 state.discount_intent = action.payload;
509 state.discount_rules = [
510 {
511 id: uuidv4(),
512 min: '',
513 max: '',
514 get_quantity: '',
515 get_ids: [],
516 discount_type: 'percent',
517 discount_value: '',
518 discount_label: '',
519 recursive: 'no',
520 },
521 ];
522 state.design_blocks = initialState.design_blocks;
523 },
524
525 addNewDiscountRule: (state) => {
526 state.discount_rules.push({
527 id: uuidv4(),
528 min: '',
529 max: '',
530 get_quantity: '',
531 get_ids: [],
532 discount_type: 'percent',
533 discount_value: '',
534 discount_label: '',
535 recursive: 'no',
536 });
537 },
538
539 updateDiscountRule: (state, action) => {
540 const index = state.discount_rules.findIndex(
541 (item) => item.id === action.payload.id
542 );
543 if (index !== -1) {
544 state.discount_rules[index] = action.payload;
545 }
546 },
547 deleteDiscountRule: (state, action) => {
548 state.discount_rules = state.discount_rules.filter(
549 (item) => item.id !== action.payload
550 );
551 },
552
553 // Enable recursive on a single rule and drop every other rule. Recursive
554 // applies one repeating tier, so multiple tiers no longer make sense.
555 keepOnlyRecursiveRule: (state, action) => {
556 const rule = state.discount_rules.find(
557 (item) => item.id === action.payload
558 );
559 if (rule) {
560 state.discount_rules = [{ ...rule, recursive: 'yes' }];
561 }
562 },
563
564 // *! Design Block Reducers
565
566 updateBadge: (state, action) => {
567 state.design_blocks.badge[action.payload.name] =
568 action.payload.value;
569 },
570
571 updateTextHighlight: (state, action) => {
572 state.design_blocks.text_highlight[action.payload.name] =
573 action.payload.value;
574 },
575
576 updateCountdown: (state, action) => {
577 state.design_blocks.countdown[action.payload.name] =
578 action.payload.value;
579 },
580
581 applyCountdownDesign: (state, action) => {
582 const countdown = state.design_blocks.countdown;
583 const { designKey, design } = action.payload;
584 countdown.selected_design = designKey;
585 countdown.title = { ...countdown.title, text: design.title.text, color: design.title.color, 'font-size': design.title['font-size'], 'font-weight': design.title['font-weight'] };
586 countdown.subtitle = { ...countdown.subtitle, text: design.subtitle.text, color: design.subtitle.color, 'font-size': design.subtitle['font-size'], 'font-weight': design.subtitle['font-weight'] };
587 countdown.container = { ...countdown.container, background: design.container.background, 'border-radius': design.container['border-radius'], border: design.container.border, 'border-color': design.container['border-color'], radius: { 'top-left': design.container['border-radius'], 'top-right': design.container['border-radius'], 'bottom-right': design.container['border-radius'], 'bottom-left': design.container['border-radius'] } };
588 countdown.box = { ...countdown.box, background: design.box.background, 'border-radius': design.box['border-radius'], 'min-width': design.box['min-width'] || '50px', radius: { 'top-left': design.box['border-radius'], 'top-right': design.box['border-radius'], 'bottom-right': design.box['border-radius'], 'bottom-left': design.box['border-radius'] } };
589 countdown.number = { ...countdown.number, color: design.number.color, 'font-size': design.number['font-size'], 'font-weight': design.number['font-weight'] };
590 countdown.label = { ...countdown.label, color: design.label.color, 'font-size': design.label['font-size'], 'font-weight': design.label['font-weight'] };
591 countdown.separator = { color: design.separator.color, 'font-size': design.separator['font-size'], 'font-weight': design.separator['font-weight'] };
592 countdown.image = { url: design.image.url };
593 countdown.hasSeparator = design.hasSeparator;
594 countdown.singleContainer = design.singleContainer;
595 },
596
597 updateTable: (state, action) => {
598 state.design_blocks.table[action.payload.name] =
599 action.payload.value;
600 },
601
602 updateCartPage: (state, action) => {
603 state.design_blocks.cart[action.payload.name] =
604 action.payload.value;
605 },
606
607 // updateSinglePage: (state, action) => {
608 // state.design_blocks.singlePage[action.payload.name] =
609 // action.payload.value;
610 // },
611 // updateCartPage: (state, action) => {
612 // state.design_blocks.cartPage[action.payload.name] =
613 // action.payload.value;
614 // },
615 },
616 });
617
618 export const {
619 reset,
620 editCampaign,
621 updateOption,
622 updateProducts,
623 removeProduct,
624 addCondition,
625 addConditionGroup,
626 updateConditionGroup,
627 deleteConditionGroup,
628 updateConditionValues,
629 deleteCondition,
630 setTab,
631
632 changeBOGOType,
633 changeDiscountIntention,
634 addNewDiscountRule,
635 updateDiscountRule,
636 deleteDiscountRule,
637 keepOnlyRecursiveRule,
638
639 updateBadge,
640 updateTextHighlight,
641 updateCountdown,
642 applyCountdownDesign,
643 updateTable,
644 updateCartPage,
645 } = discountSlice.actions;
646
647 export default discountSlice.reducer;
648