Skip to content

Commit 7ded123

Browse files
committed
frontend changes
1 parent c44a479 commit 7ded123

File tree

4 files changed

+69
-24
lines changed

4 files changed

+69
-24
lines changed

site/src/index.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
--avatar-lg: 2.5rem;
4444
--avatar-default: 1.5rem;
4545
--avatar-sm: 1.125rem;
46+
--divider: 240, 6%, 90%; /* tailwind zinc-200 */
4647
}
4748
.dark {
4849
--content-primary: 0 0% 98%;
@@ -75,6 +76,7 @@
7576
--border: 240 3.7% 15.9%;
7677
--input: 240 3.7% 15.9%;
7778
--ring: 240 4.9% 83.9%;
79+
--divider: 240, 5%, 26%; /* tailwind zinc-700 */
7880
}
7981
}
8082

site/src/pages/SetupPage/SetupPage.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { buildInfo } from "api/queries/buildInfo";
2-
import { createFirstUser } from "api/queries/users";
2+
import { authMethods, createFirstUser } from "api/queries/users";
33
import { Loader } from "components/Loader/Loader";
44
import { useAuthContext } from "contexts/auth/AuthProvider";
55
import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata";
@@ -19,6 +19,7 @@ export const SetupPage: FC = () => {
1919
isSignedIn,
2020
isSigningIn,
2121
} = useAuthContext();
22+
const authMethodsQuery = useQuery(authMethods());
2223
const createFirstUserMutation = useMutation(createFirstUser());
2324
const setupIsComplete = !isConfiguringTheFirstUser;
2425
const { metadata } = useEmbeddedMetadata();
@@ -34,7 +35,7 @@ export const SetupPage: FC = () => {
3435
});
3536
}, [buildInfoQuery.data]);
3637

