react-notify-sdk 1.0.42 → 1.0.43
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/dist/FeatureMessage.d.ts +2 -1
- package/dist/FeatureMessage.js +102 -24
- package/dist/FeatureMessageProvider.js +39 -4
- package/dist/lib/trackEvent.d.ts +1 -0
- package/dist/lib/trackEvent.js +20 -0
- package/dist/types.d.ts +9 -0
- package/package.json +1 -1
package/dist/FeatureMessage.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { FeatureMessages } from './types';
|
|
2
2
|
interface FeatureMessageProps {
|
|
3
3
|
message: FeatureMessages;
|
|
4
|
+
onDismiss?: (id: string) => void;
|
|
4
5
|
}
|
|
5
|
-
declare const FeatureMessage: ({ message }: FeatureMessageProps) => import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
declare const FeatureMessage: ({ message, onDismiss }: FeatureMessageProps) => import("react/jsx-runtime").JSX.Element;
|
|
6
7
|
export default FeatureMessage;
|
package/dist/FeatureMessage.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
/////////////---Icon imports---////////////////////
|
|
3
3
|
import { AlertTriangle, CircleX, Info } from "lucide-react";
|
|
4
|
-
const FeatureMessage = ({ message }) => {
|
|
4
|
+
const FeatureMessage = ({ message, onDismiss }) => {
|
|
5
5
|
function hexToRgba(hex, alpha) {
|
|
6
6
|
// Remove leading #
|
|
7
7
|
hex = hex.replace(/^#/, "");
|
|
@@ -16,32 +16,110 @@ const FeatureMessage = ({ message }) => {
|
|
|
16
16
|
const b = bigint & 255;
|
|
17
17
|
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
18
18
|
}
|
|
19
|
+
// Handle click with tracking
|
|
20
|
+
const handleClick = async (e) => {
|
|
21
|
+
// Don't trigger if clicking close button
|
|
22
|
+
if (e.target.closest('[data-dismiss-button]')) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const action = message.click_action || 'none';
|
|
26
|
+
// Perform the action
|
|
27
|
+
switch (action) {
|
|
28
|
+
case 'navigate':
|
|
29
|
+
if (message.click_url) {
|
|
30
|
+
window.location.href = message.click_url;
|
|
31
|
+
}
|
|
32
|
+
break;
|
|
33
|
+
case 'external':
|
|
34
|
+
if (message.click_url) {
|
|
35
|
+
window.open(message.click_url, '_blank', 'noopener,noreferrer');
|
|
36
|
+
}
|
|
37
|
+
break;
|
|
38
|
+
case 'dismiss':
|
|
39
|
+
handleDismiss();
|
|
40
|
+
break;
|
|
41
|
+
case 'none':
|
|
42
|
+
default:
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const handleDismiss = () => {
|
|
47
|
+
if (onDismiss) {
|
|
48
|
+
onDismiss(message.id);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const filterButton = (type) => {
|
|
52
|
+
if (type?.click_action === "external") {
|
|
53
|
+
return 'Open';
|
|
54
|
+
}
|
|
55
|
+
else if (type?.click_action === "navigate") {
|
|
56
|
+
return 'Go to';
|
|
57
|
+
}
|
|
58
|
+
else if (type?.click_action === "dismiss") {
|
|
59
|
+
return 'Close';
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
return '';
|
|
63
|
+
}
|
|
64
|
+
};
|
|
19
65
|
return (_jsxs("div", { style: {
|
|
20
|
-
width:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
66
|
+
width: "95%", // w-[95%]
|
|
67
|
+
height: "100%", // h-full
|
|
68
|
+
marginLeft: "auto", // mx-auto
|
|
69
|
+
marginRight: "auto",
|
|
70
|
+
display: "flex", // flex flex-row
|
|
71
|
+
flexDirection: "row",
|
|
72
|
+
paddingTop: "0.75rem", // py-3
|
|
73
|
+
paddingBottom: "0.75rem",
|
|
74
|
+
paddingLeft: "0.75rem", // px-3
|
|
75
|
+
paddingRight: "0.75rem",
|
|
76
|
+
borderRadius: "0.5rem", // rounded-lg
|
|
25
77
|
backgroundColor: message?.backgroundColor,
|
|
26
|
-
border: `1px solid ${message?.textColor}`, // Completed border style
|
|
27
|
-
borderRadius: "8px",
|
|
28
78
|
borderWidth: "1px",
|
|
29
|
-
borderColor:
|
|
79
|
+
borderColor: hexToRgba(message?.borderColor, 0.3),
|
|
30
80
|
boxShadow: `0 10px 15px -3px ${hexToRgba(message.borderColor, 0.4)}, 0 4px 6px -4px ${hexToRgba(message.borderColor, 0.4)}`
|
|
31
|
-
}, children: [_jsxs("div", {
|
|
32
|
-
width:
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
81
|
+
}, children: [_jsxs("div", { style: {
|
|
82
|
+
width: message?.click_action === "view only" ? "100%" : "80%", // w-4/5
|
|
83
|
+
height: "100%", // h-full
|
|
84
|
+
display: "flex", // flex flex-col
|
|
85
|
+
flexDirection: "column",
|
|
86
|
+
borderRightWidth: "1px", // border-r
|
|
87
|
+
borderRightColor: "white"
|
|
88
|
+
}, children: [_jsxs("div", { style: {
|
|
89
|
+
position: "relative", // relative
|
|
90
|
+
width: "100%", // w-full
|
|
91
|
+
display: "flex", // flex flex-row
|
|
92
|
+
flexDirection: "row",
|
|
93
|
+
alignItems: "center" // items-center
|
|
94
|
+
}, children: [message?.type === "Information" && (_jsx(Info, { size: 16, style: { color: "#3b82f6" } }) // text-blue-500
|
|
95
|
+
), message?.type === "Warning" && (_jsx(AlertTriangle, { size: 16, style: { color: "#f59e0b" } }) // text-amber-500
|
|
96
|
+
), message?.type === "Error" && (_jsx(CircleX, { size: 16, style: { color: "#ef4444" } }) // text-red-500
|
|
97
|
+
), _jsx("p", { style: {
|
|
98
|
+
color: message?.textColor,
|
|
99
|
+
fontSize: "1.125rem", // text-lg
|
|
100
|
+
fontWeight: 600, // font-semibold
|
|
101
|
+
marginLeft: "0.75rem" // ml-3
|
|
102
|
+
}, children: message?.title })] }), _jsx("p", { style: {
|
|
103
|
+
color: message?.textColor,
|
|
104
|
+
fontSize: "0.75rem", // text-xs
|
|
105
|
+
marginTop: "0.25rem" // mt-1
|
|
106
|
+
}, children: message?.content })] }), message?.click_action && message?.click_action === "view only" ?
|
|
107
|
+
null
|
|
108
|
+
:
|
|
109
|
+
_jsx("button", {
|
|
110
|
+
//data-dismiss-button
|
|
111
|
+
style: {
|
|
112
|
+
width: "20%", // w-1/5
|
|
113
|
+
height: "1rem", // h-4 (16px)
|
|
114
|
+
marginTop: "auto", // my-auto
|
|
115
|
+
marginBottom: "auto",
|
|
116
|
+
display: "flex", // flex
|
|
117
|
+
justifyContent: "center", // justify-center
|
|
118
|
+
alignItems: "center" // items-center
|
|
119
|
+
}, children: _jsx("p", { style: {
|
|
120
|
+
fontSize: "1rem", // text-base
|
|
121
|
+
color: "white",
|
|
122
|
+
cursor: "pointer"
|
|
123
|
+
}, onClick: message?.click_action ? handleClick : undefined, onMouseEnter: (e) => (e.currentTarget.style.color = `${message?.borderColor}`), onMouseLeave: (e) => (e.currentTarget.style.color = "white"), children: `${filterButton(message)}` }) })] }));
|
|
46
124
|
};
|
|
47
125
|
export default FeatureMessage;
|
|
@@ -23,6 +23,36 @@ export const FeatureMessageProvider = ({ projectKey, }) => {
|
|
|
23
23
|
const [visible, setVisible] = useState(false);
|
|
24
24
|
const [pathname, setPathname] = useState(() => typeof window !== 'undefined' ? window.location.pathname : '');
|
|
25
25
|
const device = useDeviceDetection();
|
|
26
|
+
//Dismiss message caching
|
|
27
|
+
//Dismissed message cached retrieval
|
|
28
|
+
const DISMISSED_KEY = "__feature_messages_dismissed__";
|
|
29
|
+
const getDismissedMessages = () => {
|
|
30
|
+
if (typeof window === "undefined")
|
|
31
|
+
return {};
|
|
32
|
+
try {
|
|
33
|
+
return JSON.parse(localStorage.getItem(DISMISSED_KEY) || "{}");
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return {};
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
//Dismissed message cache storing
|
|
40
|
+
const dismissMessage = (message) => {
|
|
41
|
+
const dismissed = getDismissedMessages();
|
|
42
|
+
dismissed[message.id] = {
|
|
43
|
+
messageId: message.id,
|
|
44
|
+
dismissedAt: new Date().toISOString(),
|
|
45
|
+
messageUpdatedAt: message.updated_at,
|
|
46
|
+
};
|
|
47
|
+
localStorage.setItem(DISMISSED_KEY, JSON.stringify(dismissed));
|
|
48
|
+
};
|
|
49
|
+
const isDismissed = (message) => {
|
|
50
|
+
const dismissed = getDismissedMessages()[message.id];
|
|
51
|
+
if (!dismissed)
|
|
52
|
+
return false;
|
|
53
|
+
// Re-show if message changed
|
|
54
|
+
return dismissed.messageUpdatedAt === message.updated_at;
|
|
55
|
+
};
|
|
26
56
|
// Create supabase client with project key header
|
|
27
57
|
const supabaseClient = getSupabaseClient(projectKey);
|
|
28
58
|
// Effect to track pathname changes
|
|
@@ -55,6 +85,7 @@ export const FeatureMessageProvider = ({ projectKey, }) => {
|
|
|
55
85
|
useEffect(() => {
|
|
56
86
|
if (typeof window === 'undefined')
|
|
57
87
|
return; // Skip on server
|
|
88
|
+
let fadeOutTimer = null; // Track the timer
|
|
58
89
|
const fetchMessage = async () => {
|
|
59
90
|
const { data } = await supabaseClient
|
|
60
91
|
.from('feature_messages')
|
|
@@ -64,14 +95,16 @@ export const FeatureMessageProvider = ({ projectKey, }) => {
|
|
|
64
95
|
.eq('is_active', true)
|
|
65
96
|
.order('created_at', { ascending: false });
|
|
66
97
|
const match = data?.find((msg) => routeMatches(msg.route, pathname));
|
|
67
|
-
if (match) {
|
|
98
|
+
if (match && !isDismissed(match)) {
|
|
99
|
+
if (fadeOutTimer)
|
|
100
|
+
clearTimeout(fadeOutTimer); // Clear any pending timeout
|
|
68
101
|
setMessage(match);
|
|
69
102
|
setVisible(true); // Fade in
|
|
70
103
|
}
|
|
71
104
|
else {
|
|
72
105
|
// Trigger fade out before removing message
|
|
106
|
+
fadeOutTimer = setTimeout(() => setMessage(null), 300);
|
|
73
107
|
setVisible(false);
|
|
74
|
-
setTimeout(() => setMessage(null), 300); // match fadeOut duration
|
|
75
108
|
}
|
|
76
109
|
};
|
|
77
110
|
fetchMessage();
|
|
@@ -84,12 +117,14 @@ export const FeatureMessageProvider = ({ projectKey, }) => {
|
|
|
84
117
|
}, (payload) => {
|
|
85
118
|
const msg = payload.new;
|
|
86
119
|
if (msg.project_key === projectKey && msg.is_active && routeMatches(msg.route, pathname)) {
|
|
120
|
+
if (fadeOutTimer)
|
|
121
|
+
clearTimeout(fadeOutTimer); // Clear any pending timeout
|
|
87
122
|
setMessage(msg);
|
|
88
123
|
setVisible(true);
|
|
89
124
|
}
|
|
90
125
|
else {
|
|
91
126
|
setVisible(false);
|
|
92
|
-
setTimeout(() => setMessage(null), 300);
|
|
127
|
+
fadeOutTimer = setTimeout(() => setMessage(null), 300);
|
|
93
128
|
}
|
|
94
129
|
})
|
|
95
130
|
.subscribe();
|
|
@@ -99,5 +134,5 @@ export const FeatureMessageProvider = ({ projectKey, }) => {
|
|
|
99
134
|
}, [pathname, projectKey]);
|
|
100
135
|
if (!message)
|
|
101
136
|
return null;
|
|
102
|
-
return (_jsx(FadeWrapper, { visible: visible, device: device, message: message, children: _jsx(FeatureMessage, { message: message }) }));
|
|
137
|
+
return (_jsx(FadeWrapper, { visible: visible, device: device, message: message, children: _jsx(FeatureMessage, { message: message, onDismiss: () => dismissMessage(message) }) }));
|
|
103
138
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const trackClick: (messageId: string, projectKey: string, clickAction: string, clickUrl?: string) => Promise<void>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// src/lib/trackEvent.ts
|
|
2
|
+
import { getSupabaseClient } from "../supabase/supabaseClient";
|
|
3
|
+
export const trackClick = async (messageId, projectKey, clickAction, clickUrl) => {
|
|
4
|
+
try {
|
|
5
|
+
const client = getSupabaseClient(projectKey);
|
|
6
|
+
await client.from('message_analytics').insert({
|
|
7
|
+
project_key: projectKey,
|
|
8
|
+
message_id: messageId,
|
|
9
|
+
event_type: 'click',
|
|
10
|
+
click_action: clickAction,
|
|
11
|
+
click_url: clickUrl,
|
|
12
|
+
user_agent: navigator.userAgent,
|
|
13
|
+
created_at: new Date().toISOString(),
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
// Fail silently - don't break the user experience
|
|
18
|
+
console.error('Failed to track click:', error);
|
|
19
|
+
}
|
|
20
|
+
};
|
package/dist/types.d.ts
CHANGED
|
@@ -13,10 +13,19 @@ export type FeatureMessages = {
|
|
|
13
13
|
borderWidth: number;
|
|
14
14
|
is_active: boolean;
|
|
15
15
|
created_at: string;
|
|
16
|
+
updated_at?: string;
|
|
17
|
+
ended_at?: string;
|
|
16
18
|
type?: 'Information' | 'Warning' | 'Error';
|
|
19
|
+
click_action?: 'view only' | 'navigate' | 'external' | 'dismiss';
|
|
20
|
+
click_url?: string;
|
|
17
21
|
};
|
|
18
22
|
export type FeatureMessageProviderProps = {
|
|
19
23
|
projectKey: string;
|
|
20
24
|
className?: string;
|
|
21
25
|
disableDefaultStyles?: boolean;
|
|
22
26
|
};
|
|
27
|
+
export type DismissedMessage = {
|
|
28
|
+
messageId: string;
|
|
29
|
+
dismissedAt: string;
|
|
30
|
+
messageUpdatedAt: any;
|
|
31
|
+
};
|