mirror of
https://github.com/discourse/discourse.git
synced 2025-01-30 11:11:44 +08:00
UX: Add progress bar to the registration flow (#27694)
This commit is contained in:
parent
3a04443632
commit
b092ccbdc5
|
@ -21,16 +21,17 @@
|
|||
this.model.authOptions.auth_provider
|
||||
}}
|
||||
>
|
||||
<div class="login-welcome-header" id="create-account-title">
|
||||
<h1 class="login-title">{{i18n "create_account.header_title"}}</h1>
|
||||
<img src={{this.wavingHandURL}} alt="" class="waving-hand" />
|
||||
<p class="login-subheader">{{i18n "create_account.subheader_title"}}</p>
|
||||
<SignupProgressBar @step="signup" />
|
||||
<WelcomeHeader
|
||||
id="create-account-title"
|
||||
@header={{i18n "create_account.header_title"}}
|
||||
@subheader={{i18n "create_account.subheader_title"}}
|
||||
>
|
||||
<PluginOutlet
|
||||
@name="create-account-header-bottom"
|
||||
@outletArgs={{hash showLogin=(route-action "showLogin")}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</WelcomeHeader>
|
||||
{{#if this.showCreateForm}}
|
||||
<form id="login-form">
|
||||
{{#if this.associateHtml}}
|
||||
|
@ -86,7 +87,6 @@
|
|||
id="username-validation"
|
||||
/>
|
||||
{{#unless this.usernameValidation.reason}}
|
||||
|
||||
<span class="more-info" id="username-validation-more-info">
|
||||
{{i18n "user.username.instructions"}}
|
||||
</span>
|
||||
|
@ -307,9 +307,11 @@
|
|||
|
||||
<:footer>
|
||||
{{#if (and this.showCreateForm this.site.mobileView)}}
|
||||
<div class="disclaimer">
|
||||
{{html-safe this.disclaimerHtml}}
|
||||
</div>
|
||||
{{#if this.disclaimerHtml}}
|
||||
<div class="disclaimer">
|
||||
{{html-safe this.disclaimerHtml}}
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="d-modal__footer-buttons">
|
||||
<DButton
|
||||
@action={{this.createAccount}}
|
||||
|
|
|
@ -11,7 +11,6 @@ import { setting } from "discourse/lib/computed";
|
|||
import cookie, { removeCookie } from "discourse/lib/cookie";
|
||||
import { userPath } from "discourse/lib/url";
|
||||
import { emailValid } from "discourse/lib/utilities";
|
||||
import { wavingHandURL } from "discourse/lib/waving-hand-url";
|
||||
import NameValidation from "discourse/mixins/name-validation";
|
||||
import PasswordValidation from "discourse/mixins/password-validation";
|
||||
import UserFieldsValidation from "discourse/mixins/user-fields-validation";
|
||||
|
@ -106,11 +105,6 @@ export default class CreateAccount extends Component.extend(
|
|||
return this.formSubmitted;
|
||||
}
|
||||
|
||||
@discourseComputed()
|
||||
wavingHandURL() {
|
||||
return wavingHandURL();
|
||||
}
|
||||
|
||||
@discourseComputed("userFields", "hasAtLeastOneLoginButton", "hasAuthOptions")
|
||||
modalBodyClasses(userFields, hasAtLeastOneLoginButton, hasAuthOptions) {
|
||||
const classes = [];
|
||||
|
|
|
@ -27,10 +27,15 @@
|
|||
</div>
|
||||
{{else}}
|
||||
{{#if this.site.mobileView}}
|
||||
<Modal::Login::WelcomeHeader
|
||||
@wavingHandURL={{this.wavingHandURL}}
|
||||
@createAccount={{this.createAccount}}
|
||||
/>
|
||||
<WelcomeHeader
|
||||
@header={{i18n "login.header_title"}}
|
||||
@subheader={{i18n "login.subheader_title"}}
|
||||
>
|
||||
<PluginOutlet
|
||||
@name="login-header-bottom"
|
||||
@outletArgs={{hash createAccount=this.createAccount}}
|
||||
/>
|
||||
</WelcomeHeader>
|
||||
{{#if this.showLoginButtons}}
|
||||
<LoginButtons
|
||||
@externalLogin={{this.externalLoginAction}}
|
||||
|
@ -43,10 +48,15 @@
|
|||
{{#if this.canLoginLocal}}
|
||||
<div class={{if this.site.desktopView "login-left-side"}}>
|
||||
{{#if this.site.desktopView}}
|
||||
<Modal::Login::WelcomeHeader
|
||||
@wavingHandURL={{this.wavingHandURL}}
|
||||
@createAccount={{this.createAccount}}
|
||||
/>
|
||||
<WelcomeHeader
|
||||
@header={{i18n "login.header_title"}}
|
||||
@subheader={{i18n "login.subheader_title"}}
|
||||
>
|
||||
<PluginOutlet
|
||||
@name="login-header-bottom"
|
||||
@outletArgs={{hash createAccount=this.createAccount}}
|
||||
/>
|
||||
</WelcomeHeader>
|
||||
{{/if}}
|
||||
<Modal::Login::LocalLoginForm
|
||||
@loginName={{this.loginName}}
|
||||
|
@ -91,8 +101,9 @@
|
|||
{{#if (and this.showLoginButtons this.site.desktopView)}}
|
||||
{{#unless this.canLoginLocal}}
|
||||
<div class="login-left-side">
|
||||
<Modal::Login::WelcomeHeader
|
||||
@wavingHandURL={{this.wavingHandURL}}
|
||||
<WelcomeHeader
|
||||
@header={{i18n "login.header_title"}}
|
||||
@subheader={{i18n "login.subheader_title"}}
|
||||
/>
|
||||
</div>
|
||||
{{/unless}}
|
||||
|
|
|
@ -10,7 +10,6 @@ import { popupAjaxError } from "discourse/lib/ajax-error";
|
|||
import cookie, { removeCookie } from "discourse/lib/cookie";
|
||||
import { wantsNewWindow } from "discourse/lib/intercept-click";
|
||||
import { areCookiesEnabled } from "discourse/lib/utilities";
|
||||
import { wavingHandURL } from "discourse/lib/waving-hand-url";
|
||||
import {
|
||||
getPasskeyCredential,
|
||||
isWebauthnSupported,
|
||||
|
@ -64,10 +63,6 @@ export default class Login extends Component {
|
|||
return this.loggingIn || this.loggedIn;
|
||||
}
|
||||
|
||||
get wavingHandURL() {
|
||||
return wavingHandURL();
|
||||
}
|
||||
|
||||
get modalBodyClasses() {
|
||||
const classes = ["login-modal-body"];
|
||||
if (this.awaitingApproval) {
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
<div class="login-welcome-header">
|
||||
<h1 class="login-title">{{i18n "login.header_title"}}</h1>
|
||||
<img src={{@wavingHandURL}} alt="" class="waving-hand" />
|
||||
<p class="login-subheader">{{i18n "login.subheader_title"}}</p>
|
||||
<PluginOutlet
|
||||
@name="login-header-bottom"
|
||||
@outletArgs={{hash createAccount=@createAccount}}
|
||||
/>
|
||||
</div>
|
|
@ -0,0 +1,80 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { concat } from "@ember/helper";
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { eq } from "truth-helpers";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
import dIcon from "discourse-common/helpers/d-icon";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
export default class SignupProgressBar extends Component {
|
||||
@service siteSettings;
|
||||
@tracked steps = [];
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
if (this.siteSettings.must_approve_users) {
|
||||
this.steps = ["signup", "activate", "approve", "login"];
|
||||
} else {
|
||||
this.steps = ["signup", "activate", "login"];
|
||||
}
|
||||
}
|
||||
|
||||
stepText(step) {
|
||||
return I18n.t(`create_account.progress_bar.${step}`);
|
||||
}
|
||||
|
||||
get currentStepIndex() {
|
||||
return this.steps.findIndex((step) => step === this.args.step);
|
||||
}
|
||||
|
||||
get lastStepIndex() {
|
||||
return this.steps.length - 1;
|
||||
}
|
||||
|
||||
@action
|
||||
getStepState(index) {
|
||||
if (index === this.currentStepIndex) {
|
||||
return "active";
|
||||
} else if (index < this.currentStepIndex) {
|
||||
return "completed";
|
||||
} else if (index > this.currentStepIndex) {
|
||||
return "incomplete";
|
||||
}
|
||||
}
|
||||
|
||||
<template>
|
||||
{{#if @step}}
|
||||
<div class="signup-progress-bar">
|
||||
{{#each this.steps as |step index|}}
|
||||
<div class="signup-progress-bar__segment">
|
||||
<div
|
||||
class={{concatClass
|
||||
"signup-progress-bar__step"
|
||||
(concat "--" (this.getStepState index))
|
||||
}}
|
||||
>
|
||||
<div class="signup-progress-bar__circle">
|
||||
{{#if (eq (this.getStepState index) "completed")}}
|
||||
{{dIcon "check"}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#unless (eq index this.lastStepIndex)}}
|
||||
<span
|
||||
class={{concatClass
|
||||
"signup-progress-bar__line"
|
||||
(concat "--" (this.getStepState index))
|
||||
}}
|
||||
></span>
|
||||
{{/unless}}
|
||||
</div>
|
||||
<span class="signup-progress-bar__step-text">
|
||||
{{this.stepText step}}
|
||||
</span>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import { wavingHandURL } from "discourse/lib/waving-hand-url";
|
||||
|
||||
const WelcomeHeader = <template>
|
||||
<div class="login-welcome-header" ...attributes>
|
||||
<h1 class="login-title">{{@header}}</h1>
|
||||
<img src={{(wavingHandURL)}} alt="" class="waving-hand" />
|
||||
{{#if @subheader}}
|
||||
<p class="login-subheader">{{@subheader}}</p>
|
||||
{{/if}}
|
||||
{{yield}}
|
||||
</div>
|
||||
</template>;
|
||||
|
||||
export default WelcomeHeader;
|
|
@ -2,16 +2,12 @@ import Controller from "@ember/controller";
|
|||
import { action } from "@ember/object";
|
||||
import { service } from "@ember/service";
|
||||
import { resendActivationEmail } from "discourse/lib/user-activation";
|
||||
import { wavingHandURL } from "discourse/lib/waving-hand-url";
|
||||
import getUrl from "discourse-common/lib/get-url";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
export default class AccountCreatedIndexController extends Controller {
|
||||
@service router;
|
||||
|
||||
envelopeImageUrl = getUrl("/images/envelope.svg");
|
||||
|
||||
@discourseComputed
|
||||
welcomeTitle() {
|
||||
return I18n.t("invites.welcome_to", {
|
||||
|
@ -19,11 +15,6 @@ export default class AccountCreatedIndexController extends Controller {
|
|||
});
|
||||
}
|
||||
|
||||
@discourseComputed
|
||||
wavingHandURL() {
|
||||
return wavingHandURL();
|
||||
}
|
||||
|
||||
@action
|
||||
sendActivationEmail() {
|
||||
resendActivationEmail(this.get("accountCreated.username")).then(() => {
|
||||
|
|
|
@ -6,7 +6,6 @@ import { ajax } from "discourse/lib/ajax";
|
|||
import { extractError } from "discourse/lib/ajax-error";
|
||||
import DiscourseURL from "discourse/lib/url";
|
||||
import { emailValid } from "discourse/lib/utilities";
|
||||
import { wavingHandURL } from "discourse/lib/waving-hand-url";
|
||||
import NameValidation from "discourse/mixins/name-validation";
|
||||
import PasswordValidation from "discourse/mixins/password-validation";
|
||||
import UserFieldsValidation from "discourse/mixins/user-fields-validation";
|
||||
|
@ -42,7 +41,6 @@ export default class InvitesShowController extends Controller.extend(
|
|||
errorMessage = null;
|
||||
userFields = null;
|
||||
authOptions = null;
|
||||
inviteImageUrl = getUrl("/images/envelope.svg");
|
||||
rejectedEmails = [];
|
||||
maskPassword = true;
|
||||
|
||||
|
@ -261,11 +259,6 @@ export default class InvitesShowController extends Controller.extend(
|
|||
return matchingProvider ? matchingProvider.get("prettyName") : providerName;
|
||||
}
|
||||
|
||||
@discourseComputed
|
||||
wavingHandURL() {
|
||||
return wavingHandURL();
|
||||
}
|
||||
|
||||
@discourseComputed
|
||||
ssoPath() {
|
||||
return getUrl("/session/sso");
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import { service } from "@ember/service";
|
||||
import PreloadStore from "discourse/lib/preload-store";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { deepMerge } from "discourse-common/lib/object";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
export default class InvitesShow extends DiscourseRoute {
|
||||
@service siteSettings;
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("invites.accept_title");
|
||||
}
|
||||
|
@ -21,17 +24,21 @@ export default class InvitesShow extends DiscourseRoute {
|
|||
activate() {
|
||||
super.activate(...arguments);
|
||||
|
||||
this.controllerFor("application").setProperties({
|
||||
showSiteHeader: false,
|
||||
});
|
||||
if (this.siteSettings.login_required) {
|
||||
this.controllerFor("application").setProperties({
|
||||
showSiteHeader: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
deactivate() {
|
||||
super.deactivate(...arguments);
|
||||
|
||||
this.controllerFor("application").setProperties({
|
||||
showSiteHeader: true,
|
||||
});
|
||||
if (this.siteSettings.login_required) {
|
||||
this.controllerFor("application").setProperties({
|
||||
showSiteHeader: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setupController(controller, model) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<div id="simple-container">
|
||||
<div class="account-created">
|
||||
{{outlet}}
|
||||
</div>
|
||||
{{body-class "account-created-page"}}
|
||||
{{hide-application-header-buttons "search" "login" "signup"}}
|
||||
{{hide-application-sidebar}}
|
||||
<div class="account-created">
|
||||
{{outlet}}
|
||||
</div>
|
|
@ -1,10 +1,10 @@
|
|||
<SignupProgressBar @step="activate" />
|
||||
<div class="ac-message">
|
||||
<ActivationEmailForm
|
||||
@email={{this.newEmail}}
|
||||
@updateNewEmail={{this.updateNewEmail}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="activation-controls">
|
||||
<DButton
|
||||
@action={{this.changeEmail}}
|
||||
|
|
|
@ -1,26 +1,11 @@
|
|||
{{body-class "account-activation-page"}}
|
||||
<div class="container invites-show">
|
||||
<div class="login-welcome-header">
|
||||
<h1 class="login-title">{{this.welcomeTitle}}</h1>
|
||||
<img src={{this.wavingHandURL}} alt="" class="waving-hand" />
|
||||
</div>
|
||||
|
||||
<div class="ac-page">
|
||||
<div class="two-col">
|
||||
<div class="col-image">
|
||||
<img src={{this.envelopeImageUrl}} alt="" />
|
||||
</div>
|
||||
<div class="col-form">
|
||||
<div class="success-info">
|
||||
{{html-safe this.accountCreated.message}}
|
||||
</div>
|
||||
{{#if this.accountCreated.show_controls}}
|
||||
<ActivationControls
|
||||
@sendActivationEmail={{action "sendActivationEmail"}}
|
||||
@editActivationEmail={{action "editActivationEmail"}}
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<SignupProgressBar @step="activate" />
|
||||
<WelcomeHeader @header={{this.welcomeTitle}} />
|
||||
<div class="success-info">
|
||||
{{html-safe this.accountCreated.message}}
|
||||
</div>
|
||||
{{#if this.accountCreated.show_controls}}
|
||||
<ActivationControls
|
||||
@sendActivationEmail={{action "sendActivationEmail"}}
|
||||
@editActivationEmail={{action "editActivationEmail"}}
|
||||
/>
|
||||
{{/if}}
|
|
@ -1,3 +1,4 @@
|
|||
<SignupProgressBar @step="activate" />
|
||||
<div class="ac-message">
|
||||
{{#if this.email}}
|
||||
{{html-safe
|
||||
|
|
|
@ -4,11 +4,13 @@ import { action } from "@ember/object";
|
|||
import { service } from "@ember/service";
|
||||
import RouteTemplate from "ember-route-template";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import SignupProgressBar from "discourse/components/signup-progress-bar";
|
||||
import WelcomeHeader from "discourse/components/welcome-header";
|
||||
import bodyClass from "discourse/helpers/body-class";
|
||||
import hideApplicationHeaderButtons from "discourse/helpers/hide-application-header-buttons";
|
||||
import hideApplicationSidebar from "discourse/helpers/hide-application-sidebar";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { wavingHandURL } from "discourse/lib/waving-hand-url";
|
||||
import i18n from "discourse-common/helpers/i18n";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
|
||||
|
@ -21,6 +23,16 @@ export default RouteTemplate(
|
|||
@tracked needsApproval = false;
|
||||
@tracked errorMessage = null;
|
||||
|
||||
get signupStep() {
|
||||
if (this.needsApproval) {
|
||||
return "approve";
|
||||
} else if (this.accountActivated) {
|
||||
return "login";
|
||||
} else {
|
||||
return "activate";
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async activate() {
|
||||
this.isLoading = true;
|
||||
|
@ -71,59 +83,52 @@ export default RouteTemplate(
|
|||
}
|
||||
|
||||
<template>
|
||||
{{hideApplicationSidebar}}
|
||||
{{bodyClass "activate-account-page"}}
|
||||
{{hideApplicationHeaderButtons "search" "login" "signup"}}
|
||||
<div id="simple-container">
|
||||
{{#if this.errorMessage}}
|
||||
<div class="alert alert-error">
|
||||
{{this.errorMessage}}
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="activate-account">
|
||||
<h1 class="activate-title">{{i18n
|
||||
"user.activate_account.welcome_to"
|
||||
site_name=this.siteSettings.title
|
||||
}}
|
||||
<img src={{(wavingHandURL)}} alt="" class="waving-hand" />
|
||||
</h1>
|
||||
<br />
|
||||
{{#if this.accountActivated}}
|
||||
<div class="perform-activation">
|
||||
<div class="image">
|
||||
<img
|
||||
src="/images/wizard/tada.svg"
|
||||
class="waving-hand"
|
||||
alt="tada emoji"
|
||||
/>
|
||||
</div>
|
||||
{{#if this.needsApproval}}
|
||||
<p>{{i18n "user.activate_account.approval_required"}}</p>
|
||||
{{else}}
|
||||
<p>{{i18n "user.activate_account.please_continue"}}</p>
|
||||
<p>
|
||||
<DButton
|
||||
class="continue-button"
|
||||
@translatedLabel={{i18n
|
||||
"user.activate_account.continue_button"
|
||||
site_name=this.siteSettings.title
|
||||
}}
|
||||
@action={{this.loadHomepage}}
|
||||
/>
|
||||
</p>
|
||||
{{/if}}
|
||||
{{hideApplicationSidebar}}
|
||||
{{#if this.errorMessage}}
|
||||
<div class="alert alert-error">
|
||||
{{this.errorMessage}}
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="activate-account">
|
||||
<SignupProgressBar @step={{this.signupStep}} />
|
||||
<WelcomeHeader
|
||||
@header={{i18n
|
||||
"user.activate_account.welcome_to"
|
||||
site_name=this.siteSettings.title
|
||||
}}
|
||||
/>
|
||||
<br />
|
||||
{{#if this.accountActivated}}
|
||||
<div class="account-activated">
|
||||
<div class="tada-image">
|
||||
<img src="/images/wizard/tada.svg" alt="tada emoji" />
|
||||
</div>
|
||||
{{else}}
|
||||
<DButton
|
||||
id="activate-account-button"
|
||||
class="btn-primary"
|
||||
@action={{this.activate}}
|
||||
@label="user.activate_account.action"
|
||||
@disabled={{this.isLoading}}
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if this.needsApproval}}
|
||||
<p>{{i18n "user.activate_account.approval_required"}}</p>
|
||||
{{else}}
|
||||
<p>{{i18n "user.activate_account.please_continue"}}</p>
|
||||
<DButton
|
||||
class="continue-button"
|
||||
@translatedLabel={{i18n
|
||||
"user.activate_account.continue_button"
|
||||
site_name=this.siteSettings.title
|
||||
}}
|
||||
@action={{this.loadHomepage}}
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{else}}
|
||||
<DButton
|
||||
class="activate-account-button btn-primary"
|
||||
@action={{this.activate}}
|
||||
@label="user.activate_account.action"
|
||||
@disabled={{this.isLoading}}
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
}
|
||||
);
|
||||
|
|
|
@ -1,240 +1,241 @@
|
|||
{{body-class "invite-page"}}
|
||||
{{hide-application-header-buttons "search" "login" "signup"}}
|
||||
{{hide-application-sidebar}}
|
||||
|
||||
<section>
|
||||
<div class="container invites-show clearfix">
|
||||
<div class="login-welcome-header">
|
||||
<h1 class="login-title">{{this.welcomeTitle}}</h1>
|
||||
<img src={{this.wavingHandURL}} alt="" class="waving-hand" />
|
||||
{{#unless this.successMessage}}
|
||||
<p class="login-subheader">{{this.subheaderMessage}}</p>
|
||||
{{/unless}}
|
||||
</div>
|
||||
{{#unless this.externalAuthsOnly}}
|
||||
<SignupProgressBar @step={{if this.successMessage "activate" "signup"}} />
|
||||
{{/unless}}
|
||||
<WelcomeHeader
|
||||
@header={{this.welcomeTitle}}
|
||||
@subheader={{unless this.successMessage this.subheaderMessage}}
|
||||
/>
|
||||
|
||||
<div class={{if this.successMessage "invite-success" "invite-form"}}>
|
||||
<div class="two-col">
|
||||
<div class="col-image">
|
||||
<img src={{this.inviteImageUrl}} alt="" />
|
||||
</div>
|
||||
<div class="col-form">
|
||||
{{#if this.successMessage}}
|
||||
<div class="success-info">
|
||||
<p>{{html-safe this.successMessage}}</p>
|
||||
</div>
|
||||
{{else}}
|
||||
<p>{{i18n "invites.invited_by"}}</p>
|
||||
<p><UserInfo @user={{this.invitedBy}} /></p>
|
||||
|
||||
<div class="col-form">
|
||||
{{#if this.successMessage}}
|
||||
<div class="success-info">
|
||||
<p>{{html-safe this.successMessage}}</p>
|
||||
</div>
|
||||
{{else}}
|
||||
<p>{{i18n "invites.invited_by"}}</p>
|
||||
<p><UserInfo @user={{this.invitedBy}} /></p>
|
||||
{{#if this.associateHtml}}
|
||||
<p class="create-account-associate-link">
|
||||
{{html-safe this.associateHtml}}
|
||||
</p>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.associateHtml}}
|
||||
<p class="create-account-associate-link">
|
||||
{{html-safe this.associateHtml}}
|
||||
</p>
|
||||
{{#unless this.isInviteLink}}
|
||||
<p class="email-message">
|
||||
{{html-safe this.yourEmailMessage}}
|
||||
{{#if this.showSocialLoginAvailable}}
|
||||
{{i18n "invites.social_login_available"}}
|
||||
{{/if}}
|
||||
</p>
|
||||
{{/unless}}
|
||||
|
||||
{{#if this.externalAuthsOnly}}
|
||||
{{! authOptions are present once the user has followed the OmniAuth flow (e.g. twitter/google/etc) }}
|
||||
{{#if this.authOptions}}
|
||||
{{#unless this.isInviteLink}}
|
||||
<InputTip
|
||||
@validation={{this.emailValidation}}
|
||||
id="account-email-validation"
|
||||
/>
|
||||
{{/unless}}
|
||||
{{else}}
|
||||
<LoginButtons
|
||||
@externalLogin={{action "externalLogin"}}
|
||||
@context="invite"
|
||||
/>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#unless this.isInviteLink}}
|
||||
<p class="email-message">
|
||||
{{html-safe this.yourEmailMessage}}
|
||||
{{#if this.showSocialLoginAvailable}}
|
||||
{{i18n "invites.social_login_available"}}
|
||||
{{/if}}
|
||||
</p>
|
||||
{{/unless}}
|
||||
{{#if this.discourseConnectEnabled}}
|
||||
<a
|
||||
class="btn btn-primary discourse-connect raw-link"
|
||||
href={{this.ssoPath}}
|
||||
>
|
||||
{{i18n "continue"}}
|
||||
</a>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.externalAuthsOnly}}
|
||||
{{! authOptions are present once the user has followed the OmniAuth flow (e.g. twitter/google/etc) }}
|
||||
{{#if this.authOptions}}
|
||||
{{#unless this.isInviteLink}}
|
||||
{{#if this.shouldDisplayForm}}
|
||||
<form>
|
||||
{{#if this.isInviteLink}}
|
||||
<div class="input email-input input-group">
|
||||
<Input
|
||||
@type="email"
|
||||
@value={{this.email}}
|
||||
id="new-account-email"
|
||||
name="email"
|
||||
class={{value-entered this.email}}
|
||||
autofocus="autofocus"
|
||||
disabled={{this.externalAuthsOnly}}
|
||||
/>
|
||||
<label class="alt-placeholder" for="new-account-email">
|
||||
{{i18n "user.email.title"}}
|
||||
</label>
|
||||
<InputTip
|
||||
@validation={{this.emailValidation}}
|
||||
id="account-email-validation"
|
||||
/>
|
||||
{{/unless}}
|
||||
{{else}}
|
||||
<LoginButtons
|
||||
@externalLogin={{action "externalLogin"}}
|
||||
@context="invite"
|
||||
/>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#if this.discourseConnectEnabled}}
|
||||
<a
|
||||
class="btn btn-primary discourse-connect raw-link"
|
||||
href={{this.ssoPath}}
|
||||
>
|
||||
{{i18n "continue"}}
|
||||
</a>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.shouldDisplayForm}}
|
||||
<form>
|
||||
{{#if this.isInviteLink}}
|
||||
<div class="input email-input input-group">
|
||||
<Input
|
||||
@type="email"
|
||||
@value={{this.email}}
|
||||
id="new-account-email"
|
||||
name="email"
|
||||
class={{value-entered this.email}}
|
||||
autofocus="autofocus"
|
||||
disabled={{this.externalAuthsOnly}}
|
||||
/>
|
||||
<label class="alt-placeholder" for="new-account-email">
|
||||
{{i18n "user.email.title"}}
|
||||
<span class="required">*</span>
|
||||
</label>
|
||||
<InputTip
|
||||
@validation={{this.emailValidation}}
|
||||
id="account-email-validation"
|
||||
/>
|
||||
{{#unless this.emailValidation.reason}}
|
||||
<div class="instructions">{{i18n
|
||||
"user.email.instructions"
|
||||
}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/unless}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="input username-input input-group">
|
||||
<Input
|
||||
@value={{this.accountUsername}}
|
||||
class={{value-entered this.accountUsername}}
|
||||
id="new-account-username"
|
||||
name="username"
|
||||
maxlength={{this.maxUsernameLength}}
|
||||
autocomplete="off"
|
||||
/>
|
||||
<label class="alt-placeholder" for="new-account-username">
|
||||
{{i18n "user.username.title"}}
|
||||
<span class="required">*</span>
|
||||
</label>
|
||||
<InputTip
|
||||
@validation={{this.usernameValidation}}
|
||||
id="username-validation"
|
||||
/>
|
||||
<div class="input username-input input-group">
|
||||
<Input
|
||||
@value={{this.accountUsername}}
|
||||
class={{value-entered this.accountUsername}}
|
||||
id="new-account-username"
|
||||
name="username"
|
||||
maxlength={{this.maxUsernameLength}}
|
||||
autocomplete="off"
|
||||
/>
|
||||
<label class="alt-placeholder" for="new-account-username">
|
||||
{{i18n "user.username.title"}}
|
||||
</label>
|
||||
<InputTip
|
||||
@validation={{this.usernameValidation}}
|
||||
id="username-validation"
|
||||
/>
|
||||
{{#unless this.usernameValidation.reason}}
|
||||
<div class="instructions">{{i18n
|
||||
"user.username.instructions"
|
||||
}}</div>
|
||||
</div>
|
||||
{{/unless}}
|
||||
</div>
|
||||
|
||||
{{#if this.fullnameRequired}}
|
||||
<div class="input name-input input-group">
|
||||
<Input
|
||||
@value={{this.accountName}}
|
||||
class={{value-entered this.accountName}}
|
||||
id="new-account-name"
|
||||
name="name"
|
||||
/>
|
||||
<label class="alt-placeholder" for="new-account-name">
|
||||
{{i18n "invites.name_label"}}
|
||||
{{#if this.siteSettings.full_name_required}}
|
||||
<span class="required">*</span>
|
||||
{{/if}}
|
||||
</label>
|
||||
<div class="instructions">{{this.nameInstructions}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#unless this.externalAuthsOnly}}
|
||||
<div class="input password-input input-group">
|
||||
<PasswordField
|
||||
@value={{this.accountPassword}}
|
||||
@capsLockOn={{this.capsLockOn}}
|
||||
type={{if this.maskPassword "password" "text"}}
|
||||
autocomplete="new-password"
|
||||
id="new-account-password"
|
||||
class={{value-entered this.accountPassword}}
|
||||
/>
|
||||
<label class="alt-placeholder" for="new-account-password">
|
||||
{{i18n "invites.password_label"}}
|
||||
<span class="required">*</span>
|
||||
</label>
|
||||
<div class="create-account__password-info">
|
||||
<div class="create-account__password-tip-validation">
|
||||
<InputTip
|
||||
@validation={{this.passwordValidation}}
|
||||
id="password-validation"
|
||||
/>
|
||||
{{#unless this.externalAuthsOnly}}
|
||||
<div class="input password-input input-group">
|
||||
<PasswordField
|
||||
@value={{this.accountPassword}}
|
||||
@capsLockOn={{this.capsLockOn}}
|
||||
type={{if this.maskPassword "password" "text"}}
|
||||
autocomplete="new-password"
|
||||
id="new-account-password"
|
||||
class={{value-entered this.accountPassword}}
|
||||
/>
|
||||
<label class="alt-placeholder" for="new-account-password">
|
||||
{{i18n "invites.password_label"}}
|
||||
</label>
|
||||
<div class="create-account__password-info">
|
||||
<div class="create-account__password-tip-validation">
|
||||
<InputTip
|
||||
@validation={{this.passwordValidation}}
|
||||
id="password-validation"
|
||||
/>
|
||||
{{#unless this.passwordValidation.reason}}
|
||||
<span
|
||||
class="more-info"
|
||||
>{{this.passwordInstructions}}</span>
|
||||
<div
|
||||
class="caps-lock-warning
|
||||
{{unless this.capsLockOn 'hidden'}}"
|
||||
>
|
||||
{{d-icon "exclamation-triangle"}}
|
||||
{{i18n "login.caps_lock_warning"}}
|
||||
</div>
|
||||
{{/unless}}
|
||||
<div
|
||||
class="caps-lock-warning
|
||||
{{unless this.capsLockOn 'hidden'}}"
|
||||
>
|
||||
{{d-icon "exclamation-triangle"}}
|
||||
{{i18n "login.caps_lock_warning"}}
|
||||
</div>
|
||||
<TogglePasswordMask
|
||||
@maskPassword={{this.maskPassword}}
|
||||
@togglePasswordMask={{this.togglePasswordMask}}
|
||||
@parentController="invites-show"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{{/unless}}
|
||||
|
||||
{{#if this.userFields}}
|
||||
<div class="user-fields">
|
||||
{{#each this.userFields as |f|}}
|
||||
<div class="input-group">
|
||||
<UserField
|
||||
@field={{f.field}}
|
||||
@value={{f.value}}
|
||||
class={{value-entered f.value}}
|
||||
/>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="invitation-cta">
|
||||
<DButton
|
||||
@action={{action "submit"}}
|
||||
@disabled={{this.submitDisabled}}
|
||||
@label="invites.accept_invite"
|
||||
type="submit"
|
||||
class="btn-primary invitation-cta__accept"
|
||||
/>
|
||||
<div class="invitation-cta__info">
|
||||
<span class="invitation-cta__signed-up">{{i18n
|
||||
"login.previous_sign_up"
|
||||
}}</span>
|
||||
<DButton
|
||||
@action={{route-action "showLogin"}}
|
||||
@label="log_in"
|
||||
class="btn-flat invitation-cta__sign-in"
|
||||
<TogglePasswordMask
|
||||
@maskPassword={{this.maskPassword}}
|
||||
@togglePasswordMask={{this.togglePasswordMask}}
|
||||
@parentController="invites-show"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{{/unless}}
|
||||
|
||||
<div class="disclaimer">
|
||||
{{html-safe this.disclaimerHtml}}
|
||||
{{#if this.fullnameRequired}}
|
||||
<div
|
||||
class={{concat-class
|
||||
"input"
|
||||
"name-input"
|
||||
"input-group"
|
||||
(if this.siteSettings.full_name_required "name-required")
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
@value={{this.accountName}}
|
||||
class={{value-entered this.accountName}}
|
||||
id="new-account-name"
|
||||
name="name"
|
||||
/>
|
||||
<label class="alt-placeholder" for="new-account-name">
|
||||
{{i18n "invites.name_label"}}
|
||||
</label>
|
||||
<div class="instructions">{{this.nameInstructions}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.errorMessage}}
|
||||
<br /><br />
|
||||
<div class="alert alert-error">{{this.errorMessage}}</div>
|
||||
{{/if}}
|
||||
</form>
|
||||
{{/if}}
|
||||
{{#if this.existingUserRedeeming}}
|
||||
{{#if this.existingUserCanRedeem}}
|
||||
{{#if this.userFields}}
|
||||
<div class="user-fields">
|
||||
{{#each this.userFields as |f|}}
|
||||
<div class="input-group">
|
||||
<UserField
|
||||
@field={{f.field}}
|
||||
@value={{f.value}}
|
||||
class={{value-entered f.value}}
|
||||
/>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="invitation-cta">
|
||||
<DButton
|
||||
@action={{action "submit"}}
|
||||
@disabled={{this.submitDisabled}}
|
||||
@label="invites.accept_invite"
|
||||
type="submit"
|
||||
class="btn-primary"
|
||||
class="btn-primary invitation-cta__accept"
|
||||
/>
|
||||
{{else}}
|
||||
<div
|
||||
class="alert alert-error"
|
||||
>{{this.existingUserCanRedeemError}}</div>
|
||||
<div class="invitation-cta__info">
|
||||
<span class="invitation-cta__signed-up">{{i18n
|
||||
"login.previous_sign_up"
|
||||
}}</span>
|
||||
<DButton
|
||||
@action={{route-action "showLogin"}}
|
||||
@label="log_in"
|
||||
class="btn-flat invitation-cta__sign-in"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="disclaimer">
|
||||
{{html-safe this.disclaimerHtml}}
|
||||
</div>
|
||||
|
||||
{{#if this.errorMessage}}
|
||||
<br /><br />
|
||||
<div class="alert alert-error">{{this.errorMessage}}</div>
|
||||
{{/if}}
|
||||
</form>
|
||||
{{/if}}
|
||||
{{#if this.existingUserRedeeming}}
|
||||
{{#if this.existingUserCanRedeem}}
|
||||
<DButton
|
||||
@action={{action "submit"}}
|
||||
@disabled={{this.submitDisabled}}
|
||||
@label="invites.accept_invite"
|
||||
type="submit"
|
||||
class="btn-primary"
|
||||
/>
|
||||
{{else}}
|
||||
<div
|
||||
class="alert alert-error"
|
||||
>{{this.existingUserCanRedeemError}}</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -80,6 +80,7 @@ acceptance("Invite accept", function (needs) {
|
|||
});
|
||||
|
||||
test("invite link", async function (assert) {
|
||||
this.siteSettings.login_required = true;
|
||||
PreloadStore.store("invite_info", {
|
||||
invited_by: {
|
||||
id: 123,
|
||||
|
@ -166,7 +167,9 @@ acceptance("Invite accept", function (needs) {
|
|||
test("invite name is required only if full name is required", async function (assert) {
|
||||
preloadInvite();
|
||||
await visit("/invites/my-valid-invite-token");
|
||||
assert.dom(".name-input .required").exists("Full name is required");
|
||||
assert
|
||||
.dom(".name-input .required")
|
||||
.doesNotExist("Full name is implicitly required");
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,73 +1,70 @@
|
|||
// Styles used before the user is logged into discourse. For example, activating their
|
||||
// account or changing their email.
|
||||
|
||||
.account-activation-page {
|
||||
.desktop-view & {
|
||||
background: var(--primary-very-low);
|
||||
}
|
||||
#main-outlet-wrapper {
|
||||
display: block;
|
||||
.sidebar-wrapper {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.header-sidebar-toggle {
|
||||
display: none;
|
||||
}
|
||||
.account-created-page,
|
||||
.activate-account-page {
|
||||
background: var(--secondary);
|
||||
|
||||
#main-outlet {
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
#simple-container {
|
||||
}
|
||||
|
||||
.activate-account-page .alert-error {
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
.account-created,
|
||||
.activate-account {
|
||||
max-width: 500px;
|
||||
padding: 2rem 3rem;
|
||||
background: var(--secondary);
|
||||
box-shadow: var(--shadow-menu-panel);
|
||||
margin: 10vh auto 1em auto;
|
||||
@media screen and (max-height: 700px) {
|
||||
margin: 1em auto 1em auto;
|
||||
}
|
||||
}
|
||||
|
||||
.account-created {
|
||||
.ac-message {
|
||||
font-size: var(--font-up-1);
|
||||
line-height: var(--line-height-large);
|
||||
}
|
||||
.activation-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
border-radius: 10px;
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
justify-content: center;
|
||||
margin-top: var(--header-offset);
|
||||
.account-created {
|
||||
.ac-message {
|
||||
font-size: var(--font-up-1);
|
||||
line-height: var(--line-height-large);
|
||||
}
|
||||
.activation-controls {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5em;
|
||||
}
|
||||
.ac-page {
|
||||
border-radius: 10px;
|
||||
margin-top: 25px;
|
||||
}
|
||||
}
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.edit-cancel {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.success-info p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.activate-account {
|
||||
.activate-title {
|
||||
text-align: center;
|
||||
.waving-hand {
|
||||
height: 32px;
|
||||
margin-bottom: 13px;
|
||||
}
|
||||
}
|
||||
#activate-account-button {
|
||||
margin-top: 20px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
.activate-account-button,
|
||||
.continue-button {
|
||||
margin-top: 1em;
|
||||
margin-inline: auto;
|
||||
display: block;
|
||||
width: fit-content;
|
||||
}
|
||||
.perform-activation {
|
||||
border-top: 6px solid var(--tertiary);
|
||||
box-shadow: 0 1px 10px 1px rgba(var(--primary-low-rgb), 1.25);
|
||||
border-radius: 10px;
|
||||
padding: 1em 2.5em 1em 2.5em;
|
||||
.image {
|
||||
width: 150px;
|
||||
margin: auto;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
.login-welcome-header {
|
||||
margin-inline: auto;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.tada-image {
|
||||
width: 150px;
|
||||
margin: auto;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,16 +97,6 @@ body.invite-page {
|
|||
}
|
||||
}
|
||||
|
||||
.invite-error {
|
||||
box-shadow: 0 1px 10px 1px rgba(var(--primary-low-rgb), 1.25);
|
||||
border-radius: 10px;
|
||||
padding: 1em 2.5em 1em 2.5em;
|
||||
.error-image {
|
||||
text-align: center;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.email-login {
|
||||
border-radius: 10px;
|
||||
background-color: var(--secondary);
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
@import "sidebar/edit-navigation-menu/categories-modal";
|
||||
@import "sidebar/edit-navigation-menu/modal";
|
||||
@import "sidebar/edit-navigation-menu/tags-modal";
|
||||
@import "signup-progress-bar";
|
||||
@import "svg";
|
||||
@import "tap-tile";
|
||||
@import "time-input";
|
||||
|
@ -51,3 +52,4 @@
|
|||
@import "user-stream";
|
||||
@import "widget-dropdown";
|
||||
@import "dropdown-menu";
|
||||
@import "welcome-header";
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
.has-full-page-chat &,
|
||||
.static-login &,
|
||||
.invite-page &,
|
||||
.account-activation-page & {
|
||||
.account-created-page &,
|
||||
.activate-account-page & {
|
||||
display: none !important;
|
||||
}
|
||||
grid-area: below-content;
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
$progress-bar-line-width: 2px;
|
||||
$progress-bar-circle-size: 1.2rem;
|
||||
$progress-bar-icon-size: 0.8rem;
|
||||
|
||||
.signup-progress-bar {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
color: var(--primary-low-mid);
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 1.2em;
|
||||
|
||||
&__segment {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
|
||||
&:first-child .signup-progress-bar__circle {
|
||||
transform: translateX(50%);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
width: $progress-bar-circle-size;
|
||||
.signup-progress-bar__circle {
|
||||
transform: translateX(-50%);
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__step-text {
|
||||
white-space: nowrap;
|
||||
width: fit-content;
|
||||
transform: translateX(calc(calc($progress-bar-circle-size / 2) - 50%));
|
||||
|
||||
.signup-progress-bar__segment:first-child & {
|
||||
transform: translateX(0%);
|
||||
}
|
||||
|
||||
.signup-progress-bar__segment:last-child & {
|
||||
transform: translateX(
|
||||
calc(calc($progress-bar-circle-size + $progress-bar-line-width) - 100%)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
&__step {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&__line {
|
||||
transform: translateY(
|
||||
calc(calc($progress-bar-circle-size + $progress-bar-line-width) / 2)
|
||||
);
|
||||
height: $progress-bar-line-width;
|
||||
width: 100%;
|
||||
background-color: var(--primary-low-mid);
|
||||
}
|
||||
|
||||
&__circle {
|
||||
flex-shrink: 0;
|
||||
font-size: $progress-bar-icon-size;
|
||||
color: var(--secondary);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: $progress-bar-circle-size;
|
||||
width: $progress-bar-circle-size;
|
||||
border-radius: 50%;
|
||||
border: $progress-bar-line-width solid var(--primary-low-mid);
|
||||
background-color: var(--secondary);
|
||||
}
|
||||
|
||||
&__step.--completed {
|
||||
color: var(--primary);
|
||||
|
||||
.signup-progress-bar__circle {
|
||||
background-color: var(--success);
|
||||
border: $progress-bar-line-width solid var(--success);
|
||||
}
|
||||
}
|
||||
|
||||
&__line.--completed {
|
||||
background-color: var(--success);
|
||||
}
|
||||
|
||||
&__step.--active {
|
||||
.signup-progress-bar__circle {
|
||||
border: $progress-bar-line-width solid var(--success);
|
||||
}
|
||||
+ .signup-progress-bar__step-text {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
24
app/assets/stylesheets/common/components/welcome-header.scss
Normal file
24
app/assets/stylesheets/common/components/welcome-header.scss
Normal file
|
@ -0,0 +1,24 @@
|
|||
.login-welcome-header {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
grid-template-rows: auto 1fr;
|
||||
overflow-wrap: anywhere;
|
||||
|
||||
.login-title {
|
||||
font-size: var(--font-up-6);
|
||||
margin: 0;
|
||||
line-height: var(--line-height-medium);
|
||||
}
|
||||
|
||||
.login-subheader {
|
||||
font-size: var(--font-up-1);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.waving-hand {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
margin-left: 0.5em;
|
||||
align-self: center;
|
||||
}
|
||||
}
|
|
@ -2,28 +2,8 @@
|
|||
padding: 2rem 3rem;
|
||||
background: var(--secondary);
|
||||
|
||||
.login-welcome-header {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
grid-template-rows: auto 1fr;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.login-title {
|
||||
font-size: var(--font-up-6);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.waving-hand {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
margin-left: 0.5em;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.login-subheader {
|
||||
font-size: var(--font-up-1);
|
||||
margin: 0;
|
||||
.success-info p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
|
@ -36,10 +16,6 @@
|
|||
height: 30px;
|
||||
}
|
||||
|
||||
.col-image {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.create-account__password {
|
||||
&-info {
|
||||
display: flex;
|
||||
|
@ -65,4 +41,17 @@
|
|||
color: var(--primary-medium);
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
.invite-form form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.input-group {
|
||||
&.email-input,
|
||||
&.username-input,
|
||||
&.name-input.name-required {
|
||||
order: -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,11 +36,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.login-subheader {
|
||||
font-size: var(--font-up-1);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.login-left-side {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
|
@ -48,25 +43,6 @@
|
|||
overflow: auto;
|
||||
}
|
||||
|
||||
.login-welcome-header {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
grid-template-rows: auto 1fr;
|
||||
}
|
||||
|
||||
.login-title {
|
||||
font-size: var(--font-up-6);
|
||||
margin: 0;
|
||||
line-height: var(--line-height-medium);
|
||||
}
|
||||
|
||||
.waving-hand {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
margin-left: 0.5em;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.login-right-side {
|
||||
background: var(--tertiary-or-tertiary-low);
|
||||
padding: 3.5rem 3rem;
|
||||
|
@ -151,13 +127,12 @@
|
|||
flex-direction: column;
|
||||
overflow: auto;
|
||||
gap: 1em;
|
||||
.login-welcome-header,
|
||||
.d-modal__footer {
|
||||
font-size: var(--font-down-1);
|
||||
}
|
||||
.login-left-side {
|
||||
overflow: unset;
|
||||
padding: 1em 2.75em 1em 1em;
|
||||
padding: 1em;
|
||||
}
|
||||
.login-right-side {
|
||||
padding: 1em;
|
||||
|
@ -166,6 +141,9 @@
|
|||
#login-form {
|
||||
margin: 1.5em 0;
|
||||
}
|
||||
.signup-progress-bar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -173,7 +151,14 @@
|
|||
/* end shared styles */
|
||||
|
||||
.d-modal.create-account {
|
||||
&:not(:has(.has-alt-auth)) .d-modal__container {
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.d-modal {
|
||||
&__container {
|
||||
width: 100%;
|
||||
}
|
||||
&__footer {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
.invite-page {
|
||||
background: var(--primary-50);
|
||||
background: var(--secondary);
|
||||
}
|
||||
|
||||
.invites-show {
|
||||
.invites-show,
|
||||
#simple-container .invite-error {
|
||||
max-width: 500px;
|
||||
padding: 2rem 3rem;
|
||||
background: var(--secondary);
|
||||
|
@ -12,3 +13,14 @@
|
|||
margin: 1em auto 1em auto;
|
||||
}
|
||||
}
|
||||
|
||||
#simple-container .invite-error {
|
||||
.error-info {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.error-image {
|
||||
text-align: center;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,3 +4,4 @@
|
|||
@import "topic-map";
|
||||
@import "user-card";
|
||||
@import "user-stream-item";
|
||||
@import "welcome-header";
|
||||
|
|
14
app/assets/stylesheets/mobile/components/welcome-header.scss
Normal file
14
app/assets/stylesheets/mobile/components/welcome-header.scss
Normal file
|
@ -0,0 +1,14 @@
|
|||
.login-welcome-header {
|
||||
.login-title {
|
||||
font-size: var(--font-up-5);
|
||||
}
|
||||
|
||||
.login-subheader {
|
||||
font-size: var(--font-0);
|
||||
}
|
||||
|
||||
.waving-hand {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
}
|
|
@ -97,3 +97,21 @@
|
|||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.d-modal.create-account {
|
||||
.d-modal__footer-buttons {
|
||||
flex-direction: row;
|
||||
gap: 8px;
|
||||
button {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.login-welcome-header {
|
||||
padding-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.signup-progress-bar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2336,6 +2336,11 @@ en:
|
|||
associate: "Already have an account? <a href='%{associate_link}'>Log In</a> to link your %{provider} account."
|
||||
activation_title: "Activate your account"
|
||||
already_have_account: "Already have an account?"
|
||||
progress_bar:
|
||||
signup: "Sign Up"
|
||||
activate: "Activate"
|
||||
approve: "Approve"
|
||||
login: "Log In"
|
||||
|
||||
forgot_password:
|
||||
title: "Password Reset"
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 47.5 47.5" style="enable-background:new 0 0 47.5 47.5;" xml:space="preserve" version="1.1" id="svg2"><metadata id="metadata8"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata><defs id="defs6"><clipPath id="clipPath16" clipPathUnits="userSpaceOnUse"><path id="path18" d="M 0,38 38,38 38,0 0,0 0,38 Z"/></clipPath></defs><g transform="matrix(1.25,0,0,-1.25,0,47.5)" id="g10"><g id="g12"><g clip-path="url(#clipPath16)" id="g14"><g transform="translate(37,10)" id="g20"><path id="path22" style="fill:#ccd6dd;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 0,0 c 0,-2.209 -1.791,-4 -4,-4 l -28,0 c -2.209,0 -4,1.791 -4,4 l 0,18 c 0,2.209 1.791,4 4,4 l 28,0 c 2.209,0 4,-1.791 4,-4 L 0,0 Z"/></g><g transform="translate(12.9497,19.3643)" id="g24"><path id="path26" style="fill:#99aab5;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 0,0 -11.313,-11.313 c -0.027,-0.028 -0.037,-0.063 -0.06,-0.091 0.34,-0.571 0.814,-1.043 1.384,-1.384 0.029,0.023 0.063,0.033 0.09,0.059 L 1.415,-1.414 c 0.39,0.391 0.39,1.022 0,1.414 C 1.023,0.391 0.391,0.391 0,0"/></g><g transform="translate(36.4229,7.96)" id="g28"><path id="path30" style="fill:#99aab5;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 0,0 c -0.021,0.028 -0.033,0.063 -0.06,0.09 l -11.312,11.314 c -0.392,0.391 -1.024,0.391 -1.415,0 -0.391,-0.391 -0.391,-1.023 0,-1.414 L -1.474,-1.324 c 0.027,-0.027 0.062,-0.037 0.09,-0.06 C -0.812,-1.044 -0.34,-0.57 0,0"/></g><g transform="translate(33,32)" id="g32"><path id="path34" style="fill:#99aab5;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 0,0 -28,0 c -2.209,0 -4,-1.791 -4,-4 l 0,-1.03 14.528,-14.495 c 1.894,-1.894 4.988,-1.894 6.884,0 L 4,-5.009 4,-4 C 4,-1.791 2.209,0 0,0"/></g><g transform="translate(33,32)" id="g36"><path id="path38" style="fill:#e1e8ed;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 0,0 -28,0 c -1.588,0 -2.949,-0.934 -3.595,-2.275 l 14.766,-14.767 c 1.562,-1.562 4.096,-1.562 5.657,0 L 3.595,-2.275 C 2.949,-0.934 1.589,0 0,0"/></g></g></g></g></svg>
|
Before Width: | Height: | Size: 2.3 KiB |
|
@ -4,15 +4,15 @@ module PageObjects
|
|||
module Pages
|
||||
class ActivateAccount < PageObjects::Pages::Base
|
||||
def click_activate_account
|
||||
find("#activate-account-button").click
|
||||
find(".activate-account-button").click
|
||||
end
|
||||
|
||||
def click_continue
|
||||
find(".perform-activation .continue-button").click
|
||||
find(".account-activated .continue-button").click
|
||||
end
|
||||
|
||||
def has_error?
|
||||
has_css?("#simple-container .alert-error")
|
||||
has_css?(".alert-error")
|
||||
has_content?(I18n.t("js.user.activate_account.already_done"))
|
||||
end
|
||||
end
|
||||
|
|
|
@ -30,7 +30,7 @@ describe "Account activation", type: :system do
|
|||
|
||||
expect(user.reload.active).to eq(false)
|
||||
|
||||
find("#activate-account-button").click
|
||||
find(".activate-account-button").click
|
||||
|
||||
wait_for(timeout: 5) { user.reload.active }
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue
Block a user