37-
if (isLoading) {
38+
if (isLoading || authMethodsQuery.isLoading) {
3839
return <Loader fullscreen />;
3940
}
4041

@@ -54,6 +55,7 @@ export const SetupPage: FC = () => {
5455
<title>{pageTitle("Set up your account")}</title>
5556
</Helmet>
5657
<SetupPageView
58+
authMethods={authMethodsQuery.data}
5759
isLoading={isSigningIn || createFirstUserMutation.isLoading}
5860
error={createFirstUserMutation.error}
5961
onSubmit={async (firstUser) => {

site/src/pages/SetupPage/SetupPageView.tsx

Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import GitHubIcon from "@mui/icons-material/GitHub";
12
import LoadingButton from "@mui/lab/LoadingButton";
23
import AlertTitle from "@mui/material/AlertTitle";
34
import Autocomplete from "@mui/material/Autocomplete";
5+
import Button from "@mui/material/Button";
46
import Checkbox from "@mui/material/Checkbox";
57
import Link from "@mui/material/Link";
68
import MenuItem from "@mui/material/MenuItem";
@@ -15,8 +17,7 @@ import { PasswordField } from "components/PasswordField/PasswordField";
1517
import { SignInLayout } from "components/SignInLayout/SignInLayout";
1618
import { Stack } from "components/Stack/Stack";
1719
import { type FormikContextType, useFormik } from "formik";
18-
import type { FC } from "react";
19-
import { useEffect } from "react";
20+
import { type ChangeEvent, type FC, useCallback } from "react";
2021
import { docs } from "utils/docs";
2122
import {
2223
getFormHelpers,
@@ -33,7 +34,8 @@ export const Language = {
3334
emailInvalid: "Please enter a valid email address.",
3435
emailRequired: "Please enter an email address.",
3536
passwordRequired: "Please enter a password.",
36-
create: "Create account",
37+
create: "Continue with email",
38+
githubCreate: "Continue with GitHub",
3739
welcomeMessage: <>Welcome to Coder</>,
3840
firstNameLabel: "First name",
3941
lastNameLabel: "Last name",
@@ -50,13 +52,29 @@ export const Language = {
5052
developersRequired: "Please select the number of developers in your company.",
5153
};
5254

55+
const usernameValidator = nameValidator(Language.usernameLabel);
56+
const usernameFromEmail = (email: string): string => {
57+
try {
58+
const emailPrefix = email.split("@")[0];
59+
const username = emailPrefix.toLowerCase().replace(/[^a-z0-9]/g, "-");
60+
usernameValidator.validateSync(username);
61+
return username;
62+
} catch (error) {
63+
console.warn(
64+
"failed to automatically generate username, defaulting to 'admin'",
65+
error,
66+
);
67+
return "admin";
68+
}
69+
};
70+
5371
const validationSchema = Yup.object({
5472
email: Yup.string()
5573
.trim()
5674
.email(Language.emailInvalid)
5775
.required(Language.emailRequired),
5876
password: Yup.string().required(Language.passwordRequired),
59-
username: nameValidator(Language.usernameLabel),
77+
username: usernameValidator,
6078
trial: Yup.bool(),
6179
trial_info: Yup.object().when("trial", {
6280
is: true,
@@ -81,16 +99,23 @@ const numberOfDevelopersOptions = [
8199
"2500+",
82100
];
83101

102+
const iconStyles = {
103+
width: 16,
104+
height: 16,
105+
};
106+
84107
export interface SetupPageViewProps {
85108
onSubmit: (firstUser: TypesGen.CreateFirstUserRequest) => void;
86109
error?: unknown;
87110
isLoading?: boolean;
111+
authMethods: TypesGen.AuthMethods | undefined;
88112
}
89113

90114
export const SetupPageView: FC<SetupPageViewProps> = ({
91115
onSubmit,
92116
error,
93117
isLoading,
118+
authMethods,
94119
}) => {
95120
const form: FormikContextType<TypesGen.CreateFirstUserRequest> =
96121
useFormik<TypesGen.CreateFirstUserRequest>({
@@ -112,6 +137,10 @@ export const SetupPageView: FC<SetupPageViewProps> = ({
112137
},
113138
validationSchema,
114139
onSubmit,
140+
// With validate on blur set to true, the form lights up red whenever
141+
// you click out of it. This is a bit jarring. We instead validate
142+
// on submit and change.
143+
validateOnBlur: false,
115144
});
116145
const getFieldHelpers = getFormHelpers<TypesGen.CreateFirstUserRequest>(
117146
form,
@@ -142,23 +171,36 @@ export const SetupPageView: FC<SetupPageViewProps> = ({
142171
</header>
143172
<VerticalForm onSubmit={form.handleSubmit}>
144173
<FormFields>
145-
<TextField
146-
autoFocus
147-
{...getFieldHelpers("username")}
148-
onChange={onChangeTrimmed(form)}
149-
autoComplete="username"
150-
fullWidth
151-
label={Language.usernameLabel}
152-
/>
153-
<TextField
154-
{...getFieldHelpers("name")}
155-
autoComplete="name"
156-
fullWidth
157-
label={Language.nameLabel}
158-
/>
174+
{authMethods?.github.enabled && (
175+
<>
176+
<Button
177+
fullWidth
178+
component="a"
179+
href="/api/v2/users/oauth2/github/callback"
180+
variant="contained"
181+
startIcon={<GitHubIcon css={iconStyles} />}
182+
type="submit"
183+
size="xlarge"
184+
>
185+
{Language.githubCreate}
186+
</Button>
187+
<div className="flex items-center gap-4">
188+
<div className="h-[1px] w-full bg-border" />
189+
<div className="shrink-0 text-xs uppercase text-content-secondary tracking-wider">
190+
or
191+
</div>
192+
<div className="h-[1px] w-full bg-border" />
193+
</div>
194+
</>
195+
)}
159196
<TextField
160197
{...getFieldHelpers("email")}
161-
onChange={onChangeTrimmed(form)}
198+
onChange={(event) => {
199+
const email = event.target.value;
200+
const username = usernameFromEmail(email);
201+
form.setFieldValue("username", username);
202+
onChangeTrimmed(form)(event as ChangeEvent<HTMLInputElement>);
203+
}}
162204
autoComplete="email"
163205
fullWidth
164206
label={Language.emailLabel}
@@ -340,9 +382,7 @@ export const SetupPageView: FC<SetupPageViewProps> = ({
340382
loading={isLoading}
341383
type="submit"
342384
data-testid="create"
343-
size="large"
344-
variant="contained"
345-
color="primary"
385+
size="xlarge"
346386
>
347387
{Language.create}
348388
</LoadingButton>

site/tailwind.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ module.exports = {
6363
grey: "hsl(var(--highlight-grey))",
6464
sky: "hsl(var(--highlight-sky))",
6565
},
66+
divider: "hsl(var(--divider))",
6667
},
6768
keyframes: {
6869
loading: {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy