2023-11-01 13:54:19 +00:00
|
|
|
import {logTelemetryEvent} from 'app/client/lib/telemetry';
|
2023-06-06 17:08:50 +00:00
|
|
|
import {AppModel} from 'app/client/models/AppModel';
|
|
|
|
import {bigBasicButton, bigPrimaryButtonLink} from 'app/client/ui2018/buttons';
|
|
|
|
import {testId, theme, vars} from 'app/client/ui2018/cssVars';
|
|
|
|
import {cardPopup, cssPopupBody, cssPopupButtons, cssPopupCloseButton,
|
|
|
|
cssPopupTitle} from 'app/client/ui2018/popups';
|
|
|
|
import {icon} from 'app/client/ui2018/icons';
|
|
|
|
import {getGristConfig} from 'app/common/urlUtils';
|
|
|
|
import {dom, styled} from 'grainjs';
|
2024-02-07 16:53:48 +00:00
|
|
|
import { makeT } from '../lib/localization';
|
2023-06-06 17:08:50 +00:00
|
|
|
|
2024-02-07 16:53:48 +00:00
|
|
|
const t = makeT('WelcomeCoachingCall');
|
2023-06-06 17:08:50 +00:00
|
|
|
|
|
|
|
export function shouldShowWelcomeCoachingCall(appModel: AppModel) {
|
|
|
|
const {deploymentType} = getGristConfig();
|
|
|
|
if (deploymentType !== 'saas') { return false; }
|
|
|
|
|
|
|
|
// Defer showing coaching call until Add New tip is dismissed.
|
2023-10-30 03:21:28 +00:00
|
|
|
const {behavioralPromptsManager, dismissedWelcomePopups} = appModel;
|
|
|
|
if (behavioralPromptsManager.shouldShowTip('addNew')) { return false; }
|
2023-06-06 17:08:50 +00:00
|
|
|
|
|
|
|
const popup = dismissedWelcomePopups.get().find(p => p.id === 'coachingCall');
|
|
|
|
return (
|
|
|
|
// Only show if the user is an owner.
|
|
|
|
appModel.isOwner() && (
|
|
|
|
// And preferences for the popup haven't been saved before.
|
|
|
|
popup === undefined ||
|
|
|
|
// Or the popup has been shown before, and it's time to shown it again.
|
|
|
|
popup.nextAppearanceAt !== null && popup.nextAppearanceAt <= Date.now()
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Shows a popup with an offer for a free coaching call.
|
|
|
|
*/
|
|
|
|
export function showWelcomeCoachingCall(triggerElement: Element, appModel: AppModel) {
|
|
|
|
const {dismissedWelcomePopups} = appModel;
|
|
|
|
|
|
|
|
cardPopup(triggerElement, (ctl) => {
|
|
|
|
const dismissPopup = (scheduleNextAppearance?: boolean) => {
|
|
|
|
const dismissedPopups = dismissedWelcomePopups.get();
|
|
|
|
const newDismissedPopups = [...dismissedPopups];
|
|
|
|
const coachingPopup = newDismissedPopups.find(p => p.id === 'coachingCall');
|
|
|
|
if (!coachingPopup) {
|
|
|
|
newDismissedPopups.push({
|
|
|
|
id: 'coachingCall',
|
|
|
|
lastDismissedAt: Date.now(),
|
|
|
|
timesDismissed: 1,
|
|
|
|
nextAppearanceAt: scheduleNextAppearance
|
|
|
|
? new Date().setDate(new Date().getDate() + 7)
|
|
|
|
: null,
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
Object.assign(coachingPopup, {
|
|
|
|
lastDismissedAt: Date.now(),
|
|
|
|
timesDismissed: coachingPopup.timesDismissed + 1,
|
|
|
|
nextAppearanceAt: scheduleNextAppearance && coachingPopup.timesDismissed + 1 <= 1
|
|
|
|
? new Date().setDate(new Date().getDate() + 7)
|
|
|
|
: null,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
dismissedWelcomePopups.set(newDismissedPopups);
|
|
|
|
ctl.close();
|
|
|
|
};
|
|
|
|
|
|
|
|
return [
|
|
|
|
cssPopup.cls(''),
|
|
|
|
cssPopupHeader(
|
|
|
|
cssLogoAndName(
|
|
|
|
cssLogo(),
|
|
|
|
cssName('Grist'),
|
|
|
|
),
|
|
|
|
cssPopupCloseButton(
|
|
|
|
cssCloseIcon('CrossBig'),
|
|
|
|
dom.on('click', () => dismissPopup(true)),
|
|
|
|
testId('popup-close-button'),
|
|
|
|
),
|
|
|
|
),
|
2024-02-07 16:53:48 +00:00
|
|
|
cssPopupTitle(t('free coaching call'),
|
|
|
|
dom.style('text-transform', 'capitalize'),
|
|
|
|
testId('popup-title')
|
|
|
|
),
|
2023-06-06 17:08:50 +00:00
|
|
|
cssPopupBody(
|
|
|
|
cssBody(
|
|
|
|
dom('div',
|
2024-02-07 16:53:48 +00:00
|
|
|
t('Schedule your {{freeCoachingCall}} with a member of our team.',
|
|
|
|
{freeCoachingCall: cssBoldText(t('free coaching call'))}
|
|
|
|
)
|
2023-06-06 17:08:50 +00:00
|
|
|
),
|
|
|
|
dom('div',
|
2024-02-07 16:53:48 +00:00
|
|
|
t("On the call, we'll take the time to understand your needs and tailor the call to you. \
|
|
|
|
We can show you the Grist basics, or start working with your data right away to build the dashboards you need.")
|
2023-06-06 17:08:50 +00:00
|
|
|
),
|
|
|
|
),
|
|
|
|
testId('popup-body'),
|
|
|
|
),
|
|
|
|
cssPopupButtons(
|
|
|
|
bigPrimaryButtonLink(
|
2024-02-07 16:53:48 +00:00
|
|
|
t('Schedule Call'),
|
2023-11-01 13:54:19 +00:00
|
|
|
dom.on('click', () => {
|
|
|
|
dismissPopup(false);
|
|
|
|
logTelemetryEvent('clickedScheduleCoachingCall');
|
|
|
|
}),
|
2023-06-06 17:08:50 +00:00
|
|
|
{
|
2024-02-07 16:53:48 +00:00
|
|
|
href: getGristConfig().freeCoachingCallUrl,
|
2023-06-06 17:08:50 +00:00
|
|
|
target: '_blank',
|
|
|
|
},
|
|
|
|
testId('popup-primary-button'),
|
|
|
|
),
|
|
|
|
bigBasicButton(
|
2024-02-07 16:53:48 +00:00
|
|
|
t('Maybe Later'),
|
2023-06-06 17:08:50 +00:00
|
|
|
dom.on('click', () => dismissPopup(true)),
|
|
|
|
testId('popup-basic-button'),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
testId('coaching-call'),
|
|
|
|
];
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
const cssBody = styled('div', `
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
row-gap: 16px;
|
|
|
|
`);
|
|
|
|
|
|
|
|
const cssBoldText = styled('span', `
|
|
|
|
font-weight: 600;
|
|
|
|
`);
|
|
|
|
|
|
|
|
const cssCloseIcon = styled(icon, `
|
|
|
|
padding: 12px;
|
|
|
|
`);
|
|
|
|
|
|
|
|
const cssName = styled('div', `
|
|
|
|
color: ${theme.popupCloseButtonFg};
|
|
|
|
font-size: ${vars.largeFontSize};
|
|
|
|
font-weight: 600;
|
|
|
|
`);
|
|
|
|
|
|
|
|
const cssLogo = styled('div', `
|
|
|
|
flex: none;
|
|
|
|
height: 32px;
|
|
|
|
width: 32px;
|
|
|
|
background-image: var(--icon-GristLogo);
|
|
|
|
background-size: ${vars.logoSize};
|
|
|
|
background-repeat: no-repeat;
|
|
|
|
background-position: center;
|
|
|
|
`);
|
|
|
|
|
|
|
|
const cssLogoAndName = styled('div', `
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
gap: 4px;
|
|
|
|
`);
|
|
|
|
|
|
|
|
const cssPopup = styled('div', `
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
`);
|
|
|
|
|
|
|
|
const cssPopupHeader = styled('div', `
|
|
|
|
display: flex;
|
|
|
|
justify-content: space-between;
|
|
|
|
margin-bottom: 16px;
|
|
|
|
`);
|