PluginProbe
Extendify / 3.1.4
Extendify v3.1.4
3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 0.7.0 All 126 releases
extendify / src / PartnerNotification / PartnerNotification.jsx

PartnerNotification.jsx in Extendify 3.1.4, at src/PartnerNotification/PartnerNotification.jsx

132 lines 4.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { safeParseJson } from '@shared/lib/parsing';
2 import { track } from '@shared/lib/track';
3 import { useEffect, useState } from '@wordpress/element';
4 import { __ } from '@wordpress/i18n';
5 import { close, Icon } from '@wordpress/icons';
6 import { useNotificationsStore } from './notifications';
7 import { resolveNotificationLink } from './partner-notification-link';
8
9 export const COLOR_DEFAULTS = {
10 'color-background': '#ffffff',
11 'color-border': '#d1d5db',
12 'color-text': '#1e1e1e',
13 'color-button-background': '#1e1e1e',
14 'color-button-text': '#ffffff',
15 'color-button-hover-background': '#000000',
16 'color-button-hover-text': '#ffffff',
17 'color-button-close-background': '#f3f4f6',
18 'color-button-close-text': '#1e1e1e',
19 'color-button-close-hover-background': '#d1d5db',
20 'color-button-close-hover-text': '#1e1e1e',
21 };
22
23 const CSS_VARS = {
24 'color-background': '--ext-pn-bg',
25 'color-border': '--ext-pn-border',
26 'color-text': '--ext-pn-text',
27 'color-button-background': '--ext-pn-btn-bg',
28 'color-button-text': '--ext-pn-btn-text',
29 'color-button-hover-background': '--ext-pn-btn-hover-bg',
30 'color-button-hover-text': '--ext-pn-btn-hover-text',
31 'color-button-close-background': '--ext-pn-close-bg',
32 'color-button-close-text': '--ext-pn-close-icon',
33 'color-button-close-hover-background': '--ext-pn-close-hover-bg',
34 'color-button-close-hover-text': '--ext-pn-close-hover-icon',
35 };
36
37 const colorStyle = (notification) =>
38 Object.fromEntries(
39 Object.entries(CSS_VARS).map(([field, cssVar]) => [
40 cssVar,
41 notification[field] || COLOR_DEFAULTS[field],
42 ]),
43 );
44
45 export const PartnerNotification = ({ slot }) => {
46 const {
47 dismissBanner,
48 isDismissedBanner,
49 hasViewedNotification,
50 recordNotificationView,
51 } = useNotificationsStore();
52 const adminUrl = window.extSharedData?.adminUrl ?? '';
53
54 const notifications = safeParseJson(
55 window.extSharedData?.partnerNotifications,
56 [],
57 );
58 // Frozen at mount so dismissing doesn't reveal the next notification until reload.
59 const [notification] = useState(() =>
60 notifications.find(
61 (item) => item?.slots?.includes(slot) && !isDismissedBanner(item.slug),
62 ),
63 );
64
65 const slug = notification?.slug;
66 const page = window.pagenow ?? '';
67 useEffect(() => {
68 if (!slug) return;
69 if (hasViewedNotification(slug, slot, page)) return;
70 track('partner_notification_view', { slug, slot, page });
71 recordNotificationView(slug, slot, page);
72 }, [slug, slot, page, hasViewedNotification, recordNotificationView]);
73
74 if (!notification || isDismissedBanner(slug)) return null;
75
76 const { title, content, image } = notification;
77 const buttonLabel = notification['button-label'];
78 const linkType = notification['button-link-type'];
79 const { href, external } = resolveNotificationLink(notification, adminUrl);
80
81 const dismiss = () => {
82 track('partner_notification_dismiss', { slug, slot, page });
83 dismissBanner(slug);
84 };
85
86 return (
87 <div className="extendify-shared">
88 <div
89 style={colorStyle(notification)}
90 className="relative h-full min-h-32 w-full rounded-sm border bg-(--ext-pn-bg) px-5 py-5 text-base text-(--ext-pn-text) lg:px-8 lg:py-6 border-(--ext-pn-border)"
91 data-test="assist-partner-notification"
92 >
93 <button
94 type="button"
95 aria-label={__('Dismiss notification', 'extendify-local')}
96 onClick={dismiss}
97 className="absolute right-0 top-0 flex h-8 w-8 items-center justify-center rounded-bl rounded-se text-center p-1.5 rtl:left-0 rtl:right-auto rtl:rounded-bl-none rtl:rounded-br bg-(--ext-pn-close-bg) text-(--ext-pn-close-icon) hover:bg-(--ext-pn-close-hover-bg) hover:text-(--ext-pn-close-hover-icon)"
98 >
99 <Icon icon={close} size={32} className="fill-current" />
100 </button>
101 <div className="flex flex-col items-start gap-4">
102 {image && (
103 <img src={image} alt="" className="max-h-8 w-auto rounded-xs" />
104 )}
105 <div>
106 <div className="text-lg font-semibold">{title}</div>
107 <div className="mt-1 text-sm">{content}</div>
108 </div>
109 {buttonLabel && href && (
110 <a
111 href={href}
112 target={external ? '_blank' : undefined}
113 rel={external ? 'noreferrer' : undefined}
114 onClick={() =>
115 track('partner_notification_click', {
116 slug,
117 slot,
118 linkType,
119 page,
120 })
121 }
122 className="inline-flex h-10 cursor-pointer items-center rounded-xs px-4 text-sm no-underline bg-(--ext-pn-btn-bg) text-(--ext-pn-btn-text) hover:bg-(--ext-pn-btn-hover-bg) hover:text-(--ext-pn-btn-hover-text)"
123 >
124 {buttonLabel}
125 </a>
126 )}
127 </div>
128 </div>
129 </div>
130 );
131 };
132