(core) Adding tutorial card

Summary:
For now only html stub and docList adjustement for showing a tutorial card.
It will be used in future diffs after tutorial implementation.

Test Plan: Manual

Reviewers: georgegevoian

Reviewed By: georgegevoian

Differential Revision: https://phab.getgrist.com/D3750
This commit is contained in:
Jarosław Sadziński
2023-03-28 18:11:40 +02:00
parent 6b5c178953
commit a317a727c8
20 changed files with 425 additions and 31 deletions

View File

@@ -21,7 +21,7 @@ import {getDefaultThemePrefs, Theme, ThemeAppearance, ThemeColors, ThemePrefs,
import {getThemeColors} from 'app/common/Themes';
import {getGristConfig} from 'app/common/urlUtils';
import {getOrgName, Organization, OrgError, UserAPI, UserAPIImpl} from 'app/common/UserAPI';
import {getUserPrefObs, getUserPrefsObs} from 'app/client/models/UserPrefs';
import {getUserPrefObs, getUserPrefsObs, markAsSeen, markAsUnSeen} from 'app/client/models/UserPrefs';
import {bundleChanges, Computed, Disposable, Observable, subscribe} from 'grainjs';
const t = makeT('AppModel');
@@ -111,6 +111,8 @@ export interface AppModel {
isSupport(): boolean; // If user is a Support user
isOwner(): boolean; // If user is an owner of this org
isOwnerOrEditor(): boolean; // If user is an owner or editor of this org
/** Creates an computed observable to dismiss a popup or check if it was dismissed */
dismissedPopup(name: DismissedPopup): Observable<boolean>;
}
export class TopAppModelImpl extends Disposable implements TopAppModel {
@@ -277,6 +279,10 @@ export class AppModelImpl extends Disposable implements AppModel {
urlState().pushUrl({createTeam: false, params: {}}, {avoidReload: true, replace: true}).catch(() => {});
this.showNewSiteModal(state.params?.planType);
}
G.window.resetSeenPopups = (seen = false) => {
this.dismissedPopups.set(seen ? DismissedPopup.values : []);
};
}
public get planName() {
@@ -337,6 +343,18 @@ export class AppModelImpl extends Disposable implements AppModel {
}
}
public dismissedPopup(name: DismissedPopup): Computed<boolean> {
const computed = Computed.create(null, use => use(this.dismissedPopups).includes(name));
computed.onWrite(value => {
if (value) {
markAsSeen(this.dismissedPopups, name);
} else {
markAsUnSeen(this.dismissedPopups, name);
}
});
return computed;
}
/**
* If the current user is a new user, record a sign-up event via Google Tag Manager.
*/

View File

@@ -98,3 +98,17 @@ export function markAsSeen<T>(seenIdsObs: Observable<T[] | undefined>, itemId: T
console.warn("Failed to save preference in markAsSeen", e);
}
}
export function markAsUnSeen<T>(seenIdsObs: Observable<T[] | undefined>, itemId: T) {
const seenIds = seenIdsObs.get() || [];
try {
if (seenIds.includes(itemId)) {
const seen = new Set(seenIds);
seen.delete(itemId);
seenIdsObs.set([...seen].sort());
}
} catch (e) {
// tslint:disable-next-line:no-console
console.warn("Failed to save preference in markAsUnSeen", e);
}
}