-
Notifications
You must be signed in to change notification settings - Fork 157
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(onboarding-ui): Self-hosted registration (#501)
* Add prototype of self-hosted registration * Add more details to the flow * Fix Callout icon color * Refactor form state * fix: validation * Refactor form validation * Improve AdminInfoForm validation * Update Loki references * Add more details * improve: email confirmation * Trim dummy comment Co-authored-by: dougfabris <devfabris@gmail.com>
- Loading branch information
1 parent
9a7f3d5
commit e47d579
Showing
52 changed files
with
426 additions
and
116 deletions.
There are no files selected for viewing
Binary file modified
BIN
-335 Bytes
(99%)
packages/fuselage/.loki/reference/chrome_iphone7_Misc_Callout_Default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
-307 Bytes
(99%)
packages/fuselage/.loki/reference/chrome_iphone7_Misc_Callout_With_Description.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
-354 Bytes
(99%)
.../fuselage/.loki/reference/chrome_iphone7_Misc_Callout_With_Description_Only.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
-51 Bytes
(100%)
packages/fuselage/.loki/reference/chrome_iphone7_Playground_Default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
-37 Bytes
(100%)
packages/fuselage/.loki/reference/chrome_laptop_Misc_Callout_Default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
-43 Bytes
(100%)
packages/fuselage/.loki/reference/chrome_laptop_Misc_Callout_With_Description.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
-52 Bytes
(100%)
...s/fuselage/.loki/reference/chrome_laptop_Misc_Callout_With_Description_Only.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+5 Bytes
(100%)
packages/fuselage/.loki/reference/chrome_laptop_Playground_Default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file modified
BIN
+153 Bytes
(100%)
...ges/onboarding-ui/.loki/reference/desktop_forms_AdminInfoForm_AdminInfoForm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+142 Bytes
(100%)
...-ui/.loki/reference/desktop_forms_OrganizationInfoForm_OrganizationInfoForm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed
BIN
-6.46 KB
...g-ui/.loki/reference/desktop_forms_RegisterServerForm_OptionCard_OptionCard.png
Binary file not shown.
Binary file removed
BIN
-6.48 KB
...i/reference/desktop_forms_RegisterServerForm_OptionCard_OptionCard_Selected.png
Binary file not shown.
Binary file modified
BIN
+76 Bytes
(100%)
...ding-ui/.loki/reference/desktop_forms_RegisterServerForm_RegisterServerForm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+342 Bytes
(100%)
...ges/onboarding-ui/.loki/reference/desktop_pages_AdminInfoPage_AdminInfoPage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+189 Bytes
(100%)
...i/.loki/reference/desktop_pages_CloudAccountEmailPage_CloudAccountEmailPage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+320 Bytes
(100%)
...-ui/.loki/reference/desktop_pages_OrganizationInfoPage_OrganizationInfoPage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+189 Bytes
(100%)
...ding-ui/.loki/reference/desktop_pages_RegisterServerPage_RegisterServerPage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+515 Bytes
(100%)
...ages/onboarding-ui/.loki/reference/mobile_forms_AdminInfoForm_AdminInfoForm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+356 Bytes
(100%)
...g-ui/.loki/reference/mobile_forms_OrganizationInfoForm_OrganizationInfoForm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed
BIN
-13.4 KB
...ng-ui/.loki/reference/mobile_forms_RegisterServerForm_OptionCard_OptionCard.png
Binary file not shown.
Binary file removed
BIN
-13.5 KB
...ki/reference/mobile_forms_RegisterServerForm_OptionCard_OptionCard_Selected.png
Binary file not shown.
Binary file modified
BIN
-117 Bytes
(100%)
...rding-ui/.loki/reference/mobile_forms_RegisterServerForm_RegisterServerForm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+935 Bytes
(100%)
...ages/onboarding-ui/.loki/reference/mobile_pages_AdminInfoPage_AdminInfoPage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+416 Bytes
(100%)
...ui/.loki/reference/mobile_pages_CloudAccountEmailPage_CloudAccountEmailPage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+825 Bytes
(100%)
...g-ui/.loki/reference/mobile_pages_OrganizationInfoPage_OrganizationInfoPage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+13 Bytes
(100%)
...rding-ui/.loki/reference/mobile_pages_RegisterServerPage_RegisterServerPage.png
Oops, something went wrong.
Binary file modified
BIN
+153 Bytes
(100%)
...ages/onboarding-ui/.loki/reference/tablet_forms_AdminInfoForm_AdminInfoForm.png
Oops, something went wrong.
Binary file modified
BIN
+142 Bytes
(100%)
...g-ui/.loki/reference/tablet_forms_OrganizationInfoForm_OrganizationInfoForm.png
Oops, something went wrong.
Binary file removed
BIN
-5.88 KB
...ng-ui/.loki/reference/tablet_forms_RegisterServerForm_OptionCard_OptionCard.png
Diff not rendered.
Binary file removed
BIN
-5.9 KB
...ki/reference/tablet_forms_RegisterServerForm_OptionCard_OptionCard_Selected.png
Diff not rendered.
Binary file modified
BIN
+81 Bytes
(100%)
...rding-ui/.loki/reference/tablet_forms_RegisterServerForm_RegisterServerForm.png
Oops, something went wrong.
Binary file modified
BIN
+341 Bytes
(100%)
...ages/onboarding-ui/.loki/reference/tablet_pages_AdminInfoPage_AdminInfoPage.png
Oops, something went wrong.
Binary file modified
BIN
+162 Bytes
(100%)
...ui/.loki/reference/tablet_pages_CloudAccountEmailPage_CloudAccountEmailPage.png
Oops, something went wrong.
Binary file modified
BIN
+333 Bytes
(100%)
...g-ui/.loki/reference/tablet_pages_OrganizationInfoPage_OrganizationInfoPage.png
Oops, something went wrong.
Binary file modified
BIN
+193 Bytes
(100%)
...rding-ui/.loki/reference/tablet_pages_RegisterServerPage_RegisterServerPage.png
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
104 changes: 104 additions & 0 deletions
104
packages/onboarding-ui/src/flows/SelfHostedRegistration/mocks.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import { action } from '@storybook/addon-actions'; | ||
import { countries } from 'countries-list'; | ||
import type { Validate } from 'react-hook-form'; | ||
|
||
export const logSubmit = | ||
<T extends (...args: any[]) => any>(onSubmit: T) => | ||
(...args: Parameters<T>): ReturnType<T> => { | ||
action('submit')(...args); | ||
return onSubmit(...args); | ||
}; | ||
|
||
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); | ||
|
||
const simulateNetworkDelay = () => delay(3000 * Math.random()); | ||
|
||
const fetchMock = | ||
<T extends (...args: any[]) => any>(endpoint: string, handler: T) => | ||
async (...args: Parameters<T>): Promise<ReturnType<T>> => { | ||
action(`fetch(${endpoint})`)(...args); | ||
await simulateNetworkDelay(); | ||
return handler(...args); | ||
}; | ||
|
||
export const validateUsername = fetchMock( | ||
'/username/validate', | ||
(username: string) => { | ||
if (username === 'admin') { | ||
return `Username "${username}" is not available`; | ||
} | ||
|
||
return true; | ||
} | ||
); | ||
|
||
export const validateEmail = fetchMock('/email/validate', (email: string) => { | ||
if (email === 'admin@rocket.chat') { | ||
return `Email "${email}" is already in use`; | ||
} | ||
|
||
return true; | ||
}); | ||
|
||
export const validatePassword: Validate<string> = (password: string) => { | ||
if (password.length < 6) { | ||
return `Password is too short`; | ||
} | ||
|
||
return true; | ||
}; | ||
|
||
export const organizationTypes: [string, string][] = [ | ||
['community', 'Community'], | ||
['enterprise', 'Enterprise'], | ||
['government', 'Government'], | ||
['nonprofit', 'Nonprofit'], | ||
]; | ||
|
||
export const organizationIndustryOptions: [string, string][] = [ | ||
['aerospaceDefense', 'Aerospace and Defense'], | ||
['blockchain', 'Blockchain'], | ||
['consulting', 'Consulting'], | ||
['consumerGoods', 'Consumer Packaged Goods'], | ||
['contactCenter', 'Contact Center'], | ||
['education', 'Education'], | ||
['entertainment', 'Entertainment'], | ||
['financialServices', 'Financial Services'], | ||
['gaming', 'Gaming'], | ||
['healthcare', 'Healthcare'], | ||
['hospitalityBusinness', 'Hospitality Businness'], | ||
['insurance', 'Insurance'], | ||
['itSecurity', 'IT Security'], | ||
['logistics', 'Logistics'], | ||
['manufacturing', 'Manufacturing'], | ||
['media', 'Media'], | ||
['pharmaceutical', 'Pharmaceutical'], | ||
['realEstate', 'Real Estate'], | ||
['religious', 'Religious'], | ||
['retail', 'Retail'], | ||
['socialNetwork', 'Social Network'], | ||
['technologyProvider', 'Technology Provider'], | ||
['technologyServices', 'Technology Services'], | ||
['telecom', 'Telecom'], | ||
['utilities', 'Utilities'], | ||
['other', 'Other'], | ||
]; | ||
|
||
export const organizationSizeOptions: [string, string][] = [ | ||
['0', '1-10 people'], | ||
['1', '11-50 people'], | ||
['2', '51-100 people'], | ||
['3', '101-250 people'], | ||
['4', '251-500 people'], | ||
['5', '501-1000 people'], | ||
['6', '1001-4000 people'], | ||
['7', '4000 or more people'], | ||
]; | ||
|
||
export const countryOptions: [string, string][] = [ | ||
...Object.entries(countries).map<[string, string]>(([code, { name }]) => [ | ||
code, | ||
name, | ||
]), | ||
['worldwide', 'Worldwide'], | ||
]; |
219 changes: 219 additions & 0 deletions
219
packages/onboarding-ui/src/flows/SelfHostedRegistration/stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
import { Box, Callout } from '@rocket.chat/fuselage'; | ||
import type { Meta, Story } from '@storybook/react'; | ||
import { useState } from 'react'; | ||
|
||
import type { AdminInfoPayload } from '../../forms/AdminInfoForm/AdminInfoForm'; | ||
import type { CloudAccountEmailPayload } from '../../forms/CloudAccountEmailForm/CloudAccountEmailForm'; | ||
import type { OrganizationInfoPayload } from '../../forms/OrganizationInfoForm/OrganizationInfoForm'; | ||
import type { RegisterServerPayload } from '../../forms/RegisterServerForm/RegisterServerForm'; | ||
import AdminInfoPage from '../../pages/AdminInfoPage'; | ||
import AwaitingConfirmationPage from '../../pages/AwaitingConfirmationPage'; | ||
import CloudAccountEmailPage from '../../pages/CloudAccountEmailPage'; | ||
import ConfirmationProcessPage from '../../pages/ConfirmationProcessPage'; | ||
import EmailConfirmedPage from '../../pages/EmailConfirmedPage'; | ||
import OrganizationInfoPage from '../../pages/OrganizationInfoPage'; | ||
import RegisterServerPage from '../../pages/RegisterServerPage'; | ||
import { | ||
countryOptions, | ||
logSubmit, | ||
organizationIndustryOptions, | ||
organizationSizeOptions, | ||
organizationTypes, | ||
validateEmail, | ||
validatePassword, | ||
validateUsername, | ||
} from './mocks'; | ||
|
||
export default { | ||
title: 'flows/Self-Hosted Registration', | ||
parameters: { | ||
layout: 'fullscreen', | ||
actions: { argTypesRegex: '^on.*' }, | ||
loki: { skip: true }, | ||
}, | ||
} as Meta; | ||
|
||
export const SelfHostedRegistration: Story = () => { | ||
const [path, navigateTo] = | ||
useState<`/${ | ||
| 'admin-info' | ||
| 'org-info' | ||
| 'register-server' | ||
| 'cloud-email' | ||
| 'awaiting' | ||
| 'home' | ||
| 'email' | ||
| 'confirmation-progress' | ||
| 'email-confirmed'}`>('/admin-info'); | ||
|
||
const [adminInfo, setAdminInfo] = | ||
useState<Omit<AdminInfoPayload, 'password'>>(); | ||
|
||
const [organizationInfo, setOrganizationInfo] = | ||
useState<OrganizationInfoPayload>(); | ||
|
||
const [serverRegistration, setServerRegistration] = useState<{ | ||
updates?: boolean; | ||
agreement?: boolean; | ||
cloudAccountEmail?: string; | ||
securityCode?: string; | ||
}>(); | ||
|
||
const handleAdminInfoSubmit = logSubmit((data: AdminInfoPayload) => { | ||
setAdminInfo(data); | ||
navigateTo('/org-info'); | ||
}); | ||
|
||
const handleOrganizationInfoSubmit = logSubmit( | ||
(data: OrganizationInfoPayload) => { | ||
setOrganizationInfo(data); | ||
navigateTo('/register-server'); | ||
} | ||
); | ||
|
||
const handleRegisterServerSubmit = logSubmit( | ||
(data: RegisterServerPayload) => { | ||
switch (data.registerType) { | ||
case 'standalone': { | ||
navigateTo('/home'); | ||
break; | ||
} | ||
|
||
case 'registered': { | ||
setServerRegistration((serverRegistration) => ({ | ||
...serverRegistration, | ||
updates: data.updates, | ||
agreement: data.agreement, | ||
})); | ||
navigateTo('/cloud-email'); | ||
break; | ||
} | ||
} | ||
} | ||
); | ||
|
||
const handleCloudAccountEmailSubmit = logSubmit( | ||
(data: CloudAccountEmailPayload) => { | ||
setServerRegistration((serverRegistration) => ({ | ||
...serverRegistration, | ||
cloudAccountEmail: data.email, | ||
securityCode: 'Funny Tortoise In The Hat', | ||
})); | ||
navigateTo('/awaiting'); | ||
} | ||
); | ||
|
||
if (path === '/admin-info') { | ||
return ( | ||
<AdminInfoPage | ||
currentStep={1} | ||
stepCount={4} | ||
passwordRulesHint='' | ||
validateUsername={validateUsername} | ||
validateEmail={validateEmail} | ||
validatePassword={validatePassword} | ||
initialValues={adminInfo} | ||
onSubmit={handleAdminInfoSubmit} | ||
/> | ||
); | ||
} | ||
|
||
if (path === '/org-info') { | ||
return ( | ||
<OrganizationInfoPage | ||
currentStep={2} | ||
stepCount={4} | ||
organizationTypeOptions={organizationTypes} | ||
organizationIndustryOptions={organizationIndustryOptions} | ||
organizationSizeOptions={organizationSizeOptions} | ||
countryOptions={countryOptions} | ||
initialValues={organizationInfo} | ||
onBackButtonClick={() => navigateTo('/admin-info')} | ||
onSubmit={handleOrganizationInfoSubmit} | ||
/> | ||
); | ||
} | ||
|
||
if (path === '/register-server') { | ||
return ( | ||
<RegisterServerPage | ||
currentStep={3} | ||
stepCount={4} | ||
initialValues={{ | ||
...(serverRegistration?.updates && { | ||
updates: serverRegistration?.updates, | ||
}), | ||
...(serverRegistration?.agreement && { | ||
agreement: serverRegistration?.agreement, | ||
}), | ||
}} | ||
onBackButtonClick={() => navigateTo('/org-info')} | ||
onSubmit={handleRegisterServerSubmit} | ||
/> | ||
); | ||
} | ||
|
||
if (path === '/cloud-email') { | ||
return ( | ||
<CloudAccountEmailPage | ||
currentStep={4} | ||
stepCount={4} | ||
initialValues={{}} | ||
onBackButtonClick={() => navigateTo('/register-server')} | ||
onSubmit={handleCloudAccountEmailSubmit} | ||
/> | ||
); | ||
} | ||
|
||
if (path === '/awaiting') { | ||
if (!serverRegistration?.cloudAccountEmail) { | ||
throw new Error('missing cloud account email'); | ||
} | ||
|
||
if (!serverRegistration?.securityCode) { | ||
throw new Error('missing verification code'); | ||
} | ||
|
||
setTimeout(() => { | ||
navigateTo('/confirmation-progress'); | ||
}, 5000); | ||
|
||
return ( | ||
<AwaitingConfirmationPage | ||
emailAddress={serverRegistration.cloudAccountEmail} | ||
securityCode={serverRegistration.securityCode} | ||
onChangeEmailRequest={() => navigateTo('/admin-info')} | ||
onResendEmailRequest={() => undefined} | ||
/> | ||
); | ||
} | ||
|
||
if (path === '/confirmation-progress') { | ||
setTimeout(() => { | ||
navigateTo('/email-confirmed'); | ||
}, 3000); | ||
|
||
return <ConfirmationProcessPage />; | ||
} | ||
|
||
if (path === '/email-confirmed') { | ||
return <EmailConfirmedPage />; | ||
} | ||
|
||
if (path === '/home') { | ||
return ( | ||
<Box | ||
width='100vw' | ||
height='100vh' | ||
display='flex' | ||
justifyContent='center' | ||
alignItems='center' | ||
> | ||
<Callout type='success'>This is the home of the workspace.</Callout> | ||
</Box> | ||
); | ||
} | ||
|
||
throw new Error('invalid path'); | ||
}; | ||
SelfHostedRegistration.storyName = 'Self-Hosted Registration'; |
Oops, something went wrong.