Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5935543

Browse files
refactor: Refactor login page (#5148)
1 parent 71bc48d commit 5935543

File tree

13 files changed

+244
-65
lines changed

13 files changed

+244
-65
lines changed

site/e2e/pom/SignInPage.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ export class SignInPage extends BasePom {
1212
): Promise<void> {
1313
await this.page.fill("text=Email", email)
1414
await this.page.fill("text=Password", password)
15-
await this.page.click("text=Sign In")
15+
await this.page.click('button:has-text("Sign In")')
1616
}
1717
}

site/src/components/SignInForm/SignInForm.tsx

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import { FC } from "react"
1111
import * as Yup from "yup"
1212
import { AuthMethods } from "../../api/typesGenerated"
1313
import { getFormHelpers, onChangeTrimmed } from "../../util/formUtils"
14-
import { Welcome } from "../Welcome/Welcome"
1514
import { LoadingButton } from "./../LoadingButton/LoadingButton"
1615
import { AlertBanner } from "components/AlertBanner/AlertBanner"
16+
import { useTranslation } from "react-i18next"
1717

1818
/**
1919
* BuiltInAuthFormValues describes a form using built-in (email/password)
@@ -57,6 +57,27 @@ const validationSchema = Yup.object({
5757
})
5858

5959
const useStyles = makeStyles((theme) => ({
60+
wrapper: {
61+
maxWidth: 385,
62+
width: "100%",
63+
64+
[theme.breakpoints.down("sm")]: {
65+
maxWidth: "none",
66+
},
67+
},
68+
69+
title: {
70+
fontSize: theme.spacing(4),
71+
fontWeight: 400,
72+
margin: 0,
73+
marginBottom: theme.spacing(4),
74+
lineHeight: 1,
75+
76+
"& strong": {
77+
fontWeight: 600,
78+
},
79+
},
80+
6081
buttonIcon: {
6182
width: 14,
6283
height: 14,
@@ -87,13 +108,7 @@ export interface SignInFormProps {
87108
redirectTo: string
88109
loginErrors: Partial<Record<LoginErrors, Error | unknown>>
89110
authMethods?: AuthMethods
90-
onSubmit: ({
91-
email,
92-
password,
93-
}: {
94-
email: string
95-
password: string
96-
}) => Promise<void>
111+
onSubmit: (credentials: { email: string; password: string }) => void
97112
// initialTouched is only used for testing the error state of the form.
98113
initialTouched?: FormikTouched<BuiltInAuthFormValues>
99114
}
@@ -107,7 +122,6 @@ export const SignInForm: FC<React.PropsWithChildren<SignInFormProps>> = ({
107122
initialTouched,
108123
}) => {
109124
const styles = useStyles()
110-
111125
const form: FormikContextType<BuiltInAuthFormValues> =
112126
useFormik<BuiltInAuthFormValues>({
113127
initialValues: {
@@ -127,10 +141,15 @@ export const SignInForm: FC<React.PropsWithChildren<SignInFormProps>> = ({
127141
form,
128142
loginErrors.authError,
129143
)
144+
const commonTranslation = useTranslation("common")
145+
const loginPageTranslation = useTranslation("loginPage")
130146

131147
return (
132-
<>
133-
<Welcome />
148+
<div className={styles.wrapper}>
149+
<h1 className={styles.title}>
150+
{loginPageTranslation.t("signInTo")}{" "}
151+
<strong>{commonTranslation.t("coder")}</strong>
152+
</h1>
134153
<form onSubmit={form.handleSubmit}>
135154
<Stack>
136155
{Object.keys(loginErrors).map(
@@ -176,7 +195,7 @@ export const SignInForm: FC<React.PropsWithChildren<SignInFormProps>> = ({
176195
</Stack>
177196
</form>
178197
{(authMethods?.github || authMethods?.oidc) && (
179-
<>
198+
<div>
180199
<div className={styles.divider}>
181200
<div className={styles.dividerLine} />
182201
<div className={styles.dividerLabel}>Or</div>
@@ -222,8 +241,8 @@ export const SignInForm: FC<React.PropsWithChildren<SignInFormProps>> = ({
222241
</Link>
223242
)}
224243
</Box>
225-
</>
244+
</div>
226245
)}
227-
</>
246+
</div>
228247
)
229248
}

site/src/components/WorkspacesTable/WorkspacesTableBody.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export const WorkspacesTableBody: FC<
6262
}
6363
image={
6464
<div className={styles.emptyImage}>
65-
<img src="/empty/workspaces.webp" alt="" />
65+
<img src="/featured/workspaces.webp" alt="" />
6666
</div>
6767
}
6868
/>

site/src/i18n/en/common.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
2+
"coder": "Coder",
23
"workspaceStatus": {
34
"loading": "Loading",
45
"running": "Running",

site/src/i18n/en/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import buildPage from "./buildPage.json"
99
import workspacesPage from "./workspacesPage.json"
1010
import usersPage from "./usersPage.json"
1111
import templateVersionPage from "./templateVersionPage.json"
12+
import loginPage from "./loginPage.json"
1213

1314
export const en = {
1415
common,
@@ -22,4 +23,5 @@ export const en = {
2223
workspacesPage,
2324
usersPage,
2425
templateVersionPage,
26+
loginPage,
2527
}

site/src/i18n/en/loginPage.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"signInTo": "Sign in to"
3+
}

site/src/pages/LoginPage/LoginPage.tsx

Lines changed: 16 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,19 @@
11
import { useActor } from "@xstate/react"
2-
import { FullScreenLoader } from "components/Loader/FullScreenLoader"
3-
import { SignInLayout } from "components/SignInLayout/SignInLayout"
4-
import React, { useContext } from "react"
2+
import { FC, useContext } from "react"
53
import { Helmet } from "react-helmet-async"
4+
import { useTranslation } from "react-i18next"
65
import { Navigate, useLocation } from "react-router-dom"
7-
import { LoginErrors, SignInForm } from "../../components/SignInForm/SignInForm"
8-
import { pageTitle } from "../../util/page"
96
import { retrieveRedirect } from "../../util/redirect"
107
import { XServiceContext } from "../../xServices/StateContext"
8+
import { LoginPageView } from "./LoginPageView"
119

12-
interface LocationState {
13-
isRedirect: boolean
14-
}
15-
16-
export const LoginPage: React.FC = () => {
10+
export const LoginPage: FC = () => {
1711
const location = useLocation()
1812
const xServices = useContext(XServiceContext)
1913
const [authState, authSend] = useActor(xServices.authXService)
20-
const isLoading = authState.hasTag("loading")
2114
const redirectTo = retrieveRedirect(location.search)
22-
const locationState = location.state
23-
? (location.state as LocationState)
24-
: null
25-
const isRedirected = locationState ? locationState.isRedirect : false
26-
const { authError, getUserError, checkPermissionsError, getMethodsError } =
27-
authState.context
28-
29-
const onSubmit = async ({
30-
email,
31-
password,
32-
}: {
33-
email: string
34-
password: string
35-
}) => {
36-
authSend({ type: "SIGN_IN", email, password })
37-
}
15+
const commonTranslation = useTranslation("common")
16+
const loginPageTranslation = useTranslation("loginPage")
3817

3918
if (authState.matches("signedIn")) {
4019
return <Navigate to={redirectTo} replace />
@@ -44,28 +23,17 @@ export const LoginPage: React.FC = () => {
4423
return (
4524
<>
4625
<Helmet>
47-
<title>{pageTitle("Login")}</title>
26+
<title>
27+
{loginPageTranslation.t("signInTo")} {commonTranslation.t("coder")}
28+
</title>
4829
</Helmet>
49-
{authState.hasTag("loading") ? (
50-
<FullScreenLoader />
51-
) : (
52-
<SignInLayout>
53-
<SignInForm
54-
authMethods={authState.context.methods}
55-
redirectTo={redirectTo}
56-
isLoading={isLoading}
57-
loginErrors={{
58-
[LoginErrors.AUTH_ERROR]: authError,
59-
[LoginErrors.GET_USER_ERROR]: isRedirected
60-
? getUserError
61-
: null,
62-
[LoginErrors.CHECK_PERMISSIONS_ERROR]: checkPermissionsError,
63-
[LoginErrors.GET_METHODS_ERROR]: getMethodsError,
64-
}}
65-
onSubmit={onSubmit}
66-
/>
67-
</SignInLayout>
68-
)}
30+
<LoginPageView
31+
context={authState.context}
32+
isLoading={authState.hasTag("loading")}
33+
onSignIn={({ email, password }) => {
34+
authSend({ type: "SIGN_IN", email, password })
35+
}}
36+
/>
6937
</>
7038
)
7139
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { action } from "@storybook/addon-actions"
2+
import { ComponentMeta, Story } from "@storybook/react"
3+
import { LoginPageView, LoginPageViewProps } from "./LoginPageView"
4+
5+
export default {
6+
title: "pages/LoginPageView",
7+
component: LoginPageView,
8+
} as ComponentMeta<typeof LoginPageView>
9+
10+
const Template: Story<LoginPageViewProps> = (args) => (
11+
<LoginPageView {...args} />
12+
)
13+
14+
export const Example = Template.bind({})
15+
Example.args = {
16+
isLoading: false,
17+
onSignIn: action("onSignIn"),
18+
context: {},
19+
}

0 commit comments

Comments
 (0)