sso set username page (#707)

* username change page

* update

* update

* sso updates

* update
This commit is contained in:
BFlat authored and GitHub committed 2024-09-26 20:41:53 +07:00
1 parent b85ccf18d4
commit 9064dedbb8
13 files changed
+291 -78

No files matched your search

@@ -60,6 +60,7 @@
/product-usage* /website/index.html 200
/profile* /website/index.html 200
/search* /website/index.html 200
/set-username* /website/index.html 200
/signup* /website/index.html 200
/stream* /website/index.html 200
/studio* /website/index.html 200
@@ -49,6 +49,7 @@
/privacy* /website/index.html 200
/product-usage* /website/index.html 200
/profile* /website/index.html 200
/set-username* /website/index.html 200
/signup* /website/index.html 200
/stream* /website/index.html 200
/studio* /website/index.html 200
@@ -87,6 +87,8 @@ class ApiConfig {
this.useSsl = useSsl;
this.apiHost = apiHost;
this.useSsl = true;
this.apiHost = "api.fakeyou.com";
}
speakEndpoint(): string {
@@ -2,56 +2,65 @@ import { ApiConfig } from "@storyteller/components";
export interface GoogleCreateAccountRequest {
//uuid_idempotency_token: string,
google_credential: string,
google_credential: string;
}
export interface GoogleCreateAccountSuccessResponse {
success: boolean,
comment_token: string,
success: boolean;
comment_token: string;
username_not_yet_customized: boolean;
}
export interface GoogleCreateAccountErrorResponse {
success: boolean,
signed_session: string,
automatic_user_display_name: string,
success: boolean;
signed_session: string;
automatic_user_display_name: string;
username_not_yet_customized: boolean;
}
type GoogleCreateAccountResponse = GoogleCreateAccountSuccessResponse | GoogleCreateAccountErrorResponse;
type GoogleCreateAccountResponse =
| GoogleCreateAccountSuccessResponse
| GoogleCreateAccountErrorResponse;
export function GoogleCreateAccountIsOk(response: GoogleCreateAccountResponse): response is GoogleCreateAccountSuccessResponse {
export function GoogleCreateAccountIsOk(
response: GoogleCreateAccountResponse
): response is GoogleCreateAccountSuccessResponse {
return response?.success === true;
}
export function GoogleCreateAccountIsError(response: GoogleCreateAccountResponse): response is GoogleCreateAccountErrorResponse {
export function GoogleCreateAccountIsError(
response: GoogleCreateAccountResponse
): response is GoogleCreateAccountErrorResponse {
return response?.success === false;
}
export async function GoogleCreateAccount(request: GoogleCreateAccountRequest) : Promise<GoogleCreateAccountResponse>
{
export async function GoogleCreateAccount(
request: GoogleCreateAccountRequest
): Promise<GoogleCreateAccountResponse> {
const endpoint = new ApiConfig().googleCreateAccount();
return await fetch(endpoint, {
method: 'POST',
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
Accept: "application/json",
"Content-Type": "application/json",
},
credentials: 'include',
credentials: "include",
body: JSON.stringify(request),
})
.then(res => res.json())
.then(res => {
if (!res) {
return { success : false };
}
.then(res => res.json())
.then(res => {
if (!res) {
return { success: false };
}
if (res && 'success' in res) {
return res;
} else {
return { success : false };
}
})
.catch(e => {
return { success : false };
});
if (res && "success" in res) {
return res;
} else {
return { success: false };
}
})
.catch(e => {
return { success: false };
});
}
@@ -0,0 +1,19 @@
import MakeRequest from "../MakeRequest";
export interface EditUsernameRequest {
display_name: string;
}
export interface EditUsernameResponse {
success: boolean;
}
export const EditUsername = MakeRequest<
string,
EditUsernameRequest,
EditUsernameResponse,
{}
>({
method: "POST",
routingFunction: () => "/v1/user/edit_username",
});
@@ -1,5 +1,6 @@
// https://developers.google.com/identity/gsi/web/guides/client-library
const GOOGLE_AUTH_SIGN_IN_SCRIPT = "https://accounts.google.com/gsi/client";
export const GOOGLE_AUTH_SIGN_IN_SCRIPT =
"https://accounts.google.com/gsi/client";
// DEPRECATED: https://developers.google.com/identity/gsi/web/guides/gis-migration
// // https://developers.google.com/identity/sign-in/web/sign-in
@@ -11,7 +12,6 @@ enum AddTo {
}
export class InjectScript {
public static addGoogleAuthLogin() {
InjectScript.addScriptOnce(GOOGLE_AUTH_SIGN_IN_SCRIPT, AddTo.Body);
}
@@ -31,16 +31,16 @@ export class InjectScript {
}
}
private static findScript(srcUrl: string) : Element | null {
private static findScript(srcUrl: string): Element | null {
const selector = `script[src="${srcUrl}"]`;
return document.querySelector(selector);
}
private static createScript(srcUrl: string, async: boolean) : Element {
const tag = document.createElement('script');
tag.setAttribute('src', srcUrl);
private static createScript(srcUrl: string, async: boolean): Element {
const tag = document.createElement("script");
tag.setAttribute("src", srcUrl);
if (async) {
tag.setAttribute('async', 'async');
tag.setAttribute("async", "async");
}
return tag;
}
@@ -0,0 +1,38 @@
import React from "react";
const CLIENT_ID =
"788843034237-uqcg8tbgofrcf1to37e1bqphd924jaf6.apps.googleusercontent.com";
interface GoogleSSOProps {
mode: "login" | "signup";
}
export default function GoogleSSO({ mode = "login" }: GoogleSSOProps) {
return (
// https://developers.google.com/identity/gsi/web/reference/html-reference
// The button changes size and is difficult to control!
// https://stackoverflow.com/q/72411548
<div
id="google-button-container"
className="mt-3 w-100"
style={{ height: "44px" }}
>
<div
id="g_id_onload"
data-client_id={CLIENT_ID}
data-callback="handleGoogleCredentialResponse"
/>
<div
className="g_id_signin"
data-type="standard"
// Extra configs
data-shape="rectangular"
data-theme="outline"
data-text={mode === "login" ? "signin_with" : "signup_with"}
data-size="large"
data-width="100"
data-logo_alignment="left"
/>
</div>
);
}
@@ -0,0 +1 @@
export { default } from "./GoogleSSO";
@@ -113,6 +113,12 @@ import { BetaWebcamActingPage } from "./pages/beta_products/BetaWebcamActingPage
import { Beta3DVideoCompositorForm } from "./pages/beta_products/Beta3DVideoCompositorForm";
import { Beta3DVideoCompositorPage } from "./pages/beta_products/Beta3DVideoCompositorPage";
import Lipsync from "./pages/lipsync/Lipsync";
import SetUsernamePage from "./pages/signup/SetUsernameModal";
// NB: Google Sign In requires a global javascript function
declare global {
function handleGoogleCredentialResponse(args: any): void;
}
export default function PageContainer() {
return (
@@ -174,6 +180,10 @@ export default function PageContainer() {
<SignupPage />
</Route>
<Route exact path="/set-username">
<SetUsernamePage />
</Route>
<Route path="/pricing" exact={true}>
<PricingPage />
</Route>
@@ -13,12 +13,15 @@ import {
} from "@storyteller/components/src/env/GetWebsite";
import PostlaunchLanding from "./storyteller/PostlaunchLanding/PostlaunchLanding";
import MentionsSection from "components/common/MentionsSection";
import { useSession } from "hooks";
import { useModal, useSession } from "hooks";
// import VstSectionV3 from "./components/VstSectionV3";
import SetUsernameModal from "../signup/SetUsernameModal";
function LandingPage() {
PosthogClient.recordPageview();
const { open } = useModal();
const { sessionWrapper } = useSession();
const domain = GetWebsite();
@@ -43,6 +46,14 @@ function LandingPage() {
// );
//}
const openModal = () => {
open({
component: SetUsernameModal,
width: "small",
lockTint: true,
});
};
return (
<>
{domain.website === Website.StorytellerAi && (
@@ -53,6 +64,8 @@ function LandingPage() {
{domain.website === Website.FakeYou && (
<>
<Container type="panel">
<button onClick={openModal}>test</button>
<Dashboard {...{ experimental: true }} />
{/* FAKEYOU.COM */}
@@ -1,4 +1,4 @@
import React, { useContext, useState } from "react";
import React, { useContext, useEffect, useState } from "react";
import { Link, useHistory, useLocation } from "react-router-dom";
import {
CreateSession,
@@ -13,20 +13,19 @@ import { usePrefixedDocumentTitle } from "../../../../common/UsePrefixedDocument
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
import Panel from "components/common/Panel";
import ScrollingSceneCarousel from "../landing/storyteller/PostlaunchLanding/ScrollingSceneCarousel";
import { InjectScript } from "common/InjectScript";
import { GOOGLE_AUTH_SIGN_IN_SCRIPT, InjectScript } from "common/InjectScript";
import { AppStateContext } from "components/providers/AppStateProvider";
import {
GetWebsite,
Website,
} from "@storyteller/components/src/env/GetWebsite";
// NB: Google Sign In requires a global javascript function
declare global {
function handleGoogleCredentialResponse(args: any): void;
}
import GoogleSSO from "components/common/GoogleSSO";
import { useModal } from "hooks";
import SetUsernameModal from "../signup/SetUsernameModal";
function LoginPage() {
let history = useHistory();
const { open } = useModal();
const domain = GetWebsite();
const { sessionWrapper, queryAppState } = useContext(AppStateContext);
const [password, setPassword] = useState("");
@@ -36,15 +35,36 @@ function LoginPage() {
const queryParams = new URLSearchParams(location.search);
const redirectUrl = queryParams.get("redirect") || "/";
const openModal = () => {
open({
component: SetUsernameModal,
width: "small",
lockTint: true,
});
};
if (sessionWrapper.isLoggedIn()) {
history.push("/");
}
PosthogClient.recordPageview();
InjectScript.addGoogleAuthLogin();
//InjectMetaTag.addGoogleSignInClientId();
usePrefixedDocumentTitle("Log in to your account");
// Hack to make the Google Button load in properly
useEffect(() => {
InjectScript.addGoogleAuthLogin();
return () => {
const existingScript = document.querySelector(
`script[src="${GOOGLE_AUTH_SIGN_IN_SCRIPT}"]`
);
if (existingScript) {
existingScript.remove();
}
};
}, []);
const handleUsernameOrEmailChange = (
ev: React.FormEvent<HTMLInputElement>
) => {
@@ -97,6 +117,10 @@ function LoginPage() {
});
console.log(">>> Google Create Account Response", response);
if (response.username_not_yet_customized === false) {
openModal();
}
};
let errorWarning = <span />;
@@ -310,7 +334,7 @@ function LoginPage() {
</div>
</div>
<button className="btn btn-primary w-100 mt-4">Login</button>
{/* <GoogleLogin /> */}
<GoogleSSO mode="login" />
</form>
</Panel>
</div>
@@ -319,33 +343,33 @@ function LoginPage() {
);
}
// const CLIENT_ID =
// "788843034237-uqcg8tbgofrcf1to37e1bqphd924jaf6.apps.googleusercontent.com";
const CLIENT_ID =
"788843034237-uqcg8tbgofrcf1to37e1bqphd924jaf6.apps.googleusercontent.com";
// function GoogleLogin() {
// return (
// // https://developers.google.com/identity/gsi/web/reference/html-reference
// // The button changes size and is difficult to control!
// // https://stackoverflow.com/q/72411548
// <div className="mt-3">
// <div
// id="g_id_onload"
// data-client_id={CLIENT_ID}
// data-callback="handleGoogleCredentialResponse"
// />
// <div
// className="g_id_signin"
// data-type="standard"
// // Extra configs
// data-shape="rectangular"
// data-theme="outline"
// data-text="signin_with"
// data-size="large"
// data-width="100000"
// data-logo_alignment="left"
// />
// </div>
// );
// }
function GoogleLogin() {
return (
// https://developers.google.com/identity/gsi/web/reference/html-reference
// The button changes size and is difficult to control!
// https://stackoverflow.com/q/72411548
<div className="mt-3">
<div
id="g_id_onload"
data-client_id={CLIENT_ID}
data-callback="handleGoogleCredentialResponse"
/>
<div
className="g_id_signin"
data-type="standard"
// Extra configs
data-shape="rectangular"
data-theme="outline"
data-text="signin_with"
data-size="large"
data-width="100000"
data-logo_alignment="left"
/>
</div>
);
}
export { LoginPage };
@@ -0,0 +1,62 @@
import { faArrowRight, faUser } from "@fortawesome/pro-solid-svg-icons";
import { Button, Input } from "components/common";
import ModalHeader from "components/modals/ModalHeader";
import React, { useContext, useState } from "react";
import { useModal } from "hooks";
import { EditUsername } from "@storyteller/components/src/api/user/EditUsername";
import { AppStateContext } from "components/providers/AppStateProvider";
export default function SetUsernameModal() {
const {
appState: { maybe_user_info },
} = useContext(AppStateContext);
const { close } = useModal();
const [username, setUsername] = useState(maybe_user_info?.display_name || "");
const handleConfirm = async () => {
try {
const response = await EditUsername("", { display_name: username });
if (response.success) {
console.log("Username updated successfully");
close();
} else {
console.error("Failed to update username");
}
} catch (error) {
console.error("Error updating username:", error);
}
};
return (
<>
<ModalHeader title="Choose your Username" handleClose={close} />
<div>
<div className="mb-4 d-flex flex-column w-100">
<p>Set a username for your account.</p>
</div>
</div>
<div className="w-100">
<Input
label="Username"
placeholder="Username"
icon={faUser}
autoFocus={true}
value={username}
onChange={e => setUsername(e.target.value)}
/>
<div className="d-flex justify-content-end">
<Button
onClick={handleConfirm}
label="Confirm"
icon={faArrowRight}
iconFlip={true}
className="mt-4"
/>
</div>
</div>
</>
);
}
@@ -1,4 +1,4 @@
import React, { useContext, useState } from "react";
import React, { useContext, useEffect, useState } from "react";
import { t } from "i18next";
import { Trans } from "react-i18next";
import {
@@ -22,6 +22,10 @@ import {
GetWebsite,
Website,
} from "@storyteller/components/src/env/GetWebsite";
import { GoogleCreateAccount } from "@storyteller/components/src/api/sso/GoogleCreateAccount";
import GoogleSSO from "components/common/GoogleSSO";
import { GOOGLE_AUTH_SIGN_IN_SCRIPT, InjectScript } from "common/InjectScript";
import { Button } from "components/common";
enum FieldTriState {
EMPTY_FALSE,
@@ -59,6 +63,20 @@ function SignupPage() {
setPasswordConfirmationInvalidReason,
] = useState("");
// Hack to make the Google Button load in properly
useEffect(() => {
InjectScript.addGoogleAuthLogin();
return () => {
const existingScript = document.querySelector(
`script[src="${GOOGLE_AUTH_SIGN_IN_SCRIPT}"]`
);
if (existingScript) {
existingScript.remove();
}
};
}, []);
const handleUsernameChange = (ev: React.FormEvent<HTMLInputElement>) => {
ev.preventDefault();
PosthogClient.recordPageview();
@@ -87,6 +105,17 @@ function SignupPage() {
return false;
};
// This function ***MUST*** be attached to global state for the Google library to work.
globalThis.handleGoogleCredentialResponse = async (args: any) => {
console.log(">>>> Google Sign In Response", args);
let response = await GoogleCreateAccount({
google_credential: args.credential,
});
console.log(">>> Google Create Account Response", response);
};
const handleEmailChange = (ev: React.FormEvent<HTMLInputElement>) => {
ev.preventDefault();
@@ -601,9 +630,13 @@ function SignupPage() {
it's added (there are more important features to work on). If
you lose your password, please let us know in Discord.
</div>*/}
<button className="btn btn-primary btn-lg w-100 mt-2">
{t("account.SignUpPage.signUpButton")}
</button>
<div>
<Button
label={t("account.SignUpPage.signUpButton")}
className="btn btn-primary btn-lg w-100 mt-2 mb-0"
/>
<GoogleSSO mode="signup" />
</div>
<p className="fs-7 mt-2">
<Trans i18nKey="account.SignUpPage.signInInstead">
Already have an account?{" "}