@crazy-web/feedback
Version:
A feedback form handler package that shows a popup based on allowed URLs.
427 lines (388 loc) • 15.3 kB
JavaScript
;
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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.openFeedbackSlider = openFeedbackSlider;
const closeIcon_1 = require("../components/reuseables/closeIcon");
const feedbackDetails_1 = require("../components/feedbackDetails");
const ideas_1 = require("../components/ideas");
const config_1 = require("../core/lib/config");
const announcementsIcon_1 = require("../components/reuseables/announcementsIcon");
const whiteLabel_1 = require("./whiteLabel");
const ideasIcon_1 = require("../components/reuseables/ideasIcon");
const announcement_1 = require("../components/announcement");
const mdxStyles_1 = require("../components/reuseables/mdxStyles");
const roadMap_1 = require("../components/roadMap");
const roadMapIcon_1 = require("../components/reuseables/roadMapIcon");
const checkIsDarkMode_1 = require("../components/reuseables/checkIsDarkMode");
/**
* Fetches feedbacks from the server.
*/
let selectedCard = null;
/**
* Displays a feedback slider with form fields.
*/
function openFeedbackSlider(data) {
return __awaiter(this, void 0, void 0, function* () {
if (document.getElementById("custom-slider-overlay"))
return; // Avoid duplicate sliders
const { orgData, config } = data;
const { primaryColor = config_1.configData === null || config_1.configData === void 0 ? void 0 : config_1.configData.primaryColor, heading = config_1.configData.heading, theme = config_1.configData.theme } = config !== null && config !== void 0 ? config : {};
const { ideas = config_1.configData.heading.ideas, announcement = config_1.configData.heading.announcement, roadMap = config_1.configData.heading.roadMap } = heading !== null && heading !== void 0 ? heading : {};
const accountId = orgData === null || orgData === void 0 ? void 0 : orgData.organizationId;
const isDarkMode = (0, checkIsDarkMode_1.checkIsDarkMode)({ theme });
const backgroundColor = isDarkMode ? "#1B1D21" : "#F8F9FA";
const textColor = "#000";
// Create the overlay
const overlay = document.createElement("div");
overlay.id = "custom-slider-overlay";
overlay.style.position = "fixed";
overlay.style.top = "0";
overlay.style.left = "0";
overlay.style.width = "100%";
overlay.style.height = "100%";
overlay.style.backgroundColor = "rgba(0, 0, 0, 0.5)";
overlay.style.zIndex = "9999998";
const slider = document.createElement("div");
slider.id = "prodio-slider";
slider.style.display = "flex";
slider.style.flexDirection = "column";
slider.style.gap = "12px";
slider.style.position = "fixed";
slider.style.zIndex = "9999999";
slider.style.top = "0%";
slider.style.right = "0%";
slider.style.height = "100%";
slider.style.backgroundColor = backgroundColor;
slider.style.color = textColor;
slider.style.padding = "90px 15px 100px 15px";
slider.style.borderRadius = "0px";
slider.style.width = "90%";
slider.style.maxWidth = "400px";
slider.style.fontFamily = "'Inter', sans-serif";
slider.style.animation = "slideIn 0.5s ease-in-out forwards"; // Apply animation
const renderHeader = (heading) => {
// background-color:${primaryColor}
const headingBgColor = isDarkMode ? "#414549" : "#E5E7EB";
const headingTextColor = isDarkMode ? "#E4E4E4CC" : "#374151";
const bottomBorderColor = isDarkMode ? "#292B2F" : "#E5E7EB";
return `
<div style="border-bottom:1px solid ${bottomBorderColor};color:white;position:fixed;top:0;width:400px;display:flex;justify-content:space-between;align-items:center;padding:20px 20px; margin: 0px -15px;z-index:10;">
<h3 class="prodio-feedback-form-heading" style="margin: 0; padding: 4px 12px;border-radius:5px; background-color:${headingBgColor}; color:${headingTextColor};font-size:16px;">
${heading}
</h3>
<span id="slider-close-button" style="cursor: pointer;z-index: 25; width: max-content;">
${(0, closeIcon_1.renderCloseIcon)({ stroke: isDarkMode ? "#9FA1A7" : "#718096", size: "20" })}
</span>
</div>
`;
};
const addStyles = () => {
const styleElement = document.createElement("style");
styleElement.innerHTML = `
${(0, mdxStyles_1.addMDXStyles)()}
/* Loader Container */
.prodio-spinner-container {
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
width:100%;
height: -webkit-fill-available;
}
/* Spinner Animation */
.prodio-spinner {
width: 30px;
height: 30px;
border: 4px solid rgba(0, 0, 0, 0.1);
border-top-color: ${primaryColor}; /* Blue spinner */
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* No Data Found Message */
.prodio-no-data {
text-align: center;
font-size: 14px;
color: #999;
font-weight: normal;
padding: 20px;
height: -webkit-fill-available;
display: flex;
justify-content: center;
align-items: center;
}
@keyframes slideIn {
from {
transform: translateX(100%); /* Start off-screen */
}
to {
transform: translateX(0); /* Move into view */
}
}
@keyframes slideOut {
from {
transform: translateX(0);
}
to {
transform: translateX(100%); /* Move off-screen */
}
}
.prodioHideSlider {
animation: slideOut 0.5s ease-in-out forwards !important;
}
.prodio-feedback-hidden-scrollbar {
overflow-y: auto;
max-height: 100vh;
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* Internet Explorer & Edge */
}
/* Hide scrollbar for WebKit (Chrome, Safari) */
.prodio-feedback-hidden-scrollbar::-webkit-scrollbar {
display: none;
}
.prodio-ideas-card-comment-text{
opacity:0;
}
.prodio-feedback-card-animate:hover .prodio-ideas-card-comment-text{
opacity:1;
}
.prodio-feedback-card-description{
display: -webkit-box;
-webkit-line-clamp: 3; /* Limits text to 3 lines */
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
max-width: 280px;
margin:0;
}
.prodio-feedback-card-detail-title{
text-decoration:none;
font-size:17px;
color:#424242;
}
.prodio-feedback-card-title {
max-width: 280px; /* Adjust width based on your layout */
font-size:17px;
color:#347151;
}
.prodio-idea-comment-container:hover .prodio-idea-comment-delete-icon{
display:block
}
.prodio-idea-comment-delete-icon{
display:none
}
.prodio-feedback-form-container{
background-color: transparent;
padding:15px;
border-radius:5px;
margin-bottom:15px;
border:1px solid ${isDarkMode ? "#313337" : "#31333740"};
}
.prodio-feedback-form-heading {
font-size: 16px;
margin: 0;
}
@media screen and (max-width: 700px) {
.prodio-feedback-form-heading {
font-size: 16px;
}
}
.prodio-feedback-form-description {
font-size: 16px;
}
@media screen and (max-width: 700px) {
.prodio-feedback-form-description {
font-size: 12px;
}
}
/* Animation classes for card transitions */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.prodio-feedback-card-animate {
animation: fadeIn 0.4s ease-out forwards;
}
.prodio-tab-btn{
display:flex;
flex-direction:column;
justify-content:center;
align-items:center;
gap:5px;
font-size:12px;
cursor:pointer;
font-weight:bold;
padding:5px;
border-radius:5px;
}
.prodio-tab-btn:hover {
background-color:rgba(236,236,236,0.5)
}
.prodio-disabled-btn {
cursor: not-allowed !important; /* Show disabled cursor */
opacity: 0.6;
pointer-events: none; /* Prevent clicks */
border-radius:5px;
}
`;
document.head.appendChild(styleElement);
};
const removeStyles = () => {
const styles = document.head.getElementsByTagName("style");
for (let i = 0; i < styles.length; i++) {
if (styles[i].innerHTML.includes(".prodio-feedback")) {
styles[i].remove();
break;
}
}
};
const tabs = {
ideas: {
value: "ideas",
icon: (stroke) => (0, ideasIcon_1.renderIdeasIcon)({ stroke }),
label: "Feedback",
content: () => (0, ideas_1.ideasContainer)(data, selectedCard),
heading: ideas,
},
announcement: {
value: "announcement",
icon: (stroke) => (0, announcementsIcon_1.renderAnnouncementsIcon)({ stroke }),
label: "Announcements",
content: () => (0, announcement_1.announcementContainer)(data),
heading: announcement
},
roadMap: {
value: "roadMap",
icon: (stroke) => (0, roadMapIcon_1.renderRoadMapIcon)({ stroke }),
label: "Roadmap",
content: () => (0, roadMap_1.roadMapContainer)(data, selectedCard),
heading: roadMap,
}
};
const tabsArray = Object.keys(tabs).map((item) => (Object.assign({}, tabs[item])));
let selectedTab = "ideas";
function renderTabs() {
var _a;
const containerBg = isDarkMode ? "#222429" : "#fff";
const tabActiveColor = isDarkMode ? "#D2D3E0" : "#1D1D1D";
const tabActiveBgColor = isDarkMode ? "#52525B61" : "#E8E8E8";
const tabColor = isDarkMode ? "#5B5B60" : "#71809650";
const tabBorderColor = isDarkMode ? "none" : "1px solid #CFCFCF";
const whiteLabelColor = isDarkMode ? "#5B5B60" : "#5B5B60";
slider.innerHTML = selectedCard ? (0, feedbackDetails_1.renderFeedbackDetails)(selectedCard, data) : `
${renderHeader((_a = tabs[selectedTab]) === null || _a === void 0 ? void 0 : _a.heading)}
<div id="prodio-tab-content">
</div>
<div style="
position: fixed;
bottom: 0px;
background:${containerBg};
padding:20px 20px 5px 20px;
margin:0 0 0 -15px;
max-width: 400px;
width:100%;
">
<div id="tab-container" style="display:grid;grid-template-columns:repeat(${tabsArray.length},1fr);gap:5px;">
${tabsArray.map((tab) => `
<div class="prodio-tab-btn" data-tab="${tab.value}"
style="
color:${selectedTab === tab.value ? tabActiveColor : tabColor};
cursor: pointer;
background-color:${selectedTab === tab.value ? tabActiveBgColor : "transparent"};
border:${selectedTab === tab.value ? tabBorderColor : "none"};
">
<span> ${tab === null || tab === void 0 ? void 0 : tab.icon(selectedTab === tab.value ? tabActiveColor : tabColor)}</span>
<span>${tab.label}</span>
</div>
`).join("")}
</div>
<div style="display:flex; justify-content:end;width:100%; padding :5px 0 0 0;">
${(0, whiteLabel_1.whiteLabelRender)({ fontSize: "10px", color: whiteLabelColor })}
</div>
</div>
`;
setTimeout(() => {
const closeButton = document.getElementById("slider-close-button");
// Add click event to close button
if (closeButton) {
closeButton.addEventListener("click", (event) => {
closeSlider();
event.stopPropagation(); // Prevent event from bubbling up
});
}
}, 100);
}
// Attach a single event listener to the parent container
document.addEventListener('click', (event) => __awaiter(this, void 0, void 0, function* () {
var _a;
const tabBtn = event.target.closest('.prodio-tab-btn');
if (tabBtn) {
selectedTab = tabBtn.getAttribute('data-tab');
renderTabs(); // Re-render UI with new tab
(_a = tabs[selectedTab]) === null || _a === void 0 ? void 0 : _a.content();
// if (tabs[selectedTab]?.afterRender) {
// await tabs[selectedTab]?.afterRender()
// }
// await announcementContainer(data)
}
}));
setTimeout(() => {
var _a;
renderTabs();
(_a = tabs[selectedTab]) === null || _a === void 0 ? void 0 : _a.content();
}, 100);
addStyles();
// slider.appendChild(closeButton);
document.body.appendChild(overlay);
document.body.appendChild(slider);
document.body.style.overflow = "hidden";
// Function to close the slider
const closeSlider = () => {
slider.classList.add("prodioHideSlider"); // Add the hide animation class
// Wait for animation to complete before removing
setTimeout(() => {
slider.remove();
overlay.remove();
selectedCard = null; // Reset selectedCard when closing the slider
removeStyles();
document.body.removeEventListener("click", handleOutsideClick);
}, 500); // Adjust the timeout to match the animation duration
};
// setTimeout(() => {
// const closeButton = document.getElementById("slider-close-button")
// // Add click event to close button
// if (closeButton) {
// closeButton.addEventListener("click", (event) => {
// closeSlider();
// event.stopPropagation(); // Prevent event from bubbling up
// });
// }
// }, 100);
// Function to close the slider when clicking outside
const handleOutsideClick = (event) => {
if (!slider.contains(event.target)) {
closeSlider();
}
};
setTimeout(() => {
document.body.addEventListener("click", handleOutsideClick);
}, 100); // Small delay to prevent immediate closing when opening the slider
});
}