mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) Remove code for unused welcome flows
Summary: Removes code that was marked for removal. Test Plan: Existing tests still pass. Reviewers: paulfitz Reviewed By: paulfitz Differential Revision: https://phab.getgrist.com/D3289
This commit is contained in:
parent
83ba2957bf
commit
fa68b790bb
@ -7,7 +7,6 @@ import {MFAConfig} from 'app/client/ui/MFAConfig';
|
|||||||
import {pagePanels} from 'app/client/ui/PagePanels';
|
import {pagePanels} from 'app/client/ui/PagePanels';
|
||||||
import {createTopBarHome} from 'app/client/ui/TopBar';
|
import {createTopBarHome} from 'app/client/ui/TopBar';
|
||||||
import {transientInput} from 'app/client/ui/transientInput';
|
import {transientInput} from 'app/client/ui/transientInput';
|
||||||
import {buildNameWarningsDom, checkName} from 'app/client/ui/WelcomePage';
|
|
||||||
import {bigBasicButton, bigPrimaryButtonLink} from 'app/client/ui2018/buttons';
|
import {bigBasicButton, bigPrimaryButtonLink} from 'app/client/ui2018/buttons';
|
||||||
import {cssBreadcrumbs, cssBreadcrumbsLink, separator} from 'app/client/ui2018/breadcrumbs';
|
import {cssBreadcrumbs, cssBreadcrumbsLink, separator} from 'app/client/ui2018/breadcrumbs';
|
||||||
import {labeledSquareCheckbox} from 'app/client/ui2018/checkbox';
|
import {labeledSquareCheckbox} from 'app/client/ui2018/checkbox';
|
||||||
@ -218,6 +217,31 @@ function confirmPwdResetModal(userEmail: string) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We allow alphanumeric characters and certain common whitelisted characters (except at the start),
|
||||||
|
* plus everything non-ASCII (for non-English alphabets, which we want to allow but it's hard to be
|
||||||
|
* more precise about what exactly to allow).
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line no-control-regex
|
||||||
|
const VALID_NAME_REGEXP = /^(\w|[^\u0000-\u007F])(\w|[- ./'"()]|[^\u0000-\u007F])*$/;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test name against various rules to check if it is a valid username.
|
||||||
|
*/
|
||||||
|
export function checkName(name: string): boolean {
|
||||||
|
return VALID_NAME_REGEXP.test(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds dom to show marning messages to the user.
|
||||||
|
*/
|
||||||
|
function buildNameWarningsDom() {
|
||||||
|
return cssWarning(
|
||||||
|
"Names only allow letters, numbers and certain special characters",
|
||||||
|
testId('username-warning'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const cssContainer = styled('div', `
|
const cssContainer = styled('div', `
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@ -308,3 +332,7 @@ const cssEmail = styled('div', `
|
|||||||
const cssLoginMethod = styled(cssFlexGrow, `
|
const cssLoginMethod = styled(cssFlexGrow, `
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
const cssWarning = styled('div', `
|
||||||
|
color: red;
|
||||||
|
`);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Computed, Disposable, dom, domComputed, DomContents, input, MultiHolder, Observable, styled } from "grainjs";
|
import { Disposable, dom, domComputed, DomContents, input, MultiHolder, Observable, styled } from "grainjs";
|
||||||
|
|
||||||
import { handleSubmit, submitForm } from "app/client/lib/formUtils";
|
import { handleSubmit, submitForm } from "app/client/lib/formUtils";
|
||||||
import { AppModel, reportError } from "app/client/models/AppModel";
|
import { AppModel, reportError } from "app/client/models/AppModel";
|
||||||
@ -6,12 +6,11 @@ import { getLoginUrl, getSignupUrl, urlState } from "app/client/models/gristUrlS
|
|||||||
import { AccountWidget } from "app/client/ui/AccountWidget";
|
import { AccountWidget } from "app/client/ui/AccountWidget";
|
||||||
import { AppHeader } from 'app/client/ui/AppHeader';
|
import { AppHeader } from 'app/client/ui/AppHeader';
|
||||||
import * as BillingPageCss from "app/client/ui/BillingPageCss";
|
import * as BillingPageCss from "app/client/ui/BillingPageCss";
|
||||||
import * as forms from "app/client/ui/forms";
|
|
||||||
import { pagePanels } from "app/client/ui/PagePanels";
|
import { pagePanels } from "app/client/ui/PagePanels";
|
||||||
import { createUserImage } from 'app/client/ui/UserImage';
|
import { createUserImage } from 'app/client/ui/UserImage';
|
||||||
import { cssMemberImage, cssMemberListItem, cssMemberPrimary,
|
import { cssMemberImage, cssMemberListItem, cssMemberPrimary,
|
||||||
cssMemberSecondary, cssMemberText } from 'app/client/ui/UserItem';
|
cssMemberSecondary, cssMemberText } from 'app/client/ui/UserItem';
|
||||||
import { basicButtonLink, bigBasicButton, bigBasicButtonLink, bigPrimaryButton, bigPrimaryButtonLink,
|
import { basicButtonLink, bigBasicButtonLink, bigPrimaryButton, bigPrimaryButtonLink,
|
||||||
cssButton } from "app/client/ui2018/buttons";
|
cssButton } from "app/client/ui2018/buttons";
|
||||||
import { colors, mediaSmall, testId, vars } from "app/client/ui2018/cssVars";
|
import { colors, mediaSmall, testId, vars } from "app/client/ui2018/cssVars";
|
||||||
import { getOrgName, Organization } from "app/common/UserAPI";
|
import { getOrgName, Organization } from "app/common/UserAPI";
|
||||||
@ -26,18 +25,9 @@ function _redirectToSiblingPage(name: string) {
|
|||||||
window.location.assign(url.href);
|
window.location.assign(url.href);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect to result.redirectUrl is set, otherwise fail
|
|
||||||
function _redirectOnSuccess(result: any) {
|
|
||||||
const redirectUrl = result.redirectUrl;
|
|
||||||
if (!redirectUrl) {
|
|
||||||
throw new Error('form failed to redirect');
|
|
||||||
}
|
|
||||||
window.location.assign(redirectUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleSubmitForm(
|
function handleSubmitForm(
|
||||||
pending: Observable<boolean>,
|
pending: Observable<boolean>,
|
||||||
onSuccess: (v: any) => void = _redirectOnSuccess,
|
onSuccess: (v: any) => void,
|
||||||
onError?: (e: unknown) => void
|
onError?: (e: unknown) => void
|
||||||
): (elem: HTMLFormElement) => void {
|
): (elem: HTMLFormElement) => void {
|
||||||
return handleSubmit(pending, submitForm, onSuccess, onError);
|
return handleSubmit(pending, submitForm, onSuccess, onError);
|
||||||
@ -45,7 +35,6 @@ function handleSubmitForm(
|
|||||||
|
|
||||||
export class WelcomePage extends Disposable {
|
export class WelcomePage extends Disposable {
|
||||||
|
|
||||||
private _currentUserName = this._appModel.currentUser && this._appModel.currentUser.name || '';
|
|
||||||
private _orgs: Organization[];
|
private _orgs: Organization[];
|
||||||
private _orgsLoaded = Observable.create(this, false);
|
private _orgsLoaded = Observable.create(this, false);
|
||||||
|
|
||||||
@ -75,8 +64,6 @@ export class WelcomePage extends Disposable {
|
|||||||
domComputed(urlState().state, (state) => (
|
domComputed(urlState().state, (state) => (
|
||||||
state.welcome === 'signup' ? dom.create(this._buildSignupForm.bind(this)) :
|
state.welcome === 'signup' ? dom.create(this._buildSignupForm.bind(this)) :
|
||||||
state.welcome === 'verify' ? dom.create(this._buildVerifyForm.bind(this)) :
|
state.welcome === 'verify' ? dom.create(this._buildVerifyForm.bind(this)) :
|
||||||
state.welcome === 'user' ? dom.create(this._buildNameForm.bind(this)) :
|
|
||||||
state.welcome === 'info' ? dom.create(this._buildInfoForm.bind(this)) :
|
|
||||||
state.welcome === 'teams' ? dom.create(this._buildOrgPicker.bind(this)) :
|
state.welcome === 'teams' ? dom.create(this._buildOrgPicker.bind(this)) :
|
||||||
state.welcome === 'select-account' ? dom.create(this._buildAccountPicker.bind(this)) :
|
state.welcome === 'select-account' ? dom.create(this._buildAccountPicker.bind(this)) :
|
||||||
null
|
null
|
||||||
@ -84,39 +71,6 @@ export class WelcomePage extends Disposable {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This can be removed, since the 'user' page is no longer part of any flow.
|
|
||||||
private _buildNameForm(owner: MultiHolder) {
|
|
||||||
let inputEl: HTMLInputElement;
|
|
||||||
let form: HTMLFormElement;
|
|
||||||
const value = Observable.create(owner, checkName(this._currentUserName) ? this._currentUserName : '');
|
|
||||||
const isNameValid = Computed.create(owner, value, (use, val) => checkName(val));
|
|
||||||
const pending = Observable.create(owner, false);
|
|
||||||
|
|
||||||
// delayed focus
|
|
||||||
setTimeout(() => inputEl.focus(), 10);
|
|
||||||
|
|
||||||
return form = dom(
|
|
||||||
'form',
|
|
||||||
{ method: "post", action: location.href },
|
|
||||||
handleSubmitForm(pending),
|
|
||||||
cssLabel('Your full name, as you\'d like it displayed to your collaborators.'),
|
|
||||||
inputEl = cssInput(
|
|
||||||
value, { onInput: true, },
|
|
||||||
{ name: "username" },
|
|
||||||
// TODO: catch isn't needed, so either remove or propagate errors from _submitForm.
|
|
||||||
dom.onKeyDown({Enter: () => isNameValid.get() && form.requestSubmit()}),
|
|
||||||
),
|
|
||||||
dom.maybe((use) => use(value) && !use(isNameValid), buildNameWarningsDom),
|
|
||||||
cssButtonGroup(
|
|
||||||
bigPrimaryButton(
|
|
||||||
'Continue',
|
|
||||||
dom.boolAttr('disabled', (use) => Boolean(use(value) && !use(isNameValid)) || use(pending)),
|
|
||||||
testId('continue-button')
|
|
||||||
),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _buildSignupForm(owner: MultiHolder) {
|
private _buildSignupForm(owner: MultiHolder) {
|
||||||
let inputEl: HTMLInputElement;
|
let inputEl: HTMLInputElement;
|
||||||
const pending = Observable.create(owner, false);
|
const pending = Observable.create(owner, false);
|
||||||
@ -234,61 +188,6 @@ export class WelcomePage extends Disposable {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a form to ask the new user a few questions.
|
|
||||||
*
|
|
||||||
* TODO: This can be removed, since the 'info' page is no longer part of any flow.
|
|
||||||
*/
|
|
||||||
private _buildInfoForm(owner: MultiHolder) {
|
|
||||||
const allFilled = Observable.create(owner, false);
|
|
||||||
const whereObs = Observable.create(owner, '');
|
|
||||||
const pending = Observable.create(owner, false);
|
|
||||||
|
|
||||||
return forms.form({method: "post", action: location.href },
|
|
||||||
handleSubmitForm(pending),
|
|
||||||
(elem) => { setTimeout(() => elem.focus(), 0); },
|
|
||||||
forms.text('Please help us serve you better by answering a few questions.'),
|
|
||||||
forms.question(
|
|
||||||
forms.text('Where do you plan to use Grist?'),
|
|
||||||
forms.checkboxItem([{name: 'use_work'}], 'Work'),
|
|
||||||
forms.checkboxItem([{name: 'use_school'}], 'School'),
|
|
||||||
forms.checkboxItem([{name: 'use_personal'}], 'Personal'),
|
|
||||||
forms.textBox({name: 'company'},
|
|
||||||
dom.hide(use => !use(whereObs)),
|
|
||||||
dom.attr('placeholder', (use) => use(whereObs) === 'school' ? 'Your School' : 'Your Company')
|
|
||||||
),
|
|
||||||
),
|
|
||||||
forms.question(
|
|
||||||
forms.text('What brings you to Grist?'),
|
|
||||||
forms.checkboxItem([{name: 'reason_problem'}], 'Solve a particular problem or need'),
|
|
||||||
forms.checkboxItem([{name: 'reason_tool'}], 'Find a better tool than the one I am using'),
|
|
||||||
forms.checkboxItem([{name: 'reason_curious'}], 'Just curious about a new product'),
|
|
||||||
forms.checkboxOther([{name: 'reason_other'}], {name: 'other_reason', placeholder: 'Other...'}),
|
|
||||||
),
|
|
||||||
forms.question(
|
|
||||||
forms.text('What kind of industry do you work in?'),
|
|
||||||
forms.textBox({name: 'industry', placeholder: 'Your answer'}),
|
|
||||||
),
|
|
||||||
forms.question(
|
|
||||||
forms.text('What is your role?'),
|
|
||||||
forms.textBox({name: 'role', placeholder: 'Your answer'}),
|
|
||||||
),
|
|
||||||
dom.on('change', (e, form) => {
|
|
||||||
allFilled.set(forms.isFormFilled(form, ['use_*', 'reason_*', 'industry', 'role']));
|
|
||||||
whereObs.set(form.use_work.checked ? 'work' : form.use_school.checked ? 'school' : '');
|
|
||||||
}),
|
|
||||||
cssButtonGroup(
|
|
||||||
cssButtonGroup.cls('-right'),
|
|
||||||
bigBasicButton('Continue',
|
|
||||||
cssButton.cls('-primary', allFilled),
|
|
||||||
dom.boolAttr('disabled', pending),
|
|
||||||
{tabIndex: '0'},
|
|
||||||
testId('continue-button')),
|
|
||||||
),
|
|
||||||
testId('info-form'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _fetchOrgs() {
|
private async _fetchOrgs() {
|
||||||
this._orgs = await this._appModel.api.getOrgs(true);
|
this._orgs = await this._appModel.api.getOrgs(true);
|
||||||
this._orgsLoaded.set(true);
|
this._orgsLoaded.set(true);
|
||||||
@ -412,7 +311,6 @@ const textStyle = `
|
|||||||
color: ${colors.dark};
|
color: ${colors.dark};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const cssLabel = styled('label', textStyle);
|
|
||||||
// TODO: there's probably a much better way to style labels with a bit of
|
// TODO: there's probably a much better way to style labels with a bit of
|
||||||
// space between them and things they are not the label for?
|
// space between them and things they are not the label for?
|
||||||
const cssSeparatedLabel = styled('label', textStyle + ' margin-top: 20px;');
|
const cssSeparatedLabel = styled('label', textStyle + ' margin-top: 20px;');
|
||||||
@ -427,10 +325,6 @@ const cssButtonGroup = styled('div', `
|
|||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const cssWarning = styled('div', `
|
|
||||||
color: red;
|
|
||||||
`);
|
|
||||||
|
|
||||||
const cssInput = styled(input, BillingPageCss.inputStyle);
|
const cssInput = styled(input, BillingPageCss.inputStyle);
|
||||||
|
|
||||||
const cssOrgButton = styled(bigPrimaryButtonLink, `
|
const cssOrgButton = styled(bigPrimaryButtonLink, `
|
||||||
@ -444,29 +338,3 @@ const cssOrgButton = styled(bigPrimaryButtonLink, `
|
|||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
/**
|
|
||||||
* We allow alphanumeric characters and certain common whitelisted characters (except at the start),
|
|
||||||
* plus everything non-ASCII (for non-English alphabets, which we want to allow but it's hard to be
|
|
||||||
* more precise about what exactly to allow).
|
|
||||||
*/
|
|
||||||
// eslint-disable-next-line no-control-regex
|
|
||||||
const VALID_NAME_REGEXP = /^(\w|[^\u0000-\u007F])(\w|[- ./'"()]|[^\u0000-\u007F])*$/;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test name against various rules to check if it is a valid username. Returned obj has `.valid` set
|
|
||||||
* to true if all passes, otherwise it has the `.flag` set the the first failing test.
|
|
||||||
*/
|
|
||||||
export function checkName(name: string): boolean {
|
|
||||||
return VALID_NAME_REGEXP.test(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds dom to show marning messages to the user.
|
|
||||||
*/
|
|
||||||
export function buildNameWarningsDom() {
|
|
||||||
return cssWarning(
|
|
||||||
"Names only allow letters, numbers and certain special characters",
|
|
||||||
testId('username-warning'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
@ -25,7 +25,7 @@ export function showWelcomeQuestions(userPrefsObs: Observable<UserPrefs>) {
|
|||||||
|
|
||||||
const submitUrl = new URL(window.location.href);
|
const submitUrl = new URL(window.location.href);
|
||||||
submitUrl.pathname = '/welcome/info';
|
submitUrl.pathname = '/welcome/info';
|
||||||
return BaseAPI.requestJson(submitUrl.href,
|
return BaseAPI.request(submitUrl.href,
|
||||||
{method: 'POST', body: JSON.stringify({use_cases, use_other})});
|
{method: 'POST', body: JSON.stringify({use_cases, use_other})});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,12 +37,18 @@ export class BaseAPI {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a JSON request to the given URL, and read the esponse as JSON. Handles errors, and
|
// Make a JSON request to the given URL, and read the response as JSON. Handles errors, and
|
||||||
// counts pending requests in the same way as BaseAPI methods do.
|
// counts pending requests in the same way as BaseAPI methods do.
|
||||||
public static requestJson(url: string, init: RequestInit = {}): Promise<unknown> {
|
public static requestJson(url: string, init: RequestInit = {}): Promise<unknown> {
|
||||||
return new BaseAPI().requestJson(url, init);
|
return new BaseAPI().requestJson(url, init);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make a request to the given URL, and read the response. Handles errors, and
|
||||||
|
// counts pending requests in the same way as BaseAPI methods do.
|
||||||
|
public static request(url: string, init: RequestInit = {}): Promise<Response> {
|
||||||
|
return new BaseAPI().request(url, init);
|
||||||
|
}
|
||||||
|
|
||||||
private static _numPendingRequests: number = 0;
|
private static _numPendingRequests: number = 0;
|
||||||
|
|
||||||
protected fetch: typeof fetch;
|
protected fetch: typeof fetch;
|
||||||
|
@ -20,7 +20,7 @@ export const HomePage = StringUnion('all', 'workspace', 'templates', 'trash');
|
|||||||
export type IHomePage = typeof HomePage.type;
|
export type IHomePage = typeof HomePage.type;
|
||||||
|
|
||||||
// TODO: Remove 'user' and 'info', since those pages are no longer part of any flow.
|
// TODO: Remove 'user' and 'info', since those pages are no longer part of any flow.
|
||||||
export const WelcomePage = StringUnion('user', 'info', 'teams', 'signup', 'verify', 'select-account');
|
export const WelcomePage = StringUnion('teams', 'signup', 'verify', 'select-account');
|
||||||
export type WelcomePage = typeof WelcomePage.type;
|
export type WelcomePage = typeof WelcomePage.type;
|
||||||
|
|
||||||
export const AccountPage = StringUnion('account');
|
export const AccountPage = StringUnion('account');
|
||||||
@ -286,7 +286,7 @@ export function decodeUrl(gristConfig: Partial<GristLoadConfig>, location: Locat
|
|||||||
if (map.has('m')) { state.mode = OpenDocMode.parse(map.get('m')); }
|
if (map.has('m')) { state.mode = OpenDocMode.parse(map.get('m')); }
|
||||||
if (map.has('account')) { state.account = AccountPage.parse(map.get('account')) || 'account'; }
|
if (map.has('account')) { state.account = AccountPage.parse(map.get('account')) || 'account'; }
|
||||||
if (map.has('billing')) { state.billing = BillingSubPage.parse(map.get('billing')) || 'billing'; }
|
if (map.has('billing')) { state.billing = BillingSubPage.parse(map.get('billing')) || 'billing'; }
|
||||||
if (map.has('welcome')) { state.welcome = WelcomePage.parse(map.get('welcome')) || 'user'; }
|
if (map.has('welcome')) { state.welcome = WelcomePage.parse(map.get('welcome')); }
|
||||||
if (sp.has('billingPlan')) { state.params!.billingPlan = sp.get('billingPlan')!; }
|
if (sp.has('billingPlan')) { state.params!.billingPlan = sp.get('billingPlan')!; }
|
||||||
if (sp.has('billingTask')) {
|
if (sp.has('billingTask')) {
|
||||||
state.params!.billingTask = BillingTask.parse(sp.get('billingTask'));
|
state.params!.billingTask = BillingTask.parse(sp.get('billingTask'));
|
||||||
|
@ -428,9 +428,7 @@ export class HomeDBManager extends EventEmitter {
|
|||||||
needsSave = true;
|
needsSave = true;
|
||||||
// If we are turning off the isFirstTimeUser flag, then right
|
// If we are turning off the isFirstTimeUser flag, then right
|
||||||
// after this transaction commits is a great time to trigger
|
// after this transaction commits is a great time to trigger
|
||||||
// any automation for first logins - the user has logged in
|
// any automation for first logins
|
||||||
// and gone through the welcome process (so they've had a
|
|
||||||
// chance to set a name)
|
|
||||||
if (!props.isFirstTimeUser) { isWelcomed = true; }
|
if (!props.isFirstTimeUser) { isWelcomed = true; }
|
||||||
}
|
}
|
||||||
if (needsSave) {
|
if (needsSave) {
|
||||||
|
@ -1135,69 +1135,22 @@ export class FlexServer implements GristServer {
|
|||||||
this._redirectToLoginWithoutExceptionsMiddleware,
|
this._redirectToLoginWithoutExceptionsMiddleware,
|
||||||
];
|
];
|
||||||
|
|
||||||
// These are some special-purpose pre-sign-up welcome pages, with no middleware.
|
// These are some special-purpose welcome pages, with no middleware.
|
||||||
this.app.get(['/welcome/signup', '/welcome/verify'], expressWrap(async (req, resp, next) => {
|
this.app.get(/\/welcome\/(signup|verify|teams|select-account)/, expressWrap(async (req, resp, next) => {
|
||||||
return this._sendAppPage(req, resp, {path: 'app.html', status: 200, config: {}, googleTagManager: true});
|
return this._sendAppPage(req, resp, {path: 'app.html', status: 200, config: {}, googleTagManager: true});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
/**
|
this.app.post('/welcome/info', ...middleware, expressWrap(async (req, resp, next) => {
|
||||||
* TODO: Add '/welcome/teams' and '/welcome/select-account' to the above route handler,
|
|
||||||
* and remove this one, since those are the only welcome paths that are part of current UI flows.
|
|
||||||
*/
|
|
||||||
this.app.get('/welcome/:page', ...middleware, expressWrap(async (req, resp, next) => {
|
|
||||||
return this._sendAppPage(req, resp, {path: 'app.html', status: 200, config: {}, googleTagManager: true});
|
|
||||||
}));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: We should now be able to remove this route, since the only remaining welcome path
|
|
||||||
* is GET /welcome/teams, and we already redirect there from the welcomeNewUser middleware.
|
|
||||||
*
|
|
||||||
* Leaving this alone for now, just in case, but we should remove this soon.
|
|
||||||
*/
|
|
||||||
this.app.post('/welcome/:page', ...middleware, expressWrap(async (req, resp, next) => {
|
|
||||||
const mreq = req as RequestWithLogin;
|
|
||||||
const userId = getUserId(req);
|
const userId = getUserId(req);
|
||||||
const domain = mreq.org;
|
const user = getUser(req);
|
||||||
let redirectPath: string = '/';
|
const row = {...req.body, UserID: userId, Name: user.name, Email: user.loginEmail};
|
||||||
|
this._recordNewUserInfo(row)
|
||||||
|
.catch(e => {
|
||||||
|
// If we failed to record, at least log the data, so we could potentially recover it.
|
||||||
|
log.rawWarn(`Failed to record new user info: ${e.message}`, {newUserQuestions: row});
|
||||||
|
});
|
||||||
|
|
||||||
if (req.params.page === 'user') {
|
resp.status(200).send();
|
||||||
// The /welcome/user page is no longer part of any flow, but if visited, will still submit
|
|
||||||
// here and redirect. The full name is now part of the sign-up page, so we no longer
|
|
||||||
// need to prompt new users for their name here.
|
|
||||||
const name: string|undefined = req.body && req.body.username || undefined;
|
|
||||||
|
|
||||||
// Reset isFirstTimeUser flag, used to redirect a new user to the /welcome/user page.
|
|
||||||
await this._dbManager.updateUser(userId, {name, isFirstTimeUser: false});
|
|
||||||
|
|
||||||
// This is a good time to set another flag (showNewUserQuestions), to show a popup with
|
|
||||||
// welcome question(s) to this new user. Both flags are scoped to the user, but
|
|
||||||
// isFirstTimeUser has a dedicated DB field because it predates userPrefs. Note that the
|
|
||||||
// updateOrg() method handles all levels of prefs (for user, user+org, or org).
|
|
||||||
await this._dbManager.updateOrg(getScope(req), 0, {userPrefs: {showNewUserQuestions: true}});
|
|
||||||
|
|
||||||
} else if (req.params.page === 'info') {
|
|
||||||
// The /welcome/info page is no longer part of any flow, but if visited, will still submit
|
|
||||||
// here and redirect. The new form with new-user questions appears in a modal popup. It
|
|
||||||
// also posts here to save answers, but ignores the response.
|
|
||||||
const user = getUser(req);
|
|
||||||
const row = {...req.body, UserID: userId, Name: user.name, Email: user.loginEmail};
|
|
||||||
this._recordNewUserInfo(row)
|
|
||||||
.catch(e => {
|
|
||||||
// If we failed to record, at least log the data, so we could potentially recover it.
|
|
||||||
log.rawWarn(`Failed to record new user info: ${e.message}`, {newUserQuestions: row});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// redirect to teams page if users has access to more than one org. Otherwise redirect to
|
|
||||||
// personal org.
|
|
||||||
const result = await this._dbManager.getMergedOrgs(userId, userId, domain || null);
|
|
||||||
const orgs = (result.status === 200) ? result.data : null;
|
|
||||||
if (orgs && orgs.length > 1) {
|
|
||||||
redirectPath = '/welcome/teams';
|
|
||||||
}
|
|
||||||
|
|
||||||
const redirectUrl = this.getMergedOrgUrl(mreq, redirectPath);
|
|
||||||
resp.json({redirectUrl});
|
|
||||||
}),
|
}),
|
||||||
// Add a final error handler that reports errors as JSON.
|
// Add a final error handler that reports errors as JSON.
|
||||||
jsonErrorHandler);
|
jsonErrorHandler);
|
||||||
|
@ -14,10 +14,6 @@ async function openMainPage() {
|
|||||||
await driver.get(`${server.getHost()}`);
|
await driver.get(`${server.getHost()}`);
|
||||||
while (true) { // eslint-disable-line no-constant-condition
|
while (true) { // eslint-disable-line no-constant-condition
|
||||||
try {
|
try {
|
||||||
const url = await driver.getCurrentUrl();
|
|
||||||
if (url.match(/welcome\//)) {
|
|
||||||
await driver.findContent('button', /Continue/).click();
|
|
||||||
}
|
|
||||||
if (await driver.findContent('button', /Create Empty Document/).isPresent()) {
|
if (await driver.findContent('button', /Create Empty Document/).isPresent()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user