PluginProbe
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar / 3.2.14
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar v3.2.14
3.3.1 3.3.0 3.2.14 3.2.13 3.2.12 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 trunk 0.2.5.5 0.2.5.6 0.2.5.7 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2.0 1.2.1 All 156 releases
notificationx / blocks / countdown / components / preview.js

preview.js in NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar 3.2.14, at blocks/countdown/components/preview.js

135 lines 3.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { useState, useEffect } from "@wordpress/element";
2 import { __ } from "@wordpress/i18n";
3
4 const pad = (n) => String(n).padStart(2, "0");
5
6 const ZERO = { days: 0, hours: 0, minutes: 0, seconds: 0 };
7
8 /**
9 * Live ticking countdown for the editor preview. Mirrors the frontend logic
10 * (assets/public/js/nx-countdown.js) but runs in React — it never touches the
11 * vanilla frontend script (which would fight React over the DOM).
12 */
13 function useCountdown(attributes) {
14 const {
15 countdownType,
16 dueTime,
17 evergreenHours,
18 evergreenMinutes,
19 } = attributes;
20
21 const [remaining, setRemaining] = useState(ZERO);
22 const [expired, setExpired] = useState(false);
23
24 useEffect(() => {
25 let target;
26 if (countdownType === "evergreen") {
27 const seconds =
28 (parseInt(evergreenHours || 0, 10) * 3600) +
29 (parseInt(evergreenMinutes || 0, 10) * 60);
30 target = Date.now() + seconds * 1000;
31 } else {
32 target = dueTime ? new Date(dueTime).getTime() : 0;
33 }
34
35 const tick = () => {
36 if (!target || isNaN(target)) {
37 setRemaining(ZERO);
38 setExpired(false);
39 return;
40 }
41 const diff = target - Date.now();
42 if (diff <= 0) {
43 setRemaining(ZERO);
44 setExpired(true);
45 return;
46 }
47 setExpired(false);
48 setRemaining({
49 days: Math.floor(diff / (1000 * 60 * 60 * 24)),
50 hours: Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)),
51 minutes: Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)),
52 seconds: Math.floor((diff % (1000 * 60)) / 1000),
53 });
54 };
55
56 tick();
57 const id = setInterval(tick, 1000);
58 return () => clearInterval(id);
59 }, [countdownType, dueTime, evergreenHours, evergreenMinutes]);
60
61 return { remaining, expired };
62 }
63
64 export default function CountdownPreview({ blockId, attributes }) {
65 const {
66 layout,
67 labelView,
68 showSeparator,
69 separatorStyle,
70 showDays,
71 daysLabel,
72 showHours,
73 hoursLabel,
74 showMinutes,
75 minutesLabel,
76 showSeconds,
77 secondsLabel,
78 expireType,
79 expiryTitle,
80 expiryText,
81 } = attributes;
82
83 const { remaining, expired } = useCountdown(attributes);
84
85 const listClasses = [
86 "nx-countdown-container",
87 `nx-countdown-layout-${layout || "grid"}`,
88 labelView || "nx-countdown-label-block",
89 showSeparator
90 ? `nx-countdown-show-separator nx-countdown-separator-${separatorStyle}`
91 : "",
92 ]
93 .filter(Boolean)
94 .join(" ");
95
96 const items = [
97 { show: showDays, unit: "days", label: daysLabel, value: remaining.days },
98 { show: showHours, unit: "hours", label: hoursLabel, value: remaining.hours },
99 { show: showMinutes, unit: "minutes", label: minutesLabel, value: remaining.minutes },
100 { show: showSeconds, unit: "seconds", label: secondsLabel, value: remaining.seconds },
101 ];
102
103 return (
104 <div className={`${blockId} nx-countdown-wrapper`}>
105 <ul id={`nx-countdown-${blockId}`} className={listClasses}>
106 {expired && expireType === "text" ? (
107 <div className="nx-countdown-finish-message">
108 <h4 className="nx-expiry-title">{expiryTitle}</h4>
109 <div
110 className="nx-expiry-text"
111 dangerouslySetInnerHTML={{ __html: expiryText }}
112 />
113 </div>
114 ) : expired && expireType === "url" ? (
115 <p>{__("Page will redirect to the given URL on the frontend.", "notificationx")}</p>
116 ) : (
117 items.map(
118 (item) =>
119 item.show && (
120 <li className="nx-countdown-item" key={item.unit}>
121 <div className={`nx-countdown-${item.unit}`}>
122 <span className="nx-countdown-digits">{pad(item.value)}</span>
123 {item.label ? (
124 <span className="nx-countdown-label">{item.label}</span>
125 ) : null}
126 </div>
127 </li>
128 )
129 )
130 )}
131 </ul>
132 </div>
133 );
134 }
135