diff --git a/README.md b/README.md index 727196d5..c0938587 100644 --- a/README.md +++ b/README.md @@ -89,12 +89,12 @@ You can now deploy the directory `packages/client/dist`. The app currently needs the following routes: -- `/server` -- `/channel` -- `/dev` -- `/friends` -- `/app` +- `/login` - `/pwa` +- `/dev` - `/settings` +- `/friends` +- `/server` +- `/channel` -This corresponds to [Content.tsx#L33](packages/client/src/interface/Content.tsx). +This corresponds to [Content.tsx#L33](packages/client/src/index.tsx). diff --git a/packages/client/assets b/packages/client/assets index e96fb7eb..086faa65 160000 --- a/packages/client/assets +++ b/packages/client/assets @@ -1 +1 @@ -Subproject commit e96fb7eb10b9fe79fc9674233c2bdda1d30c9f1f +Subproject commit 086faa6516ee01b25463231779b417d26a97f04f diff --git a/packages/client/components/auth/src/flows/Flow.tsx b/packages/client/components/auth/src/flows/Flow.tsx index d69fb4b2..5e0c1d53 100644 --- a/packages/client/components/auth/src/flows/Flow.tsx +++ b/packages/client/components/auth/src/flows/Flow.tsx @@ -10,8 +10,12 @@ import wave from "./wave.svg"; * Container for authentication page flows */ export const FlowBase = styled(Column)` - background: ${(props) => - props.theme!.colours["messaging-message-box-background"]}; + background: ${ + (props) => + props.theme!.colours[ + "messaging-message-box-background" + ] /* TODO: change and in other places */ + }; color: ${(props) => props.theme!.colours["messaging-message-box-foreground"]}; /* background-color: rgba(36, 36, 36, 0.75); diff --git a/packages/client/components/auth/src/flows/FlowConfirmReset.tsx b/packages/client/components/auth/src/flows/FlowConfirmReset.tsx index 5f635583..ac1994c4 100644 --- a/packages/client/components/auth/src/flows/FlowConfirmReset.tsx +++ b/packages/client/components/auth/src/flows/FlowConfirmReset.tsx @@ -28,7 +28,7 @@ export default function FlowConfirmReset() { remove_sessions, }); - navigate("../..", { replace: true }); + navigate("/login/auth", { replace: true }); } return ( @@ -39,7 +39,7 @@ export default function FlowConfirmReset() { - {t("login.remembered")} + {t("login.remembered")} ); diff --git a/packages/client/components/auth/src/flows/FlowCreate.tsx b/packages/client/components/auth/src/flows/FlowCreate.tsx index f5ed166d..6084c364 100644 --- a/packages/client/components/auth/src/flows/FlowCreate.tsx +++ b/packages/client/components/auth/src/flows/FlowCreate.tsx @@ -7,6 +7,7 @@ import MdArrowBack from "@material-design-icons/svg/filled/arrow_back.svg?compon import { clientController } from "../../../client"; +import { FlowTitle } from "./Flow"; import { setFlowCheckEmail } from "./FlowCheck"; import { Fields, Form } from "./Form"; @@ -43,9 +44,9 @@ export default function FlowCreate() { return ( <> - {/* + {t("login.welcome2")} - */} +
diff --git a/packages/client/components/auth/src/flows/FlowHome.tsx b/packages/client/components/auth/src/flows/FlowHome.tsx index 4e455aba..2de63cc6 100644 --- a/packages/client/components/auth/src/flows/FlowHome.tsx +++ b/packages/client/components/auth/src/flows/FlowHome.tsx @@ -2,26 +2,15 @@ import { Show } from "solid-js"; import { clientController } from "@revolt/client"; import { useTranslation } from "@revolt/i18n"; -import { Navigate, useNavigate } from "@revolt/routing"; -import { Button, Column, Row, Typography, styled } from "@revolt/ui"; +import { Navigate } from "@revolt/routing"; +import { Button, Column, styled } from "@revolt/ui"; -import RevoltSvg from "../../../../public/assets/wide.svg?component-solid"; - -import { FlowTitle } from "./Flow"; -import { Fields, Form } from "./Form"; - -/** - * Account switcher UI - */ -// eslint-disable-next-line -const AccountSwitcher = styled(Column)` - margin-top: 8px; -`; +import RevoltSvg from "../../../../public/assets/wordmark_wide_500px.svg?component-solid"; const Logo = styled(RevoltSvg)` - margin: auto; - fill: ${(props) => props.theme!.colours.foreground}; - /* filter: invert(1); */ + width: 100%; + object-fit: contain; + fill: ${(props) => props.theme!.colours["messaging-message-box-foreground"]}; `; /** @@ -29,23 +18,6 @@ const Logo = styled(RevoltSvg)` */ export default function FlowHome() { const t = useTranslation(); - const navigate = useNavigate(); - - /** - * Log into account - * @param data Form Data - */ - async function login(data: FormData) { - const email = data.get("email") as string; - const password = data.get("password") as string; - - await clientController.login({ - email, - password, - }); - - navigate("/app", { replace: true }); - } return ( <> @@ -82,57 +54,13 @@ export default function FlowHome() { - {/* */} - + - {/* */} - - {/* - {t("login.welcome")} - */} - {/* - - - - - {t("login.new")} {t("login.create")} - - - {t("login.forgot")} {t("login.reset")} - - - {t("login.missing_verification")}{" "} - {t("login.resend")} - */} - - {/* 0}> - }> - - - Use existing account - - {(client) => ( - } - action="chevron" - onClick={() => { - clientController.switchAccount(client.user!._id); - navigate("/app"); - }} - > - {client.user!.username} - - )} - - - - - */} ); } diff --git a/packages/client/components/auth/src/flows/FlowLogin.tsx b/packages/client/components/auth/src/flows/FlowLogin.tsx index 19b58546..968553a8 100644 --- a/packages/client/components/auth/src/flows/FlowLogin.tsx +++ b/packages/client/components/auth/src/flows/FlowLogin.tsx @@ -1,31 +1,40 @@ -import { Show } from "solid-js"; +import { Match, Show, Switch } from "solid-js"; -import { State } from "@revolt/client/Controller"; +import { styled } from "styled-system/jsx"; + +import { State, TransitionType } from "@revolt/client/Controller"; import { useTranslation } from "@revolt/i18n"; -import { Navigate, useNavigate } from "@revolt/routing"; -import { Button, Column, Row, iconSize, styled } from "@revolt/ui"; +import { Navigate } from "@revolt/routing"; +import { + Button, + Column, + Preloader, + Row, + Typography, + iconSize, +} from "@revolt/ui"; import MdArrowBack from "@material-design-icons/svg/filled/arrow_back.svg?component-solid"; +import RevoltSvg from "../../../../public/assets/wordmark_wide_500px.svg?component-solid"; import { clientController } from "../../../client"; import { FlowTitle } from "./Flow"; import { Fields, Form } from "./Form"; -/** - * Account switcher UI - */ -// eslint-disable-next-line -const AccountSwitcher = styled(Column)` - margin-top: 8px; -`; +const Logo = styled(RevoltSvg, { + base: { + height: "0.8em", + display: "inline", + fill: "var(--colours-messaging-message-box-foreground)", + }, +}); /** * Flow for logging into an account */ export default function FlowLogin() { const t = useTranslation(); - const navigate = useNavigate(); /** * Log into account @@ -41,81 +50,81 @@ export default function FlowLogin() { }); } + /** + * Select a new username + * @param data Form Data + */ + async function select(data: FormData) { + const username = data.get("username") as string; + await clientController.selectUsername(username); + } + return ( <> - - - - - - This is an indicator to indicate that we are logging in... - - - {/* - {t("login.welcome")} - */} - - You are logging into a limited demo of the new Revolt client. - + + + {t("login.welcome")} + - - Please provide feedback through{" "} - - GitHub issues - {" "} - where possible. - +
+ + + + + + + + -
- - - - - - - - + + + {t("login.reset")} + - - {/* */} - {t("login.reset")} - {/* */} - - - {/* */} - {t("login.resend")} - {/* */} - + + {t("login.resend")} + + + + } + > + + + + + + + + + + {t("app.special.modals.onboarding.welcome")} + + - {/* 0}> - }> - - - Use existing account - - {(client) => ( - } - action="chevron" - onClick={() => { - clientController.switchAccount(client.user!._id); - navigate("/app"); - }} - > - {client.user!.username} - - )} - - - - - */} +
+ + + + + + +
+
); } diff --git a/packages/client/components/auth/src/flows/FlowResend.tsx b/packages/client/components/auth/src/flows/FlowResend.tsx index 378d4a93..7c7fd015 100644 --- a/packages/client/components/auth/src/flows/FlowResend.tsx +++ b/packages/client/components/auth/src/flows/FlowResend.tsx @@ -40,7 +40,7 @@ export default function FlowResend() { - {t("login.remembered")} + {t("login.remembered")} ); diff --git a/packages/client/components/auth/src/flows/FlowReset.tsx b/packages/client/components/auth/src/flows/FlowReset.tsx index 37fb86dc..8ddbc0b1 100644 --- a/packages/client/components/auth/src/flows/FlowReset.tsx +++ b/packages/client/components/auth/src/flows/FlowReset.tsx @@ -40,7 +40,7 @@ export default function FlowReset() { - {t("login.remembered")} + {t("login.remembered")} {import.meta.env.DEV && (
- {t("login.remembered")} + {t("login.remembered")} @@ -95,7 +95,7 @@ export default function FlowVerify() { - {t("login.remembered")} + {t("login.remembered")} diff --git a/packages/client/components/auth/src/flows/Form.tsx b/packages/client/components/auth/src/flows/Form.tsx index b1ee9f51..b1e56588 100644 --- a/packages/client/components/auth/src/flows/Form.tsx +++ b/packages/client/components/auth/src/flows/Form.tsx @@ -1,6 +1,8 @@ import HCaptcha, { HCaptchaFunctions } from "solid-hcaptcha"; import { For, JSX, Show, createSignal } from "solid-js"; +import { cva } from "styled-system/css"; + import { mapAnyError } from "@revolt/client"; import { useTranslation } from "@revolt/i18n"; import { Checkbox, Column, FormGroup, Input, Typography } from "@revolt/ui"; @@ -8,7 +10,7 @@ import { Checkbox, Column, FormGroup, Input, Typography } from "@revolt/ui"; /** * Available field types */ -type Field = "email" | "password" | "new-password" | "log-out"; +type Field = "email" | "password" | "new-password" | "log-out" | "username"; /** * Properties to apply to fields @@ -38,9 +40,24 @@ const useFieldConfiguration = () => { "log-out": { name: () => t("login.log_out_other"), }, + username: { + minLength: 2, + type: "text", + autocomplete: "none", + name: () => t("login.username"), + placeholder: () => t("login.enter.username"), + }, }; }; +const labelRow = cva({ + base: { + gap: "var(--gap-sm)", + display: "flex", + alignItems: "center", + }, +}); + interface FieldProps { /** * Fields to gather @@ -67,11 +84,12 @@ export function Fields(props: FieldProps) { {(field) => ( {field === "log-out" ? ( - + ) : ( <> diff --git a/packages/client/components/client/Controller.ts b/packages/client/components/client/Controller.ts index f1a68278..fd7411aa 100644 --- a/packages/client/components/client/Controller.ts +++ b/packages/client/components/client/Controller.ts @@ -138,9 +138,9 @@ class Lifecycle { this.client.on("ready", this.onReady); } - #enter(state: State) { - console.debug("Entering state", state); - this.#setStateSetter(state); + #enter(nextState: State) { + console.debug("Entering state", nextState); + this.#setStateSetter(nextState); // Clean up retry timer if (this.#retryTimeout) { @@ -148,26 +148,42 @@ class Lifecycle { this.#retryTimeout = undefined; } - switch (state) { + switch (nextState) { case State.LoggingIn: + this.client.api.get("/onboard/hello").then(({ onboarding }) => { + if (onboarding) { + this.transition({ + type: TransitionType.NoUser, + }); + } else { + this.client.connect(); + } + }); + + break; case State.Connecting: case State.Reconnecting: this.client.connect(); break; case State.Connected: + state.auth.markValid(); this.#setLoadedOnce(true); this.#connectionFailures = 0; break; case State.Dispose: this.dispose(); - this.#enter(State.Ready); + this.transition({ + type: TransitionType.Ready, + }); this.#setLoadedOnce(false); break; case State.Disconnected: this.#connectionFailures++; if (!navigator.onLine) { - this.#enter(State.Offline); + this.transition({ + type: TransitionType.DeviceOffline, + }); } else { const retryIn = (Math.pow(2, this.#connectionFailures) - 1) * @@ -181,7 +197,9 @@ class Lifecycle { this.#retryTimeout = setTimeout(() => { this.#retryTimeout = undefined; - this.#enter(State.Reconnecting); + this.transition({ + type: TransitionType.Retry, + }); }, retryIn * 1e3) as never; } break; @@ -460,6 +478,7 @@ export default class ClientController { _id: session._id, token: session.token, userId: session.user_id, + valid: false, }; state.auth.setSession(createdSession); @@ -469,6 +488,16 @@ export default class ClientController { }); } + async selectUsername(username: string) { + await this.lifecycle.client.api.post("/onboard/complete", { + username, + }); + + this.lifecycle.transition({ + type: TransitionType.UserCreated, + }); + } + logout() { state.auth.removeSession(); this.lifecycle.transition({ diff --git a/packages/client/components/i18n/locales b/packages/client/components/i18n/locales index 1f0a96a7..62908308 160000 --- a/packages/client/components/i18n/locales +++ b/packages/client/components/i18n/locales @@ -1 +1 @@ -Subproject commit 1f0a96a7c93a187fed5f2a8cce218c406a62b7d2 +Subproject commit 6290830831cac101224faa4a6d29d4ba26c8a1cd diff --git a/packages/client/components/state/stores/Auth.ts b/packages/client/components/state/stores/Auth.ts index 2a899c99..2933d5a0 100644 --- a/packages/client/components/state/stores/Auth.ts +++ b/packages/client/components/state/stores/Auth.ts @@ -9,6 +9,7 @@ export type Session = { _id: string; token: string; userId: string; + valid: boolean; }; export type TypeAuth = { @@ -39,6 +40,7 @@ export class Auth extends AbstractStore<"auth", TypeAuth> { _id: CONFIGURATION.DEVELOPMENT_SESSION_ID ?? "0", token: CONFIGURATION.DEVELOPMENT_TOKEN, userId: CONFIGURATION.DEVELOPMENT_USER_ID, + valid: true, }); } @@ -70,12 +72,14 @@ export class Auth extends AbstractStore<"auth", TypeAuth> { if ( typeof input.session._id === "string" && typeof input.session.token === "string" && - typeof input.session.userId === "string" + typeof input.session.userId === "string" && + input.session.valid ) { session = { _id: input.session._id, token: input.session.token, userId: input.session.userId, + valid: true, }; } } @@ -107,4 +111,14 @@ export class Auth extends AbstractStore<"auth", TypeAuth> { removeSession() { this.set("session", undefined!); } + + /** + * Mark current session as valid + */ + markValid() { + const session = this.get().session; + if (session && !session.valid) { + this.set("session", "valid", true); + } + } } diff --git a/packages/client/src/interface/Home.tsx b/packages/client/src/interface/Home.tsx index ecdd81eb..723c6937 100644 --- a/packages/client/src/interface/Home.tsx +++ b/packages/client/src/interface/Home.tsx @@ -24,10 +24,15 @@ import { styled, } from "@revolt/ui"; -import wideSvg from "../../../client/public/assets/wide.svg"; +import RevoltSvg from "../../public/assets/wordmark_wide_500px.svg?component-solid"; import { HeaderIcon } from "./common/CommonHeader"; +const Logo = styled(RevoltSvg)` + width: 240px; + fill: ${(props) => props.theme!.colours["foreground"]}; +`; + /** * Base layout of the home page (i.e. the header/background) */ @@ -112,11 +117,12 @@ export function HomePage() { Home
- - {t("app.special.modals.onboarding.welcome")} -
- -
+ + + {t("app.special.modals.onboarding.welcome")} + + +