mirror of
https://github.com/astuto/astuto.git
synced 2025-12-16 03:37:56 +01:00
Improve tenant signup page (#302)
This commit is contained in:
committed by
GitHub
parent
4969bbc261
commit
719f1ad4e9
BIN
app/assets/images/blocked-tenant.png
Normal file
BIN
app/assets/images/blocked-tenant.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
BIN
app/assets/images/favicon.png
Normal file
BIN
app/assets/images/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
BIN
app/assets/images/logo.png
Normal file
BIN
app/assets/images/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.6 KiB |
BIN
app/assets/images/pending-tenant.png
Normal file
BIN
app/assets/images/pending-tenant.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
@@ -152,6 +152,9 @@
|
|||||||
.postEditFormButtons {
|
.postEditFormButtons {
|
||||||
@extend .d-flex, .justify-content-end;
|
@extend .d-flex, .justify-content-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#selectPickerBoard { margin-right: 4px !important; }
|
||||||
|
#selectPickerStatus { margin-left: 4px !important; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,41 @@
|
|||||||
|
.astutoLogo {
|
||||||
|
display: block;
|
||||||
|
margin: 12px auto;
|
||||||
|
}
|
||||||
|
|
||||||
.tenantSignUpContainer {
|
.tenantSignUpContainer {
|
||||||
@extend .smallContainer;
|
@extend .smallContainer;
|
||||||
|
|
||||||
|
h1, h2, h3 {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.userConfirm, .tenantConfirm {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.userPasswordDiv, .userPasswordConfirmationDiv {
|
||||||
|
@extend .col-6;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.userPasswordDiv { padding-right: 4px; }
|
||||||
|
.userPasswordConfirmationDiv { padding-left: 4px; }
|
||||||
|
|
||||||
|
.userRecap {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
|
.editUser {
|
||||||
|
display: block;
|
||||||
|
width: fit-content;
|
||||||
|
margin-top: 4px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ class TenantsController < ApplicationController
|
|||||||
before_action :authenticate_admin, only: [:show, :update]
|
before_action :authenticate_admin, only: [:show, :update]
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@page_title = t('signup.page_title')
|
@page_title = "Create your feedback space"
|
||||||
@o_auths = OAuth.unscoped.where(tenant_id: nil)
|
@o_auths = OAuth.unscoped.where(tenant_id: nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,25 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import I18n from 'i18n-js';
|
|
||||||
import Box from '../common/Box';
|
import Box from '../common/Box';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
subdomain: string;
|
subdomain: string;
|
||||||
userEmail: string;
|
userEmail: string;
|
||||||
|
pendingTenantImage: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ConfirmSignUpPage = ({
|
const ConfirmSignUpPage = ({
|
||||||
subdomain,
|
subdomain,
|
||||||
userEmail,
|
userEmail,
|
||||||
|
pendingTenantImage,
|
||||||
}: Props) => (
|
}: Props) => (
|
||||||
<Box>
|
<Box>
|
||||||
<h3>{ I18n.t('signup.step3.title') }</h3>
|
<h3>You're almost done!</h3>
|
||||||
|
|
||||||
<p>{ I18n.t('signup.step3.message', { email: userEmail, subdomain: `${subdomain}.astuto.io` }) }</p>
|
<img src={pendingTenantImage} width={64} height={64} style={{margin: '12px auto'}} />
|
||||||
|
|
||||||
|
<p style={{textAlign: 'center'}}>
|
||||||
|
Check your email <b>{userEmail}</b> to activate your new feedback space {subdomain}.astuto.io!
|
||||||
|
</p>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { SubmitHandler, useForm } from 'react-hook-form';
|
import { SubmitHandler, useForm } from 'react-hook-form';
|
||||||
import I18n from 'i18n-js';
|
|
||||||
|
|
||||||
import Box from '../common/Box';
|
import Box from '../common/Box';
|
||||||
import Button from '../common/Button';
|
import Button from '../common/Button';
|
||||||
@@ -28,7 +27,7 @@ const TenantSignUpForm = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box customClass="tenantSignUpStep2">
|
<Box customClass="tenantSignUpStep2">
|
||||||
<h3>{ I18n.t('signup.step2.title') }</h3>
|
<h3>Create feedback space</h3>
|
||||||
|
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
<div className="formRow">
|
<div className="formRow">
|
||||||
@@ -68,10 +67,10 @@ const TenantSignUpForm = ({
|
|||||||
{errors.subdomain?.type === 'required' && getValidationMessage('required', 'tenant', 'subdomain')}
|
{errors.subdomain?.type === 'required' && getValidationMessage('required', 'tenant', 'subdomain')}
|
||||||
</DangerText>
|
</DangerText>
|
||||||
<DangerText>
|
<DangerText>
|
||||||
{errors.subdomain?.type === 'pattern' && I18n.t('signup.step2.validations.subdomain_only_letters_and_numbers')}
|
{errors.subdomain?.type === 'pattern' && 'Subdomain can only contain alphanumeric characters and hyphens'}
|
||||||
</DangerText>
|
</DangerText>
|
||||||
<DangerText>
|
<DangerText>
|
||||||
{errors.subdomain?.type === 'notAlreadyTaken' && I18n.t('signup.step2.validations.subdomain_already_taken')}
|
{errors.subdomain?.type === 'notAlreadyTaken' && 'Sorry, this subdomain is not available'}
|
||||||
</DangerText>
|
</DangerText>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -79,7 +78,7 @@ const TenantSignUpForm = ({
|
|||||||
onClick={() => null}
|
onClick={() => null}
|
||||||
className="tenantConfirm"
|
className="tenantConfirm"
|
||||||
>
|
>
|
||||||
{ isSubmitting ? <Spinner /> : I18n.t('signup.step2.create_button') }
|
{ isSubmitting ? <Spinner /> : 'Create feedback space' }
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{ error !== '' && <DangerText>{ error }</DangerText> }
|
{ error !== '' && <DangerText>{ error }</DangerText> }
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ interface Props {
|
|||||||
authenticityToken: string,
|
authenticityToken: string,
|
||||||
): Promise<any>;
|
): Promise<any>;
|
||||||
|
|
||||||
|
astutoLogoImage: string;
|
||||||
|
pendingTenantImage: string;
|
||||||
|
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
authenticityToken: string;
|
authenticityToken: string;
|
||||||
}
|
}
|
||||||
@@ -50,6 +53,8 @@ const TenantSignUpP = ({
|
|||||||
isSubmitting,
|
isSubmitting,
|
||||||
error,
|
error,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
|
astutoLogoImage,
|
||||||
|
pendingTenantImage,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
authenticityToken
|
authenticityToken
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
@@ -93,6 +98,9 @@ const TenantSignUpP = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<img src={astutoLogoImage} width={64} height={64} className="astutoLogo" />
|
||||||
|
|
||||||
<div className="tenantSignUpContainer">
|
<div className="tenantSignUpContainer">
|
||||||
{
|
{
|
||||||
(currentStep === 1 || currentStep === 2) &&
|
(currentStep === 1 || currentStep === 2) &&
|
||||||
@@ -124,9 +132,11 @@ const TenantSignUpP = ({
|
|||||||
<ConfirmSignUpPage
|
<ConfirmSignUpPage
|
||||||
subdomain={tenantData.subdomain}
|
subdomain={tenantData.subdomain}
|
||||||
userEmail={userData.email}
|
userEmail={userData.email}
|
||||||
|
pendingTenantImage={pendingTenantImage}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { getLabel, getValidationMessage } from '../../helpers/formUtils';
|
|||||||
import { EMAIL_REGEX } from '../../constants/regex';
|
import { EMAIL_REGEX } from '../../constants/regex';
|
||||||
import { IOAuth } from '../../interfaces/IOAuth';
|
import { IOAuth } from '../../interfaces/IOAuth';
|
||||||
import ActionLink from '../common/ActionLink';
|
import ActionLink from '../common/ActionLink';
|
||||||
import { BackIcon } from '../common/Icons';
|
import { BackIcon, EditIcon } from '../common/Icons';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
currentStep: number;
|
currentStep: number;
|
||||||
@@ -47,7 +47,7 @@ const UserSignUpForm = ({
|
|||||||
} = useForm<ITenantSignUpUserForm>();
|
} = useForm<ITenantSignUpUserForm>();
|
||||||
const onSubmit: SubmitHandler<ITenantSignUpUserForm> = data => {
|
const onSubmit: SubmitHandler<ITenantSignUpUserForm> = data => {
|
||||||
if (data.password !== data.passwordConfirmation) {
|
if (data.password !== data.passwordConfirmation) {
|
||||||
setError('passwordConfirmation', I18n.t('signup.step1.validations.password_mismatch'));
|
setError('passwordConfirmation', I18n.t('common.validations.password_mismatch'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,13 +57,13 @@ const UserSignUpForm = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box customClass="tenantSignUpStep1">
|
<Box customClass="tenantSignUpStep1">
|
||||||
<h3>{ I18n.t('signup.step1.title') }</h3>
|
<h3>Create user account</h3>
|
||||||
|
|
||||||
{
|
{
|
||||||
currentStep === 1 && !emailAuth &&
|
currentStep === 1 && !emailAuth &&
|
||||||
<>
|
<>
|
||||||
<Button className="emailAuth" onClick={() => setEmailAuth(true)}>
|
<Button className="emailAuth" onClick={() => setEmailAuth(true)}>
|
||||||
{ I18n.t('signup.step1.email_auth') }
|
Sign up with email
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -118,7 +118,7 @@ const UserSignUpForm = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="formRow">
|
<div className="formRow">
|
||||||
<div className="formGroup col-6">
|
<div className="userPasswordDiv">
|
||||||
<input
|
<input
|
||||||
{...register('password', { required: true, minLength: 6, maxLength: 128 })}
|
{...register('password', { required: true, minLength: 6, maxLength: 128 })}
|
||||||
type="password"
|
type="password"
|
||||||
@@ -129,7 +129,7 @@ const UserSignUpForm = ({
|
|||||||
<DangerText>{ errors.password && I18n.t('common.validations.password', { n: 6 }) }</DangerText>
|
<DangerText>{ errors.password && I18n.t('common.validations.password', { n: 6 }) }</DangerText>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="formGroup col-6">
|
<div className="userPasswordConfirmationDiv">
|
||||||
<input
|
<input
|
||||||
{...register('passwordConfirmation')}
|
{...register('passwordConfirmation')}
|
||||||
type="password"
|
type="password"
|
||||||
@@ -152,12 +152,10 @@ const UserSignUpForm = ({
|
|||||||
|
|
||||||
{
|
{
|
||||||
currentStep === 2 && !oAuthLoginCompleted &&
|
currentStep === 2 && !oAuthLoginCompleted &&
|
||||||
<p><b>{userData.fullName}</b> ({userData.email})</p>
|
<p className="userRecap">
|
||||||
}
|
<b>{oAuthLoginCompleted ? oauthUserName : userData.fullName}</b> ({oAuthLoginCompleted ? oauthUserEmail : userData.email})
|
||||||
|
<ActionLink onClick={() => setCurrentStep(currentStep-1)} icon={<EditIcon />} customClass="editUser">Edit</ActionLink>
|
||||||
{
|
</p>
|
||||||
currentStep === 2 && oAuthLoginCompleted &&
|
|
||||||
<p><b>{oauthUserName}</b> ({oauthUserEmail})</p>
|
|
||||||
}
|
}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ interface Props {
|
|||||||
oauthUserEmail?: string;
|
oauthUserEmail?: string;
|
||||||
oauthUserName?: string;
|
oauthUserName?: string;
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
|
astutoLogoImage: string;
|
||||||
|
pendingTenantImage: string;
|
||||||
authenticityToken: string;
|
authenticityToken: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,6 +33,8 @@ class TenantSignUpRoot extends React.Component<Props> {
|
|||||||
oAuthLoginCompleted,
|
oAuthLoginCompleted,
|
||||||
oauthUserEmail,
|
oauthUserEmail,
|
||||||
oauthUserName,
|
oauthUserName,
|
||||||
|
astutoLogoImage,
|
||||||
|
pendingTenantImage,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
authenticityToken,
|
authenticityToken,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
@@ -42,6 +46,8 @@ class TenantSignUpRoot extends React.Component<Props> {
|
|||||||
oauthUserEmail={oauthUserEmail}
|
oauthUserEmail={oauthUserEmail}
|
||||||
oauthUserName={oauthUserName}
|
oauthUserName={oauthUserName}
|
||||||
oAuths={oAuths.map(oAuth => oAuthJSON2JS(oAuth))}
|
oAuths={oAuths.map(oAuth => oAuthJSON2JS(oAuth))}
|
||||||
|
astutoLogoImage={astutoLogoImage}
|
||||||
|
pendingTenantImage={pendingTenantImage}
|
||||||
baseUrl={baseUrl}
|
baseUrl={baseUrl}
|
||||||
authenticityToken={authenticityToken}
|
authenticityToken={authenticityToken}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
|
|
||||||
<%= javascript_include_tag "application", "data-turbo-track": "reload" %>
|
<%= javascript_include_tag "application", "data-turbo-track": "reload" %>
|
||||||
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
|
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
|
||||||
|
|
||||||
|
<%= favicon_link_tag asset_path('favicon.png') %>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<div class="smallContainer">
|
<div class="smallContainer">
|
||||||
<div class="box">
|
<div class="box" style="text-align: center">
|
||||||
<h3><%= t('blocked_tenant.title') %></h3>
|
<h3><%= t('blocked_tenant.title') %></h3>
|
||||||
|
|
||||||
|
<%= image_tag("blocked-tenant.png", size: 64, style: "margin: 0 auto") %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,6 +1,16 @@
|
|||||||
<div class="smallContainer">
|
<div class="smallContainer">
|
||||||
<div class="box">
|
<div class="box" style="text-align: center">
|
||||||
<h3><%= t('pending_tenant.title') %></h3>
|
<h3>Verify your email address</h3>
|
||||||
<p><%= t('pending_tenant.message') %></p>
|
|
||||||
|
<%= image_tag("pending-tenant.png", size: 64, style: "margin: 0 auto") %>
|
||||||
|
|
||||||
|
<p>Please check your email inbox (and your spam folder!) and click on the activation link.</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Need help?
|
||||||
|
<a href=<%= "mailto:info@astuto.io?subject=[SUPPORT]%20Unable%20to%20activate%20my%20feedback%20space&body=I%20need%20help%20activating%20my%20feedback%20space%20'#{request.subdomain}'" %>>
|
||||||
|
Contact us.
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -7,6 +7,8 @@
|
|||||||
oauthUserEmail: @user_email,
|
oauthUserEmail: @user_email,
|
||||||
oauthUserName: @user_name,
|
oauthUserName: @user_name,
|
||||||
baseUrl: Rails.application.base_url,
|
baseUrl: Rails.application.base_url,
|
||||||
|
astutoLogoImage: image_url("logo.png"),
|
||||||
|
pendingTenantImage: image_url("pending-tenant.png"),
|
||||||
authenticityToken: form_authenticity_token
|
authenticityToken: form_authenticity_token
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -68,20 +68,6 @@ en:
|
|||||||
days:
|
days:
|
||||||
one: '1 day ago'
|
one: '1 day ago'
|
||||||
other: '%{count} days ago'
|
other: '%{count} days ago'
|
||||||
signup:
|
|
||||||
page_title: 'Create your feedback space'
|
|
||||||
step1:
|
|
||||||
title: '1. Create user account'
|
|
||||||
email_auth: 'Sign up with email'
|
|
||||||
step2:
|
|
||||||
title: '2. Create feedback space'
|
|
||||||
create_button: 'Create feedback space'
|
|
||||||
validations:
|
|
||||||
subdomain_already_taken: 'Sorry, this subdomain is not available'
|
|
||||||
subdomain_only_letters_and_numbers: 'Subdomain can only contain alphanumeric characters and hyphen'
|
|
||||||
step3:
|
|
||||||
title: "You're almost done!"
|
|
||||||
message: "Check your email %{email} to activate your new feedback space %{subdomain}!"
|
|
||||||
header:
|
header:
|
||||||
menu:
|
menu:
|
||||||
site_settings: 'Site settings'
|
site_settings: 'Site settings'
|
||||||
@@ -90,9 +76,6 @@ en:
|
|||||||
log_in: 'Log in / Sign up'
|
log_in: 'Log in / Sign up'
|
||||||
roadmap:
|
roadmap:
|
||||||
title: 'Roadmap'
|
title: 'Roadmap'
|
||||||
pending_tenant:
|
|
||||||
title: 'Verify your email address'
|
|
||||||
message: 'We''ve sent an email with an activation link to the email you provided during registration. Click on that link to activate this feedback space!'
|
|
||||||
blocked_tenant:
|
blocked_tenant:
|
||||||
title: 'This feedback space has been blocked'
|
title: 'This feedback space has been blocked'
|
||||||
board:
|
board:
|
||||||
|
|||||||
Reference in New Issue
Block a user