diff --git a/packages/builder/src/analytics.js b/packages/builder/src/analytics.js index 60a41e42c2..a7166f00f6 100644 --- a/packages/builder/src/analytics.js +++ b/packages/builder/src/analytics.js @@ -6,6 +6,10 @@ let analyticsEnabled const posthogConfigured = process.env.POSTHOG_TOKEN && process.env.POSTHOG_URL const sentryConfigured = process.env.SENTRY_DSN +const FEEDBACK_SUBMITTED_KEY = "budibase:feedback_submitted" +const APP_FIRST_STARTED_KEY = "budibase:first_run" +const feedbackHours = 12 + async function activate() { if (analyticsEnabled === undefined) { // only the server knows the true NODE_ENV @@ -62,10 +66,50 @@ function captureEvent(eventName, props = {}) { posthog.capture(eventName, props) } +if (!localStorage.getItem(APP_FIRST_STARTED_KEY)) { + localStorage.setItem(APP_FIRST_STARTED_KEY, Date.now()) +} + +const isFeedbackTimeElapsed = sinceDateStr => { + const sinceDate = parseFloat(sinceDateStr) + const feedbackMilliseconds = feedbackHours * 60 * 60 * 1000 + return Date.now() > sinceDate + feedbackMilliseconds +} +function submitFeedback(values) { + if (!analyticsEnabled || !process.env.POSTHOG_TOKEN) return + localStorage.setItem(FEEDBACK_SUBMITTED_KEY, Date.now()) + + const prefixedValues = Object.entries(values).reduce((obj, [key, value]) => { + obj[`feedback_${key}`] = value + return obj + }, {}) + + posthog.capture("Feedback Submitted", prefixedValues) +} + +function requestFeedbackOnDeploy() { + if (!analyticsEnabled || !process.env.POSTHOG_TOKEN) return false + const lastSubmittedStr = localStorage.getItem(FEEDBACK_SUBMITTED_KEY) + if (!lastSubmittedStr) return true + return isFeedbackTimeElapsed(lastSubmittedStr) +} + +function highlightFeedbackIcon() { + if (!analyticsEnabled || !process.env.POSTHOG_TOKEN) return false + const lastSubmittedStr = localStorage.getItem(FEEDBACK_SUBMITTED_KEY) + if (lastSubmittedStr) return isFeedbackTimeElapsed(lastSubmittedStr) + const firstRunStr = localStorage.getItem(APP_FIRST_STARTED_KEY) + if (!firstRunStr) return false + return isFeedbackTimeElapsed(firstRunStr) +} + export default { activate, identify, identifyByApiKey, captureException, captureEvent, + requestFeedbackOnDeploy, + submitFeedback, + highlightFeedbackIcon, } diff --git a/packages/builder/src/components/userInterface/Feedback/FeedbackIframe.svelte b/packages/builder/src/components/userInterface/Feedback/FeedbackIframe.svelte index 0de129ff80..17c6059de4 100644 --- a/packages/builder/src/components/userInterface/Feedback/FeedbackIframe.svelte +++ b/packages/builder/src/components/userInterface/Feedback/FeedbackIframe.svelte @@ -1,6 +1,7 @@ - + @@ -32,4 +43,12 @@ color: var(--ink); font-weight: 500; } + + .highlight { + color: var(--blue); + } + + .highlight > :global(svg) { + filter: drop-shadow(0 0 20px var(--blue)); + } diff --git a/packages/builder/src/pages/[application]/deploy/index.svelte b/packages/builder/src/pages/[application]/deploy/index.svelte index 691e039e38..b2ee0e8fdb 100644 --- a/packages/builder/src/pages/[application]/deploy/index.svelte +++ b/packages/builder/src/pages/[application]/deploy/index.svelte @@ -33,7 +33,10 @@ analytics.captureEvent("Deployed App", { appId, }) - feedbackModal.show() + + if (analytics.requestFeedbackOnDeploy()) { + feedbackModal.show() + } } catch (err) { analytics.captureEvent("Deploy App Failed", { appId, @@ -61,7 +64,7 @@ alt="Rocket flying through sky" /> - + feedbackModal.hide()} />