react-notify-sdk 1.0.64 → 1.0.66
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/FeatureMessageProvider.js +72 -45
- package/package.json +1 -1
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
// src/FeatureMessageProvider.tsx
|
|
3
|
-
import { useEffect, useState } from 'react';
|
|
3
|
+
import { useEffect, useState, useRef } from 'react';
|
|
4
4
|
import FeatureMessage from './FeatureMessage';
|
|
5
|
-
import { getSupabaseClient } from './supabase/supabaseClient';
|
|
6
5
|
import useDeviceDetection from './useDeviceDetection';
|
|
7
6
|
import FadeWrapper from './FadeWrapper';
|
|
8
7
|
// Wildcard route matching utility
|
|
@@ -26,12 +25,17 @@ const baseUrlMatches = (msgBaseUrl) => {
|
|
|
26
25
|
return msgBaseUrl === window.location.origin;
|
|
27
26
|
};
|
|
28
27
|
export const FeatureMessageProvider = ({ projectKey, }) => {
|
|
28
|
+
const TTL = 30000; // 30 seconds
|
|
29
|
+
// Route-level cache (module scoped, persists across re-renders)
|
|
30
|
+
const routeCache = {};
|
|
29
31
|
const [message, setMessage] = useState(null);
|
|
30
32
|
const [messages, setMessages] = useState([]);
|
|
31
33
|
const [visible, setVisible] = useState(false);
|
|
32
34
|
const [pathname, setPathname] = useState(() => typeof window !== 'undefined' ? window.location.pathname : '');
|
|
33
35
|
const device = useDeviceDetection();
|
|
34
|
-
//
|
|
36
|
+
// 🔹 Persist version across renders
|
|
37
|
+
const versionRef = useRef(0);
|
|
38
|
+
const intervalRef = useRef(null);
|
|
35
39
|
//Dismissed message cached retrieval
|
|
36
40
|
const DISMISSED_KEY = "__feature_messages_dismissed__";
|
|
37
41
|
const getDismissedMessages = () => {
|
|
@@ -62,9 +66,9 @@ export const FeatureMessageProvider = ({ projectKey, }) => {
|
|
|
62
66
|
// Re-show if message changed
|
|
63
67
|
return dismissed.messageUpdatedAt === message?.updated_at;
|
|
64
68
|
};
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
//
|
|
69
|
+
// --------------------------------------------
|
|
70
|
+
// PATHNAME TRACKING
|
|
71
|
+
// --------------------------------------------
|
|
68
72
|
useEffect(() => {
|
|
69
73
|
if (typeof window === 'undefined')
|
|
70
74
|
return;
|
|
@@ -90,55 +94,78 @@ export const FeatureMessageProvider = ({ projectKey, }) => {
|
|
|
90
94
|
window.history.replaceState = originalReplaceState;
|
|
91
95
|
};
|
|
92
96
|
}, []);
|
|
97
|
+
// --------------------------------------------
|
|
98
|
+
// FETCH + VERSION DIFF POLLING
|
|
99
|
+
// --------------------------------------------
|
|
93
100
|
// Your main effect - now uses the reactive pathname state
|
|
94
101
|
useEffect(() => {
|
|
95
102
|
if (typeof window === 'undefined')
|
|
96
103
|
return; // Skip on server
|
|
97
|
-
let fadeOutTimer = null; // Track the timer
|
|
98
104
|
const origin = window.location.origin;
|
|
105
|
+
const cacheKey = `${projectKey}_${pathname}`;
|
|
106
|
+
// Track current version per route
|
|
107
|
+
//const versionRef = { current: 0 };
|
|
99
108
|
// 🔹 1. Fetch ALL active messages once per project
|
|
100
|
-
const fetchMessages = async () => {
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}),
|
|
111
|
-
});
|
|
112
|
-
if (!response.ok)
|
|
113
|
-
return null;
|
|
114
|
-
const data = await response.json();
|
|
115
|
-
if (data) {
|
|
116
|
-
setMessages(data);
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
fetchMessages();
|
|
120
|
-
// 🔹 2. Subscribe ONCE per project
|
|
121
|
-
const subscription = supabaseClient
|
|
122
|
-
.channel("feature_messages_channel")
|
|
123
|
-
.on("postgres_changes", { event: "*", schema: "public", table: "feature_messages" }, (payload) => {
|
|
124
|
-
const msg = payload.new;
|
|
125
|
-
if (msg.project_key !== projectKey)
|
|
109
|
+
const fetchMessages = async (force = false) => {
|
|
110
|
+
const now = Date.now();
|
|
111
|
+
const cacheKey = `${projectKey}_${pathname}`;
|
|
112
|
+
const cached = routeCache[cacheKey];
|
|
113
|
+
// ✅ TTL cache check
|
|
114
|
+
if (!force &&
|
|
115
|
+
cached &&
|
|
116
|
+
now - cached.timestamp < TTL) {
|
|
117
|
+
versionRef.current = cached.version;
|
|
118
|
+
setMessages(cached.data);
|
|
126
119
|
return;
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
const response = await fetch("https://dhgnstjrkeuqnsapwcec.functions.supabase.co/get-feature-message", {
|
|
123
|
+
method: "POST",
|
|
124
|
+
headers: {
|
|
125
|
+
"Content-Type": "application/json",
|
|
126
|
+
},
|
|
127
|
+
body: JSON.stringify({
|
|
128
|
+
projectKey,
|
|
129
|
+
pathname,
|
|
130
|
+
origin,
|
|
131
|
+
version: versionRef.current, // 🔥 Send current version
|
|
132
|
+
}),
|
|
133
|
+
});
|
|
134
|
+
if (!response.ok)
|
|
135
|
+
return null;
|
|
136
|
+
const data = await response.json();
|
|
137
|
+
// 🔁 No changes — just bump timestamp
|
|
138
|
+
if (data.unchanged && cached) {
|
|
139
|
+
routeCache[cacheKey].timestamp = Date.now();
|
|
140
|
+
return;
|
|
131
141
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
142
|
+
versionRef.current = data.version;
|
|
143
|
+
routeCache[cacheKey] = {
|
|
144
|
+
data: data.messages,
|
|
145
|
+
version: data.version,
|
|
146
|
+
timestamp: Date.now(),
|
|
147
|
+
};
|
|
148
|
+
setMessages(data.messages);
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
console.error("Failed to fetch feature messages:", error);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
fetchMessages(true);
|
|
155
|
+
// 🔄 Poll every 30 seconds
|
|
156
|
+
intervalRef.current = setInterval(() => {
|
|
157
|
+
fetchMessages(false);
|
|
158
|
+
}, TTL);
|
|
136
159
|
return () => {
|
|
137
|
-
if (
|
|
138
|
-
|
|
139
|
-
|
|
160
|
+
if (intervalRef.current) {
|
|
161
|
+
clearInterval(intervalRef.current);
|
|
162
|
+
}
|
|
140
163
|
};
|
|
141
|
-
}, [projectKey]);
|
|
164
|
+
}, [projectKey, pathname]);
|
|
165
|
+
// --------------------------------------------
|
|
166
|
+
// MATCH ROUTE → SHOW MESSAGE
|
|
167
|
+
// --------------------------------------------
|
|
168
|
+
// Effect to determine which message to show based on current pathname and messages
|
|
142
169
|
useEffect(() => {
|
|
143
170
|
if (!pathname || !messages.length)
|
|
144
171
|
return;
|