Final style changes to signup

This commit is contained in:
Vladyslav Matsiiako
2023-05-28 14:22:17 -07:00
parent fac4968193
commit 3a5ad93450
15 changed files with 173 additions and 34 deletions

View File

@@ -11,6 +11,7 @@ import { INVITED, ACCEPTED } from '../../variables';
import { standardRequest } from '../../config/request';
import { getLoopsApiKey, getHttpsEnabled, getJwtSignupSecret } from '../../config';
import { BadRequestError } from '../../utils/errors';
import { TelemetryService } from '../../services';
/**
* Complete setting up user by adding their personal and auth information as part of the
@@ -37,6 +38,7 @@ export const completeAccountSignup = async (req: Request, res: Response) => {
verifier,
organizationName,
providerAuthToken,
attributionSource,
}: {
email: string;
firstName: string;
@@ -52,6 +54,7 @@ export const completeAccountSignup = async (req: Request, res: Response) => {
verifier: string;
organizationName: string;
providerAuthToken?: string;
attributionSource?: string;
} = req.body;
user = await User.findOne({ email });
@@ -161,6 +164,18 @@ export const completeAccountSignup = async (req: Request, res: Response) => {
sameSite: 'strict',
secure: await getHttpsEnabled()
});
const postHogClient = await TelemetryService.getPostHogClient();
if (postHogClient) {
postHogClient.capture({
event: 'User Signed Up',
distinctId: req.user.email,
properties: {
email,
attributionSource
}
});
}
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);

View File

@@ -1,8 +1,9 @@
import { useTranslation } from 'react-i18next';
import Link from 'next/link';
import { faGoogle } from '@fortawesome/free-brands-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useRouter } from 'next/router';
// import { faGoogle } from '@fortawesome/free-brands-svg-icons';
// import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Button } from '../v2';
export default function InitialLoginStep({
@@ -11,11 +12,12 @@ export default function InitialLoginStep({
setIsLoginWithEmail: (value: boolean) => void;
}) {
const router = useRouter();
const { t } = useTranslation();
return <div className='flex flex-col mx-auto w-full justify-center items-center'>
<h1 className='text-xl font-medium text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200 text-center mb-8' >Login to Infisical</h1>
<div className='lg:w-1/6 w-1/4 min-w-[20rem] rounded-md'>
{/* <div className='lg:w-1/6 w-1/4 min-w-[20rem] rounded-md'>
<Button
colorSchema="primary"
variant="solid"
@@ -27,11 +29,11 @@ export default function InitialLoginStep({
>
{t('login.continue-with-google')}
</Button>
</div>
<div className='lg:w-1/6 w-1/4 min-w-[20rem] text-center rounded-md mt-4'>
</div> */}
<div className='lg:w-1/6 w-1/4 min-w-[20rem] text-center rounded-md'>
<Button
colorSchema="primary"
variant="outline_bg"
variant="solid"
onClick={() => {
setIsLoginWithEmail(true);
}}
@@ -41,6 +43,17 @@ export default function InitialLoginStep({
{t('login.continue-with-email')}
</Button>
</div>
<div className='lg:w-1/6 w-1/4 min-w-[20rem] text-center rounded-md mt-4'>
<Button
colorSchema="primary"
variant="outline_bg"
onClick={() => router.push("/saml-sso")}
isFullWidth
className="h-14 w-full mx-0"
>
Continue with SAML SSO
</Button>
</div>
<div className="mt-4 text-bunker-400 text-sm flex flex-row">
<span className="mr-1">Don&apos;t have an acount yet?</span>
<Link href="/signup">

View File

@@ -83,9 +83,9 @@ export default function EnterEmailStep({
<div className="mx-auto mb-48 mt-2 flex w-full max-w-md flex-col items-center justify-center pt-2 md:mb-16 md:pb-2">
<Link href="/login">
<button type="button" className="w-max pb-3 duration-200 hover:opacity-90">
<u className="text-sm font-normal text-primary-500">
<span className="text-sm text-mineshaft-400 hover:underline hover:underline-offset-4 hover:decoration-primary-700 hover:text-bunker-200 duration-200 cursor-pointer">
{t('signup.already-have-account')}
</u>
</span>
</button>
</Link>
</div>

View File

@@ -1,8 +1,9 @@
import { useTranslation } from 'react-i18next';
import Link from 'next/link';
import { faGoogle } from '@fortawesome/free-brands-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useRouter } from 'next/router';
// import { faGoogle } from '@fortawesome/free-brands-svg-icons';
// import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Button } from '../v2';
export default function InitialSignupStep({
@@ -11,10 +12,11 @@ export default function InitialSignupStep({
setIsSignupWithEmail: (value: boolean) => void
}) {
const { t } = useTranslation();
const router = useRouter();
return <div className='flex flex-col mx-auto w-full justify-center items-center '>
return <div className='flex flex-col mx-auto w-full justify-center items-center'>
<h1 className='text-xl font-medium text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200 text-center mb-8' >{t('signup.initial-title')}</h1>
<div className='lg:w-1/6 w-1/4 min-w-[20rem] rounded-md'>
{/* <div className='lg:w-1/6 w-1/4 min-w-[20rem] rounded-md'>
<Button
colorSchema="primary"
variant="solid"
@@ -26,11 +28,11 @@ export default function InitialSignupStep({
>
{t('signup.continue-with-google')}
</Button>
</div>
<div className='lg:w-1/6 w-1/4 min-w-[20rem] text-center rounded-md mt-4'>
</div> */}
<div className='lg:w-1/6 w-1/4 min-w-[20rem] text-center rounded-md'>
<Button
colorSchema="primary"
variant="outline_bg"
variant="solid"
onClick={() => {
setIsSignupWithEmail(true);
}}
@@ -40,6 +42,17 @@ export default function InitialSignupStep({
{t('signup.continue-with-email')}
</Button>
</div>
<div className='lg:w-1/6 w-1/4 min-w-[20rem] text-center rounded-md mt-4'>
<Button
colorSchema="primary"
variant="outline_bg"
onClick={() => router.push("/saml-sso")}
isFullWidth
className="h-14 w-full mx-0"
>
Continue with SAML SSO
</Button>
</div>
<div className='lg:w-1/6 w-1/4 min-w-[20rem] px-8 text-center mt-6 text-xs text-bunker-400'>
{t('signup.create-policy')}
</div>

View File

@@ -43,13 +43,13 @@ export default function TeamInviteStep(): JSX.Element {
<p className="text-center flex justify-center text-bunker-400 md:mx-8 mb-6 mt-4">
{t('signup.step5-subtitle')}
</p>
<div className="bg-mineshaft-800 border border-mineshaft-600 w-max mx-auto pt-6 pb-4 px-8 rounded-xl drop-shadow-xl mb-6">
<div className="bg-mineshaft-800 border border-mineshaft-500 w-max mx-auto pt-6 pb-4 px-8 rounded-xl drop-shadow-xl mb-6">
<div>
<div className="text-bunker-300 font-medium pl-1 pb-1 text-sm">
<span>Emails</span>
</div>
<textarea
className="bg-mineshaft-900 min-w-[30rem] h-20 w-full placeholder:text-bunker-400 py-1 px-2 rounded-md border border-mineshaft-500 text-sm text-bunker-300 outline-none focus:ring-2 ring-primary-800 ring-opacity-70"
className="bg-mineshaft-900/70 min-w-[30rem] h-20 w-full placeholder:text-bunker-400 py-1 px-2 rounded-md border border-mineshaft-500 text-sm text-bunker-300 outline-none focus:ring-2 ring-primary-800 ring-opacity-70"
value={emails}
onChange={(e) => setEmails(e.target.value)}
placeholder="email@example.com, email2@example.com..."

View File

@@ -153,7 +153,7 @@ export default function UserInfoStep({
const response = await completeAccountInformationSignup({
email,
firstName: name.split(" ")[0],
lastName: name.split(" ")[1],
lastName: name.split(" ").slice(1).join(' '),
protectedKey,
protectedKeyIV,
protectedKeyTag,
@@ -165,6 +165,7 @@ export default function UserInfoStep({
salt: result.salt,
verifier: result.verifier,
organizationName,
attributionSource,
});
// unset signup JWT token and set JWT token

View File

@@ -76,7 +76,7 @@ const buttonVariants = cva(
{
colorSchema: 'primary',
variant: 'outline_bg',
className: 'bg-mineshaft-800 border border-mineshaft-600 hover:bg-primary/[0.1] hover:border-primary/40 text-bunker-200'
className: 'bg-mineshaft-600 border border-mineshaft-500 hover:bg-primary/[0.1] hover:border-primary/40 text-bunker-200'
},
{
colorSchema: 'secondary',

View File

@@ -17,6 +17,7 @@ export const publicPaths = [
`/subprocessors`,
`/verify-email`,
`/password-reset`,
`/saml-sso`,
`/login/provider/success`,
`/login/provider/error`
];

View File

@@ -16,6 +16,7 @@ interface Props {
organizationName: string;
salt: string;
verifier: string;
attributionSource?: string;
}
/**
@@ -52,6 +53,7 @@ const completeAccountInformationSignup = async ({
verifier,
organizationName,
providerAuthToken,
attributionSource
}: Props) => {
const { data } = await apiRequest.post('/api/v3/signup/complete-account/signup', {
email,
@@ -68,6 +70,7 @@ const completeAccountInformationSignup = async ({
verifier,
organizationName,
providerAuthToken,
attributionSource,
});
return data;

View File

@@ -100,7 +100,7 @@ export default function Login() {
};
return (
<div className="flex h-screen flex-col justify-center bg-gradient-to-tr from-bunker-500 to-bunker-800 px-6 pb-28 ">
<div className="flex h-screen flex-col justify-center bg-gradient-to-tr from-mineshaft-600 via-mineshaft-800 to-bunker-700 px-6 pb-28 ">
<Head>
<title>{t('common.head-title', { title: t('login.title') })}</title>
<link rel="icon" href="/infisical.ico" />
@@ -114,7 +114,7 @@ export default function Login() {
</div>
</Link>
{renderView(step)}
<div className="absolute right-4 top-0 mt-4 flex items-center justify-center">
{/* <div className="absolute right-4 top-0 mt-4 flex items-center justify-center">
<div className="mx-auto w-48">
<ListBox
isSelected={lang}
@@ -124,7 +124,7 @@ export default function Login() {
text={`${t('common.language')}: `}
/>
</div>
</div>
</div> */}
</div>
);
}

View File

@@ -0,0 +1,90 @@
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import Head from 'next/head';
import Image from 'next/image';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { Button, Input } from '@app/components/v2';
import { isLoggedIn } from '@app/reactQuery';
import getWorkspaces from './api/workspace/getWorkspaces';
export default function Login() {
const router = useRouter();
const [password, setPassword] = useState('');
const { t } = useTranslation();
useEffect(() => {
// TODO(akhilmhdh): workspace will be controlled by a workspace context
const redirectToDashboard = async () => {
let userWorkspace;
try {
const userWorkspaces = await getWorkspaces();
userWorkspace = userWorkspaces[0] && userWorkspaces[0]._id;
router.push(`/dashboard/${userWorkspace}`);
} catch (error) {
console.log('Error - Not logged in yet');
}
};
if (isLoggedIn()) {
redirectToDashboard();
}
}, []);
return (
<div className="flex h-screen flex-col justify-center bg-gradient-to-tr from-mineshaft-600 via-mineshaft-800 to-bunker-700 px-6 pb-28 ">
<Head>
<title>{t('common.head-title', { title: t('login.title') })}</title>
<link rel="icon" href="/infisical.ico" />
<meta property="og:image" content="/images/message.png" />
<meta property="og:title" content={t('login.og-title') ?? ''} />
<meta name="og:description" content={t('login.og-description') ?? ''} />
</Head>
<Link href="/">
<div className="mb-4 mt-20 flex justify-center">
<Image src="/images/gradientLogo.svg" height={90} width={120} alt="Infisical logo" />
</div>
</Link>
<div className="mx-auto w-full max-w-md px-6">
<p className="mx-auto mb-6 flex w-max justify-center text-xl font-medium text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200 text-center mb-8">
What’s your email?
</p>
<div className="relative flex items-center justify-center lg:w-1/6 w-1/4 min-w-[22rem] mx-auto w-full rounded-lg max-h-24 md:max-h-28">
<div className="flex items-center justify-center w-full rounded-lg max-h-24 md:max-h-28">
<Input
value={password}
onChange={(e) => setPassword(e.target.value)}
type="password"
placeholder="Enter your password..."
isRequired
autoComplete="current-password"
id="current-password"
className="h-12"
/>
</div>
</div>
<div className='lg:w-1/6 w-1/4 w-full mx-auto flex items-center justify-center min-w-[22rem] text-center rounded-md mt-4'>
<Button
colorSchema="primary"
variant="outline_bg"
onClick={() => {}}
isFullWidth
className="h-14"
>
{t('login.login')}
</Button>
</div>
<div className="flex flex-row items-center justify-center mt-4">
<button
onClick={() => {router.push('/login')}}
type="button"
className="text-bunker-300 text-sm hover:underline mt-2 hover:underline-offset-4 hover:decoration-primary-700 hover:text-bunker-200 duration-200 cursor-pointer"
>
{t('login.other-option')}
</button>
</div>
</div>
</div>
);
}

View File

@@ -150,7 +150,7 @@ export default function SignUp() {
};
return (
<div className="flex min-h-screen flex-col justify-center bg-gradient-to-tr from-bunker-600 to-bunker-800 px-6 pb-28 ">
<div className="flex min-h-screen flex-col justify-center bg-gradient-to-tr from-mineshaft-600 via-mineshaft-800 to-bunker-700 px-6 pb-28 ">
<Head>
<title>{t('common.head-title', { title: t('signup.title') })}</title>
<link rel="icon" href="/infisical.ico" />
@@ -158,7 +158,7 @@ export default function SignUp() {
<meta property="og:title" content={t('signup.og-title') as string} />
<meta name="og:description" content={t('signup.og-description') as string} />
</Head>
<div className="mb-8 mt-20 flex justify-center">
<div className="mb-4 mt-20 flex justify-center">
<Image src="/images/gradientLogo.svg" height={90} width={120} alt="Infisical Logo" />
</div>
<form onSubmit={(e) => e.preventDefault()}>{renderView(step)}</form>

View File

@@ -180,7 +180,7 @@ export default function SignupInvite() {
// Step 4 of the sign up process (download the emergency kit pdf)
const stepConfirmEmail = (
<div className="bg-bunker flex flex-col items-center w-full max-w-xs md:max-w-lg h-7/12 py-8 px-4 md:px-6 mx-1 mb-36 md:mb-16 rounded-xl drop-shadow-xl">
<div className="border border-mineshaft-600 bg-mineshaft-800 flex flex-col items-center w-full max-w-xs md:max-w-lg h-7/12 py-8 px-4 md:px-6 mx-1 mb-36 md:mb-16 rounded-xl drop-shadow-xl">
<p className="text-4xl text-center font-semibold mb-6 flex justify-center text-primary-100">
Confirm your email
</p>
@@ -219,8 +219,8 @@ export default function SignupInvite() {
// Because this is the invite signup - we directly go to the last step of signup (email is already verified)
const main = (
<div className="bg-bunker w-max mx-auto h-7/12 py-10 px-8 rounded-xl drop-shadow-xl mb-32 md:mb-16">
<p className="text-4xl font-bold flex justify-center mb-6 text-gray-400 mx-8 md:mx-16 text-transparent bg-clip-text bg-gradient-to-br from-sky-400 to-primary">
<div className="border border-mineshaft-600 bg-mineshaft-800 w-max mx-auto h-7/12 py-10 px-8 rounded-xl drop-shadow-xl mb-32 md:mb-16">
<p className="text-4xl font-bold flex justify-center mb-6 mx-8 md:mx-16 text-transparent bg-clip-text bg-gradient-to-tr from-mineshaft-300 to-white">
Almost there!
</p>
<div className="relative z-0 flex items-center justify-end w-full md:p-2 rounded-lg max-h-24">
@@ -322,8 +322,8 @@ export default function SignupInvite() {
// Step 4 of the sign up process (download the emergency kit pdf)
const step4 = (
<div className="bg-bunker flex flex-col items-center w-full max-w-xs md:max-w-lg h-7/12 py-8 px-4 md:px-6 mx-1 mb-36 md:mb-16 rounded-xl drop-shadow-xl">
<p className="text-4xl text-center font-semibold flex justify-center text-transparent bg-clip-text bg-gradient-to-br from-sky-400 to-primary">
<div className="border border-mineshaft-600 bg-mineshaft-800 flex flex-col items-center w-full max-w-xs md:max-w-lg h-7/12 pt-8 pb-6 px-4 md:px-6 mx-1 mb-36 md:mb-16 rounded-xl drop-shadow-xl">
<p className="text-4xl text-center font-semibold flex justify-center text-transparent bg-clip-text bg-gradient-to-br from-white to-mineshaft-300">
Save your Emergency Kit
</p>
<div className="flex flex-col items-center justify-center w-full mt-4 md:mt-8 max-w-md text-gray-400 text-md rounded-md px-2">
@@ -336,7 +336,7 @@ export default function SignupInvite() {
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-4 text-4xl" />
It contains your Secret Key which we cannot access or recover for you if you lose it.
</div>
<div className="flex flex-col items-center justify-center md:px-4 md:py-5 mt-2 px-2 py-3 max-h-24 max-w-max mx-auto text-lg">
<div className="flex flex-col items-center justify-center md:px-4 md:py-5 mt-4 px-2 py-3 max-h-24 max-w-max mx-auto text-lg">
<Button
text="Download PDF"
onButtonPressed={async () => {
@@ -368,14 +368,14 @@ export default function SignupInvite() {
);
return (
<div className="bg-bunker-800 h-screen flex flex-col items-center justify-center">
<div className="bg-gradient-to-tr from-mineshaft-600 via-mineshaft-800 to-bunker-700 h-screen flex flex-col items-center justify-center">
<Head>
<title>Sign Up</title>
<link rel="icon" href="/infisical.ico" />
</Head>
<Link href="/">
<div className="flex justify-center mb-2 md:mb-4 opacity-80 cursor-pointer">
<Image src="/images/biglogo.png" height={90} width={120} alt="Infisical Wide Logo" />
<div className="mb-4 mt-20 flex justify-center">
<Image src="/images/gradientLogo.svg" height={90} width={120} alt="Infisical Logo" />
</div>
</Link>
{step === 1 ? stepConfirmEmail : step === 2 ? main : step4}

View File

@@ -571,6 +571,8 @@ export const DashboardPage = ({ envFromTop }: { envFromTop: string }) => {
leftIcon={<FontAwesomeIcon icon={isRollbackMode ? faClockRotateLeft : faCheck} />}
onClick={handleSubmit(onSaveSecret)}
className="h-10"
color="primary"
variant="star"
>
{isRollbackMode ? 'Rollback' : 'Save Changes'}
</Button>

View File

@@ -54,7 +54,8 @@ export const OrgNameChangeSection = ({ onOrgNameChange, orgName }: Props): JSX.E
</div>
<Button
isLoading={isSubmitting}
color="mineshaft"
color="primary"
variant="outline_bg"
size="sm"
type="submit"
isDisabled={!isDirty || isSubmitting}