mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) add a way to change subdomain in billing pages
Summary: This adds an `updateDomain` billing task that allows editing the subdomain (and the org name, which is also editable with the address). A warning is shown that changing the subdomain will mean that saved links need updating. Test Plan: added test Reviewers: dsagal Reviewed By: dsagal Differential Revision: https://phab.getgrist.com/D2988
This commit is contained in:
parent
d83d734b75
commit
9f25a96d18
@ -175,17 +175,22 @@ export class BillingModelImpl extends Disposable implements BillingModel {
|
||||
}
|
||||
// If there is an org update, re-initialize the org in the client.
|
||||
if (newSettings) { this._appModel.topAppModel.initialize(); }
|
||||
} else if (task === 'signUpLite') {
|
||||
// This is a sign up variant where payment info is handled externally.
|
||||
} else if (task === 'signUpLite' || task === 'updateDomain') {
|
||||
// All that can change here is company name, and domain.
|
||||
const org = this._appModel.currentOrg;
|
||||
const name = formData.settings && formData.settings.name;
|
||||
const domain = formData.settings && formData.settings.domain;
|
||||
const newSettings = org && (name !== org.name || domain !== org.domain) && formData.settings;
|
||||
const newDomain = domain !== org?.domain;
|
||||
const newSettings = org && (name !== org.name || newDomain) && formData.settings;
|
||||
// If the address or settings have a new value, run the update.
|
||||
if (newSettings) {
|
||||
await this._billingAPI.updateAddress(undefined, newSettings || undefined);
|
||||
}
|
||||
// If the domain has changed, should redirect page.
|
||||
if (newDomain) {
|
||||
window.location.assign(urlState().makeUrl({ org: domain, billing: 'billing', params: undefined }));
|
||||
return;
|
||||
}
|
||||
// If there is an org update, re-initialize the org in the client.
|
||||
if (newSettings) { this._appModel.topAppModel.initialize(); }
|
||||
} else {
|
||||
|
@ -389,11 +389,11 @@ class BillingSettingsForm extends BillingSubForm {
|
||||
|
||||
public buildDom() {
|
||||
const noEditAccess = Boolean(this._org && !roles.canEdit(this._org.access));
|
||||
const hasDomain = Boolean(this._options.autofill?.domain);
|
||||
return css.paymentBlock(
|
||||
this._options.showHeader ? css.paymentSubHeader('Team Site') : null,
|
||||
css.paymentRow(
|
||||
css.paymentField(
|
||||
css.paymentLabel('Company Name'),
|
||||
this.billingInput(this._name,
|
||||
dom.boolAttr('disabled', () => noEditAccess),
|
||||
testId('settings-name')
|
||||
@ -410,11 +410,10 @@ class BillingSettingsForm extends BillingSubForm {
|
||||
dom.boolAttr('disabled', () => noEditAccess),
|
||||
testId('settings-domain')
|
||||
),
|
||||
// Note that we already do not allow editing the domain after it is initially set
|
||||
// anyway, this is just here for consistency.
|
||||
noEditAccess ? css.paymentFieldInfo('Organization edit access is required',
|
||||
testId('settings-domain-info')
|
||||
) : null
|
||||
) : null,
|
||||
hasDomain ? css.paymentFieldDanger('Any saved links will need updating if the URL changes') : null,
|
||||
),
|
||||
css.paymentField({style: 'flex: 0 1 0;'},
|
||||
css.inputHintLabel('.getgrist.com')
|
||||
@ -442,6 +441,8 @@ class BillingSettingsForm extends BillingSubForm {
|
||||
|
||||
// Throws if the entered domain contains any invalid characters or is already taken.
|
||||
private async _verifyDomain(domain: string): Promise<void> {
|
||||
// OK to retain current domain.
|
||||
if (domain === this._options.autofill?.domain) { return; }
|
||||
checkSubdomainValidity(domain);
|
||||
const isAvailable = await this._isDomainAvailable(domain);
|
||||
if (!isAvailable) { throw new Error('Domain is already taken.'); }
|
||||
|
@ -26,7 +26,8 @@ const taskActions = {
|
||||
addCard: 'Add Payment Method',
|
||||
updateCard: 'Update Payment Method',
|
||||
updateAddress: 'Update Address',
|
||||
signUpLite: 'Complete Sign Up'
|
||||
signUpLite: 'Complete Sign Up',
|
||||
updateDomain: 'Update Name',
|
||||
};
|
||||
|
||||
/**
|
||||
@ -357,7 +358,10 @@ export class BillingPage extends Disposable {
|
||||
|
||||
private _buildBillingForm(org: Organization|null, address: IBillingAddress|null, task: BillingTask) {
|
||||
const isSharedOrg = org && org.billingAccount && !org.billingAccount.individual;
|
||||
const currentSettings = isSharedOrg ? { name: org!.name } : this._formData.settings;
|
||||
const currentSettings = isSharedOrg ? {
|
||||
name: org!.name,
|
||||
domain: org?.domain?.startsWith('o-') ? undefined : org?.domain || undefined,
|
||||
} : this._formData.settings;
|
||||
const currentAddress = address || this._formData.address;
|
||||
const pageText = taskActions[task];
|
||||
// If there is an immediate charge required, require re-entering the card info.
|
||||
@ -365,8 +369,8 @@ export class BillingPage extends Disposable {
|
||||
this._form = new BillingForm(org, (...args) => this._model.isDomainAvailable(...args), {
|
||||
payment: ['signUp', 'updatePlan', 'addCard', 'updateCard'].includes(task),
|
||||
address: ['signUp', 'updateAddress'].includes(task),
|
||||
settings: ['signUp', 'signUpLite', 'updateAddress'].includes(task),
|
||||
domain: ['signUp', 'signUpLite'].includes(task)
|
||||
settings: ['signUp', 'signUpLite', 'updateAddress', 'updateDomain'].includes(task),
|
||||
domain: ['signUp', 'signUpLite', 'updateDomain'].includes(task)
|
||||
}, { address: currentAddress, settings: currentSettings, card: this._formData.card });
|
||||
return dom('div',
|
||||
dom.onDispose(() => {
|
||||
@ -384,7 +388,7 @@ export class BillingPage extends Disposable {
|
||||
private _buildPaymentConfirmation(formData: IFormData) {
|
||||
const settings = formData.settings || null;
|
||||
return [
|
||||
this._buildDomainSummary(settings && settings.domain),
|
||||
this._buildDomainSummary(settings && settings.domain, false),
|
||||
this._buildCompanySummary(settings && settings.name, formData.address || null, false),
|
||||
this._buildCardSummary(formData.card || null)
|
||||
];
|
||||
@ -499,9 +503,9 @@ export class BillingPage extends Disposable {
|
||||
);
|
||||
}
|
||||
|
||||
private _buildDomainSummary(domain: string|null) {
|
||||
private _buildDomainSummary(domain: string|null, showEdit: boolean = true) {
|
||||
const task = this._model.currentTask.get();
|
||||
if (task === 'signUpLite') { return null; }
|
||||
if (task === 'signUpLite' || task === 'updateDomain') { return null; }
|
||||
return css.summaryItem(
|
||||
css.summaryHeader(
|
||||
css.billingBoldText('Billing Info'),
|
||||
@ -512,7 +516,14 @@ export class BillingPage extends Disposable {
|
||||
dom('span', {style: 'font-weight: bold'}, domain),
|
||||
`.getgrist.com`,
|
||||
testId('org-domain')
|
||||
)
|
||||
),
|
||||
showEdit ? css.billingTextBtn(css.billingIcon('Settings'), 'Change',
|
||||
urlState().setLinkUrl({
|
||||
billing: 'payment',
|
||||
params: { billingTask: 'updateDomain' }
|
||||
}),
|
||||
testId('update-domain')
|
||||
) : null
|
||||
)
|
||||
] : null
|
||||
);
|
||||
@ -619,6 +630,8 @@ export class BillingPage extends Disposable {
|
||||
return makeSummaryFeature('You are updating the default payment method');
|
||||
} else if (task === 'updateAddress') {
|
||||
return makeSummaryFeature('You are updating the company name and address');
|
||||
} else if (task === 'updateDomain') {
|
||||
return makeSummaryFeature('You are updating the company name and domain');
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -242,6 +242,11 @@ export const paymentFieldInfo = styled('div', `
|
||||
margin: 10px 0;
|
||||
`);
|
||||
|
||||
export const paymentFieldDanger = styled('div', `
|
||||
color: #ffa500;
|
||||
margin: 10px 0;
|
||||
`);
|
||||
|
||||
export const paymentSpacer = styled('div', `
|
||||
width: 38px;
|
||||
`);
|
||||
|
@ -10,7 +10,8 @@ export type BillingSubPage = typeof BillingSubPage.type;
|
||||
export const BillingPage = StringUnion(...BillingSubPage.values, 'billing');
|
||||
export type BillingPage = typeof BillingPage.type;
|
||||
|
||||
export const BillingTask = StringUnion('signUp', 'signUpLite', 'updatePlan', 'addCard', 'updateCard', 'updateAddress');
|
||||
export const BillingTask = StringUnion('signUp', 'signUpLite', 'updatePlan', 'addCard',
|
||||
'updateCard', 'updateAddress', 'updateDomain');
|
||||
export type BillingTask = typeof BillingTask.type;
|
||||
|
||||
// Note that IBillingPlan includes selected fields from the Stripe plan object along with
|
||||
|
Loading…
Reference in New Issue
Block a user