gristlabs_grist-core/app/client/ui/WelcomeSitePicker.ts
Dmitry S 2740884e3c (core) Improve the look and behavior of /welcome/teams page (also shown for /welcome/start)
Summary:
- Move css module for the login page css to core/, to be reusable in core/ pages.
- Move /welcome/teams implementation to WelcomeSitePicker.ts
- List users for personal sites, as well as team sites.
- Add org param to setSessionActive() API method and end endpoint, to allow
  switching the specified org to another user.
- Add a little safety to getOrgUrl() function.

Test Plan: Added a test case for the new behaviors of the /welcome/teams page.

Reviewers: georgegevoian

Reviewed By: georgegevoian

Differential Revision: https://phab.getgrist.com/D3914
2023-06-13 20:40:59 -04:00

117 lines
3.8 KiB
TypeScript

import { makeT } from 'app/client/lib/localization';
import { AppModel } from "app/client/models/AppModel";
import { urlState} from "app/client/models/gristUrlState";
import { createUserImage } from 'app/client/ui/UserImage';
import { bigBasicButtonLink } from "app/client/ui2018/buttons";
import { testId, theme } from "app/client/ui2018/cssVars";
import { FullUser } from 'app/common/LoginSessionAPI';
import { getOrgName } from "app/common/UserAPI";
import * as css from 'app/client/ui/LoginPagesCss';
import { Computed, dom, DomContents, IDisposableOwner, styled } from "grainjs";
const t = makeT('WelcomeSitePicker');
export function buildWelcomeSitePicker(owner: IDisposableOwner, appModel: AppModel): DomContents {
// We assume that there is a single domain for personal orgs, and will show a button to open
// that domain with each of the currently signed-in users.
const personalOrg = Computed.create(owner, (use) =>
use(appModel.topAppModel.orgs).find(o => Boolean(o.owner))?.domain || undefined);
return cssPageContainer(
testId('welcome-page'),
css.centeredFlexContainer(
css.formContainer(
css.gristLogo(),
cssHeading(t('Welcome back')),
cssMessage(t('You have access to the following Grist sites.')),
cssColumns(
cssColumn(
cssColumnLabel(css.horizontalLine(), css.lightText('Personal'), css.horizontalLine()),
dom.forEach(appModel.topAppModel.users, (user) => (
cssOrgButton(
cssPersonalOrg(
createUserImage(user, 'small'),
dom('div', user.email, testId('personal-org-email')),
),
dom.attr('href', (use) => urlState().makeUrl({org: use(personalOrg)})),
dom.on('click', (ev) => { void(switchToPersonalUrl(ev, appModel, personalOrg.get(), user)); }),
testId('personal-org'),
)
)),
),
cssColumn(
cssColumnLabel(css.horizontalLine(), css.lightText('Team'), css.horizontalLine()),
dom.forEach(appModel.topAppModel.orgs, (org) => (
org.owner || !org.domain ? null : cssOrgButton(
getOrgName(org),
urlState().setLinkUrl({org: org.domain}),
testId('org'),
)
)),
)
),
cssMessage(t("You can always switch sites using the account menu.")),
)
)
);
}
// TODO This works but not for opening a link in a new tab. We currently lack and endpoint that
// would enable opening a link as a particular user, or to switch user and open as them.
async function switchToPersonalUrl(ev: MouseEvent, appModel: AppModel, org: string|undefined, user: FullUser) {
// Only handle plain-vanilla clicks.
if (ev.shiftKey || ev.metaKey || ev.ctrlKey || ev.altKey) { return; }
ev.preventDefault();
// Set the active session for the given org, then load its home page.
await appModel.api.setSessionActive(user.email, org);
window.location.assign(urlState().makeUrl({org}));
}
const cssPageContainer = styled(css.pageContainer, `
overflow: auto;
padding-bottom: 40px;
`);
const cssHeading = styled(css.formHeading, `
margin-top: 16px;
text-align: center;
`);
const cssMessage = styled(css.centeredText, `
margin: 24px 0;
`);
const cssColumns = styled('div', `
display: flex;
flex-wrap: wrap;
gap: 32px;
`);
const cssColumn = styled('div', `
flex: 1 0 0px;
min-width: 200px;
position: relative;
`);
const cssColumnLabel = styled('div', `
display: flex;
align-items: center;
gap: 8px;
`);
const cssOrgButton = styled(bigBasicButtonLink, `
display: block;
margin: 8px 0;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
`);
const cssPersonalOrg = styled('div', `
display: flex;
align-items: center;
margin-left: -8px;
gap: 8px;
color: ${theme.lightText};
`);