sso set username page (#707)
* username change page * update * update * sso updates * update
This commit is contained in:
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?{" "}
|
||||
|
||||
Reference in new issue
Block a user