customersay-widget
Version:
A plug-and-play feedback widget for React/Next.js applications with smart triggers and analytics
632 lines (631 loc) • 39.4 kB
JavaScript
"use client";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useEffect, useState } from 'react';
var FeedbackWidget = function (_a) {
var _b;
var workspace = _a.workspace, _c = _a.apiBase, apiBase = _c === void 0 ? "https://customersay.xyz/api" : _c, onFeedbackSubmit = _a.onFeedbackSubmit, onWidgetShow = _a.onWidgetShow, onWidgetHide = _a.onWidgetHide, className = _a.className, style = _a.style, _d = _a.autoLoad, autoLoad = _d === void 0 ? true : _d, _e = _a.position, position = _e === void 0 ? 'bottom-right' : _e;
var _f = useState(null), config = _f[0], setConfig = _f[1];
var _g = useState(true), loading = _g[0], setLoading = _g[1];
var _h = useState({}), answers = _h[0], setAnswers = _h[1];
var _j = useState(false), submitted = _j[0], setSubmitted = _j[1];
var _k = useState(false), showOverlay = _k[0], setShowOverlay = _k[1];
var _l = useState(false), shouldShow = _l[0], setShouldShow = _l[1];
var _m = useState(false), showOverlayWidget = _m[0], setShowOverlayWidget = _m[1];
var _o = useState(false), showFeedbackPrompt = _o[0], setShowFeedbackPrompt = _o[1];
var _p = useState(true), showFloatingButton = _p[0], setShowFloatingButton = _p[1]; // Start with true, will be controlled by triggers
var _q = useState(false), submitting = _q[0], setSubmitting = _q[1];
var _r = useState(null), error = _r[0], setError = _r[1];
var _s = useState(null), discountCode = _s[0], setDiscountCode = _s[1];
var _t = useState('manual'), triggeredBy = _t[0], setTriggeredBy = _t[1];
var _u = useState(false), hasInteracted = _u[0], setHasInteracted = _u[1];
useEffect(function () {
if (!workspace || !autoLoad)
return;
var fetchConfig = function () { return __awaiter(void 0, void 0, void 0, function () {
var res, data, error_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 3, , 4]);
return [4 /*yield*/, fetch("".concat(apiBase, "/widget-config?site_id=").concat(workspace))];
case 1:
res = _a.sent();
if (!res.ok) {
throw new Error("HTTP error! status: ".concat(res.status));
}
return [4 /*yield*/, res.json()];
case 2:
data = _a.sent();
setConfig(__assign(__assign({}, data.config), { discount_enabled: data.discount_enabled, discount_code: data.discount_code }));
setLoading(false);
return [3 /*break*/, 4];
case 3:
error_1 = _a.sent();
console.error('Failed to load widget config:', error_1);
setLoading(false);
setConfig({
title: 'Feedback',
questions: [
{ id: 'rating', type: 'rating', label: 'How would you rate your experience?', max: 5 },
{ id: 'feedback', type: 'text', label: 'Any additional feedback?', rows: 3 }
],
discount_enabled: false,
displayMode: 'overlay',
colors: {
background: '#ffffff',
button: '#1976d2',
buttonText: '#ffffff',
fieldBackground: '#ffffff',
fieldText: '#000000',
titleText: '#000000',
labelText: '#000000',
floatingButton: '#1976d2',
floatingButtonIcon: '💬'
},
triggers: {}
});
return [3 /*break*/, 4];
case 4: return [2 /*return*/];
}
});
}); };
fetchConfig();
}, [workspace, apiBase, autoLoad]);
// Trigger logic
useEffect(function () {
var _a, _b, _c, _d, _e, _f, _g, _h;
console.log('🔍 Trigger useEffect called:', { config: !!config, loading: loading, workspace: workspace });
if (!config || loading) {
console.log('❌ Early return - no config or loading');
return;
}
var triggers = config.triggers || {};
console.log('📋 Triggers config:', triggers);
// Check if widget was dismissed
var isDismissed = localStorage.getItem("feedback_widget_dismissed_".concat(workspace));
console.log('🚫 Dismissed check:', isDismissed);
if (isDismissed === 'true') {
console.log('❌ Widget dismissed, returning');
return;
}
// Check if user has already interacted with widget in this session
console.log('🤝 Has interacted check:', hasInteracted);
if (hasInteracted) {
console.log('❌ User already interacted, no more triggers');
return;
}
var cleanups = [];
// Page Load Delay - controls floating button appearance
if ((_a = triggers.pageLoadDelay) === null || _a === void 0 ? void 0 : _a.enabled) {
console.log('⏰ Page Load Delay enabled:', triggers.pageLoadDelay);
setShowFloatingButton(false); // Hide button initially
var timeout_1 = setTimeout(function () {
console.log('⏰ Page Load Delay timeout fired');
if (localStorage.getItem("feedback_widget_dismissed_".concat(workspace)) === 'true') {
console.log('❌ Widget dismissed during page load delay');
return;
}
console.log('✅ Setting page load delay trigger');
setTriggeredBy('page_load_delay');
setShowFloatingButton(true); // Show button after delay
}, (triggers.pageLoadDelay.delay || 5) * 1000);
cleanups.push(function () { return clearTimeout(timeout_1); });
}
// Time on Page - shows feedback prompt after time
if ((_b = triggers.timeOnPage) === null || _b === void 0 ? void 0 : _b.enabled) {
console.log('⏱️ Time on Page enabled:', triggers.timeOnPage);
var timeout_2 = setTimeout(function () {
console.log('⏱️ Time on Page timeout fired');
if (localStorage.getItem("feedback_widget_dismissed_".concat(workspace)) === 'true') {
console.log('❌ Widget dismissed during time on page');
return;
}
console.log('✅ Setting time on page trigger');
setTriggeredBy('time_on_page');
setShowFeedbackPrompt(true);
}, (triggers.timeOnPage.seconds || 30) * 1000);
cleanups.push(function () { return clearTimeout(timeout_2); });
}
// Scroll Percentage - shows feedback prompt on scroll
if ((_c = triggers.scrollPercentage) === null || _c === void 0 ? void 0 : _c.enabled) {
console.log('📜 Scroll Percentage enabled:', triggers.scrollPercentage);
var handleScroll_1 = function () {
var _a, _b;
if (localStorage.getItem("feedback_widget_dismissed_".concat(workspace)) === 'true') {
console.log('❌ Widget dismissed during scroll');
return;
}
var scrollPercent = (window.scrollY / (document.documentElement.scrollHeight - window.innerHeight)) * 100;
console.log('📜 Scroll percent:', scrollPercent, 'target:', ((_a = triggers.scrollPercentage) === null || _a === void 0 ? void 0 : _a.percentage) || 50);
if (scrollPercent >= (((_b = triggers.scrollPercentage) === null || _b === void 0 ? void 0 : _b.percentage) || 50)) {
console.log('✅ Setting scroll percentage trigger');
setTriggeredBy('scroll_percentage');
setShowFeedbackPrompt(true);
window.removeEventListener('scroll', handleScroll_1);
}
};
window.addEventListener('scroll', handleScroll_1);
cleanups.push(function () { return window.removeEventListener('scroll', handleScroll_1); });
}
// Visit Count - shows feedback prompt after X visits
if ((_d = triggers.visitCount) === null || _d === void 0 ? void 0 : _d.enabled) {
console.log('👥 Visit Count enabled:', triggers.visitCount);
var visitKey = "feedback_widget_visits_".concat(workspace);
var currentVisits = parseInt(localStorage.getItem(visitKey) || '0') + 1;
localStorage.setItem(visitKey, currentVisits.toString());
console.log('👥 Current visits:', currentVisits, 'target:', ((_e = triggers.visitCount) === null || _e === void 0 ? void 0 : _e.count) || 3);
if (currentVisits >= (((_f = triggers.visitCount) === null || _f === void 0 ? void 0 : _f.count) || 3)) {
console.log('✅ Setting visit count trigger');
setTriggeredBy('visit_count');
setShowFeedbackPrompt(true);
}
}
// Exit Intent - shows feedback prompt when mouse leaves
if ((_g = triggers.exitIntent) === null || _g === void 0 ? void 0 : _g.enabled) {
console.log('🚪 Exit Intent enabled:', triggers.exitIntent);
var handleMouseLeave_1 = function (e) {
console.log('🚪 Mouse leave event:', e.clientY);
if (e.clientY <= 0) {
if (localStorage.getItem("feedback_widget_dismissed_".concat(workspace)) === 'true') {
console.log('❌ Widget dismissed during exit intent');
return;
}
if (sessionStorage.getItem("exit_intent_triggered_".concat(workspace)) === 'true') {
console.log('❌ Exit intent already triggered');
return;
}
console.log('✅ Setting exit intent trigger');
setTimeout(function () {
setTriggeredBy('exit_intent');
setShowFeedbackPrompt(true);
sessionStorage.setItem("exit_intent_triggered_".concat(workspace), 'true');
}, triggers.exitIntent.delay || 150);
}
};
document.addEventListener('mouseleave', handleMouseLeave_1);
cleanups.push(function () { return document.removeEventListener('mouseleave', handleMouseLeave_1); });
}
// Idle Time - shows feedback prompt after idle
if ((_h = triggers.idleTime) === null || _h === void 0 ? void 0 : _h.enabled) {
console.log('😴 Idle Time enabled:', triggers.idleTime);
var idleTimer_1;
var resetIdleTimer_1 = function () {
var _a;
clearTimeout(idleTimer_1);
idleTimer_1 = setTimeout(function () {
console.log('😴 Idle timer fired');
if (localStorage.getItem("feedback_widget_dismissed_".concat(workspace)) === 'true') {
console.log('❌ Widget dismissed during idle');
return;
}
console.log('✅ Setting idle time trigger');
setTriggeredBy('idle_time');
setShowFeedbackPrompt(true);
}, (((_a = triggers.idleTime) === null || _a === void 0 ? void 0 : _a.seconds) || 60) * 1000);
};
var events_1 = ['mousemove', 'mousedown', 'keypress', 'scroll', 'touchstart', 'click'];
events_1.forEach(function (event) { return document.addEventListener(event, resetIdleTimer_1); });
resetIdleTimer_1();
cleanups.push(function () {
clearTimeout(idleTimer_1);
events_1.forEach(function (event) { return document.removeEventListener(event, resetIdleTimer_1); });
});
}
return function () {
cleanups.forEach(function (cleanup) { return cleanup(); });
};
}, [config, loading, workspace]);
var handleChange = function (id, value) {
setAnswers(function (prev) {
var _a;
return (__assign(__assign({}, prev), (_a = {}, _a[id] = value, _a)));
});
};
var normalizeRating = function (rating, maxRating) {
return Math.round((rating / maxRating) * 10);
};
var handleSubmit = function (e) { return __awaiter(void 0, void 0, void 0, function () {
var featureRequest, featureQuestion, response, responseData, error_2;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
e.preventDefault();
setSubmitting(true);
_a.label = 1;
case 1:
_a.trys.push([1, 6, 7, 8]);
featureRequest = null;
if (config === null || config === void 0 ? void 0 : config.questions) {
featureQuestion = config.questions.find(function (q) { return q.type === 'FeatureRequest'; });
if (featureQuestion && answers[featureQuestion.id]) {
featureRequest = answers[featureQuestion.id];
}
}
return [4 /*yield*/, fetch("".concat(apiBase, "/submit-feedback"), {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
workspace: workspace,
answers: Object.fromEntries(Object.entries(answers).map(function (_a) {
var _b;
var key = _a[0], value = _a[1];
// Normalize ratings to 1-10 scale
var question = (_b = config === null || config === void 0 ? void 0 : config.questions) === null || _b === void 0 ? void 0 : _b.find(function (q) { return q.id === key; });
if ((question === null || question === void 0 ? void 0 : question.type) === 'rating' && typeof value === 'number') {
return [key, normalizeRating(value, question.max || 5)];
}
return [key, value];
})),
page_url: window.location.href,
user_agent: navigator.userAgent,
referrer: document.referrer,
triggered_by: triggeredBy,
feature_request: featureRequest
})
})];
case 2:
response = _a.sent();
if (!response.ok) return [3 /*break*/, 4];
return [4 /*yield*/, response.json()];
case 3:
responseData = _a.sent();
setSubmitted(true);
onFeedbackSubmit === null || onFeedbackSubmit === void 0 ? void 0 : onFeedbackSubmit(__assign(__assign({}, answers), { discount_code: responseData.discount_code }));
// Show discount code if available
if (responseData.discount_code) {
setDiscountCode(responseData.discount_code);
}
return [3 /*break*/, 5];
case 4: throw new Error('Failed to submit feedback');
case 5: return [3 /*break*/, 8];
case 6:
error_2 = _a.sent();
console.error('Error submitting feedback:', error_2);
setError('Failed to submit feedback. Please try again.');
return [3 /*break*/, 8];
case 7:
setSubmitting(false);
return [7 /*endfinally*/];
case 8: return [2 /*return*/];
}
});
}); };
var handleClose = function () {
console.log('❌ Widget closed');
setShowOverlay(false);
setShowOverlayWidget(false);
setShowFeedbackPrompt(false);
setShouldShow(false);
// Don't hide the floating button - it should stay visible
onWidgetHide === null || onWidgetHide === void 0 ? void 0 : onWidgetHide();
};
var showWidget = function () {
console.log('🖱️ Manual widget click');
setTriggeredBy('manual');
setHasInteracted(true); // Mark as interacted
// Manual clicks go directly to the form
setShowOverlayWidget(true);
onWidgetShow === null || onWidgetShow === void 0 ? void 0 : onWidgetShow();
};
var colors = (config === null || config === void 0 ? void 0 : config.colors) || {};
// Position styles for floating button
var getPositionStyles = function () {
var baseStyles = {
position: 'fixed',
zIndex: 9999,
};
switch (position) {
case 'bottom-left':
return __assign(__assign({}, baseStyles), { bottom: '20px', left: '20px' });
case 'top-right':
return __assign(__assign({}, baseStyles), { top: '20px', right: '20px' });
case 'top-left':
return __assign(__assign({}, baseStyles), { top: '20px', left: '20px' });
default: // bottom-right
return __assign(__assign({}, baseStyles), { bottom: '20px', right: '20px' });
}
};
// Position styles for widget popup
var getWidgetPositionStyles = function () {
var baseStyles = {
position: 'fixed',
zIndex: 10000,
};
switch (position) {
case 'bottom-left':
return __assign(__assign({}, baseStyles), { bottom: '90px', left: '20px' });
case 'top-right':
return __assign(__assign({}, baseStyles), { top: '90px', right: '20px' });
case 'top-left':
return __assign(__assign({}, baseStyles), { top: '90px', left: '20px' });
default: // bottom-right
return __assign(__assign({}, baseStyles), { bottom: '90px', right: '20px' });
}
};
if (loading) {
return null; // Don't show anything while loading
}
if (!config) {
return null; // Don't show anything if no config
}
// Floating button
var floatingButton = showFloatingButton ? (_jsx("div", { onClick: showWidget, style: __assign(__assign({ width: 60, height: 60, borderRadius: '50%', background: colors.floatingButton || '#1976d2', color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 24, cursor: 'pointer', boxShadow: '0 4px 12px rgba(0,0,0,0.15)', transition: 'transform 0.2s', border: 'none' }, getPositionStyles()), style), className: className, children: colors.floatingButtonIcon || '💬' })) : null;
// Widget form
var widgetForm = (_jsx("div", { className: "feedback-widget-scroll", style: __assign({ maxWidth: '350px', width: '320px', maxHeight: '400px', overflow: 'auto' }, getWidgetPositionStyles()), children: _jsx("div", { style: {
background: colors.background || '#fff',
borderRadius: 16,
boxShadow: '0 8px 32px rgba(0,0,0,0.15)',
border: '1px solid #e0e0e0',
padding: 24,
fontFamily: 'Inter, Arial, sans-serif'
}, children: submitted ? (_jsxs("div", { style: { textAlign: 'center' }, children: [_jsx("div", { style: { fontSize: 48, marginBottom: 16 }, children: "\uD83C\uDF89" }), _jsx("h3", { style: { color: colors.titleText || '#222', marginBottom: 16 }, children: "Thank you for your feedback!" }), discountCode && (_jsx("div", { style: {
background: '#f0f8ff',
padding: 16,
borderRadius: 8,
marginBottom: 16
}, children: _jsxs("p", { style: { margin: 0, color: '#1976d2' }, children: ["Use code: ", _jsx("strong", { children: discountCode })] }) })), _jsx("button", { onClick: handleClose, style: {
background: colors.button || '#1976d2',
color: colors.buttonText || '#fff',
border: '1px solid #a0a0a0',
borderBottom: '3px solid #a0a0a0',
borderRadius: 8,
padding: '12px 24px',
fontWeight: 600,
fontSize: 16,
cursor: 'pointer'
}, children: "Close" })] })) : (_jsxs("form", { onSubmit: handleSubmit, children: [config.showHeader && (_jsxs("div", { style: {
background: colors.headerBackground || '#1976d2',
margin: -24,
marginBottom: 24,
padding: 20,
borderRadius: '16px 16px 0 0',
display: 'flex',
alignItems: 'center',
gap: 12
}, children: [config.showBrandLogo && config.brandLogo && (_jsx("img", { src: config.brandLogo, alt: "Logo", style: { width: 32, height: 32, borderRadius: 4 } })), config.showBrandName && config.brandName && (_jsx("span", { style: {
color: colors.brandNameColor || '#fff',
fontWeight: 600,
fontSize: 18
}, children: config.brandName }))] })), _jsxs("div", { style: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 24
}, children: [_jsx("h3", { style: {
color: colors.titleText || '#222',
fontSize: 20,
fontWeight: 600,
margin: 0
}, children: config.title }), _jsx("button", { onClick: handleClose, style: {
background: 'none',
border: 'none',
fontSize: 20,
cursor: 'pointer',
color: '#666',
padding: 4,
borderRadius: 4,
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}, title: "Close", children: "\u2715" })] }), (_b = config.questions) === null || _b === void 0 ? void 0 : _b.map(function (question) { return (_jsxs("div", { style: { marginBottom: 20 }, children: [_jsx("label", { style: {
display: 'block',
marginBottom: 8,
fontWeight: 500,
color: colors.labelText || '#333',
fontSize: 14
}, children: question.label }), question.type === 'rating' && (_jsx("div", { style: { display: 'flex', gap: 4 }, children: Array.from({ length: question.max || 5 }, function (_, i) { return (_jsx("button", { type: "button", onClick: function () { return handleChange(question.id, i + 1); }, style: {
background: 'none',
border: 'none',
fontSize: 24,
color: (answers[question.id] || 0) >= i + 1 ? '#ffd700' : '#ddd',
cursor: 'pointer',
padding: 4
}, children: "\u2605" }, i + 1)); }) })), question.type === 'text' && (_jsx("textarea", { value: answers[question.id] || '', onChange: function (e) { return handleChange(question.id, e.target.value); }, rows: question.rows || 3, placeholder: "Your feedback...", style: {
width: '100%',
padding: 12,
borderRadius: 8,
border: '1px solid #ddd',
background: colors.fieldBackground || '#fff',
color: colors.fieldText || '#333',
fontSize: 14,
fontFamily: 'inherit',
resize: 'vertical'
} })), question.type === 'FeatureRequest' && (_jsx("textarea", { value: answers[question.id] || '', onChange: function (e) { return handleChange(question.id, e.target.value); }, rows: 3, placeholder: "Describe the feature you'd like to see...", style: {
width: '100%',
padding: 12,
borderRadius: 8,
border: '1px solid #ddd',
background: colors.fieldBackground || '#fff',
color: colors.fieldText || '#333',
fontSize: 14,
fontFamily: 'inherit',
resize: 'vertical'
} }))] }, question.id)); }), error && (_jsx("div", { style: {
color: '#d32f2f',
marginBottom: 16,
fontSize: 14
}, children: error })), _jsxs("div", { style: { display: 'flex', gap: 12 }, children: [_jsx("button", { type: "submit", disabled: submitting, style: {
background: colors.button || '#1976d2',
color: colors.buttonText || '#fff',
border: '1px solid #a0a0a0',
borderBottom: '3px solid #a0a0a0',
borderRadius: 8,
padding: '12px 24px',
fontWeight: 600,
fontSize: 16,
cursor: submitting ? 'not-allowed' : 'pointer',
opacity: submitting ? 0.7 : 1
}, children: submitting ? 'Submitting...' : 'Submit Feedback' }), _jsx("button", { type: "button", onClick: handleClose, style: {
background: '#6c757d',
color: '#fff',
border: '1px solid #a0a0a0',
borderBottom: '3px solid #a0a0a0',
borderRadius: 8,
padding: '12px 24px',
fontWeight: 600,
fontSize: 16,
cursor: 'pointer'
}, children: "Cancel" })] })] })) }) }));
// Overlay mode
if (config.displayMode === 'overlay') {
return (_jsxs(_Fragment, { children: [_jsx("style", { children: "\n .feedback-widget-scroll::-webkit-scrollbar {\n width: 6px;\n }\n .feedback-widget-scroll::-webkit-scrollbar-track {\n background: transparent;\n }\n .feedback-widget-scroll::-webkit-scrollbar-thumb {\n background: #c1c1c1;\n border-radius: 3px;\n }\n .feedback-widget-scroll::-webkit-scrollbar-thumb:hover {\n background: #a8a8a8;\n }\n .feedback-widget-scroll {\n scrollbar-width: thin;\n scrollbar-color: #c1c1c1 transparent;\n }\n " }), floatingButton, showOverlayWidget && widgetForm, console.log('🎯 Rendering feedback prompt:', showFeedbackPrompt), showFeedbackPrompt && (_jsx("div", { style: __assign({ maxWidth: '280px', width: '280px' }, getWidgetPositionStyles()), children: _jsxs("div", { style: {
background: colors.background || '#fff',
border: '1px solid #e0e0e0',
borderRadius: 16,
boxShadow: '0 8px 32px rgba(0,0,0,0.15)',
padding: 20,
fontFamily: 'Inter, Arial, sans-serif',
}, children: [_jsx("div", { style: {
fontWeight: 600,
fontSize: 16,
color: colors.titleText || '#222',
marginBottom: 16,
textAlign: 'center',
}, children: "Would you like to give feedback?" }), _jsxs("div", { style: {
display: 'flex',
gap: 8,
justifyContent: 'center',
}, children: [_jsx("button", { onClick: function () {
setShowFeedbackPrompt(false);
setHasInteracted(true); // Mark as interacted
setShowOverlayWidget(true);
}, style: {
background: colors.button || '#1976d2',
color: colors.buttonText || '#fff',
border: '1px solid #a0a0a0',
borderBottom: '3px solid #a0a0a0',
borderRadius: 8,
padding: '8px 16px',
fontWeight: 600,
fontSize: 14,
cursor: 'pointer'
}, children: "Yes" }), _jsx("button", { onClick: function () {
setShowFeedbackPrompt(false);
setHasInteracted(true); // Mark as interacted
localStorage.setItem("feedback_widget_dismissed_".concat(workspace), 'true');
}, style: {
background: '#6c757d',
color: '#fff',
border: '1px solid #a0a0a0',
borderBottom: '3px solid #a0a0a0',
borderRadius: 8,
padding: '8px 16px',
fontWeight: 600,
fontSize: 14,
cursor: 'pointer'
}, children: "No" })] })] }) }))] }));
}
// Inline mode
if (config.displayMode === 'inline') {
return (_jsxs(_Fragment, { children: [showFeedbackPrompt && (_jsx("div", { style: {
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
zIndex: 10000,
maxWidth: '280px',
width: 'fit-content',
}, children: _jsxs("div", { style: {
background: colors.background || '#fff',
border: '1px solid #e0e0e0',
borderRadius: 16,
boxShadow: '0 8px 32px rgba(0,0,0,0.15)',
padding: 20,
fontFamily: 'Inter, Arial, sans-serif',
}, children: [_jsx("div", { style: {
fontWeight: 600,
fontSize: 16,
color: colors.titleText || '#222',
marginBottom: 16,
textAlign: 'center',
}, children: "Would you like to give feedback?" }), _jsxs("div", { style: {
display: 'flex',
gap: 8,
justifyContent: 'center',
}, children: [_jsx("button", { onClick: function () {
setShowFeedbackPrompt(false);
setHasInteracted(true); // Mark as interacted
setShouldShow(true);
}, style: {
background: colors.button || '#1976d2',
color: colors.buttonText || '#fff',
border: '1px solid #a0a0a0',
borderBottom: '3px solid #a0a0a0',
borderRadius: 8,
padding: '8px 16px',
fontWeight: 600,
fontSize: 14,
cursor: 'pointer'
}, children: "Yes" }), _jsx("button", { onClick: function () {
setShowFeedbackPrompt(false);
setHasInteracted(true); // Mark as interacted
localStorage.setItem("feedback_widget_dismissed_".concat(workspace), 'true');
}, style: {
background: '#6c757d',
color: '#fff',
border: '1px solid #a0a0a0',
borderBottom: '3px solid #a0a0a0',
borderRadius: 8,
padding: '8px 16px',
fontWeight: 600,
fontSize: 14,
cursor: 'pointer'
}, children: "No" })] })] }) })), shouldShow && widgetForm] }));
}
// Default fallback - just show the floating button
return floatingButton;
};
export default FeedbackWidget;
// Export for Next.js/React usage
export { FeedbackWidget };
// UMD global export for script tag usage (backward compatibility)
if (typeof window !== 'undefined') {
window.FeedbackWidget = FeedbackWidget;
}