From fecb9095709787fe565d811594fccbfebea281c4 Mon Sep 17 00:00:00 2001 From: FromTheLOLAshes <153381408+FromTheLOLAshes@users.noreply.github.com> Date: Sun, 23 Jun 2024 15:20:06 -0400 Subject: [PATCH] Fix 405 error (#516) Co-authored-by: Christopher Oliphant --- app/Classes/ApiManager/UsersApi.ts | 51 ++++++++++++ app/pages/PageEnigma/PageEditor.tsx | 3 +- app/root.tsx | 2 + app/routes/Signup.tsx | 109 +++++++++++++++++++++---- app/signals/authentication/fetchers.ts | 33 ++++++++ 5 files changed, 179 insertions(+), 19 deletions(-) diff --git a/app/Classes/ApiManager/UsersApi.ts b/app/Classes/ApiManager/UsersApi.ts index 2a5e64154e..d88670fa26 100644 --- a/app/Classes/ApiManager/UsersApi.ts +++ b/app/Classes/ApiManager/UsersApi.ts @@ -107,4 +107,55 @@ export class UsersApi extends ApiManager { }; }); } + + public async Signup({ + username, + email, + password, + passwordConfirmation, + }: { + username: string; + email: string; + password: string; + passwordConfirmation: string; + }): Promise> { + const endpoint = `${this.ApiTargets.BaseApi}/v1/create_account`; + const body = { + email_address: email, + password, + password_confirmation: passwordConfirmation, + username, + }; + return await this.post< + { + username: string; + email_address: string; + password: string; + password_confirmation: string; + }, + { + success: boolean; + signed_session?: string; + error_fields?: Record; + error_message?: string; + error_type?: string; + } + >({ + endpoint: endpoint, + body: body, + }) + .then((response) => { + return { + success: response.success, + data: { signedSession: response.signed_session }, + errorMessage: Object.values(response.error_fields ?? {}).join(","), + }; + }) + .catch((err) => { + return { + success: false, + error_message: err.message, + }; + }); + } } diff --git a/app/pages/PageEnigma/PageEditor.tsx b/app/pages/PageEnigma/PageEditor.tsx index a89516eeb7..0aac5b4e83 100644 --- a/app/pages/PageEnigma/PageEditor.tsx +++ b/app/pages/PageEnigma/PageEditor.tsx @@ -1,6 +1,6 @@ import React, { useEffect } from "react"; import { useSignals } from "@preact/signals-react/runtime"; -import { LoadingDots, Toaster, TopBar } from "~/components"; +import { LoadingDots, TopBar } from "~/components"; import { SidePanel } from "~/pages/PageEnigma/comps/SidePanel"; import { Timeline } from "./comps/Timeline"; import { Controls3D } from "./comps/Controls3D"; @@ -108,7 +108,6 @@ export const PageEditor = () => { }} >
- diff --git a/app/root.tsx b/app/root.tsx index 0c03a271e7..3413f440f8 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -22,6 +22,7 @@ import { config } from "@fortawesome/fontawesome-svg-core"; import EnvironmentVariables from "~/Classes/EnvironmentVariables"; import { environmentVariables, pageHeight, pageWidth } from "~/signals"; +import { Toaster } from "~/components"; config.autoAddCss = false; /* eslint-disable import/first */ @@ -95,6 +96,7 @@ export default function App() { {data && }
+ diff --git a/app/routes/Signup.tsx b/app/routes/Signup.tsx index 1641e80644..c208a1e061 100644 --- a/app/routes/Signup.tsx +++ b/app/routes/Signup.tsx @@ -1,31 +1,103 @@ -import { Form } from "@remix-run/react"; import { faEnvelope, faKey, faUser } from "@fortawesome/pro-solid-svg-icons"; -import { - Button, - H1, - Input, - Link, - P, -} from '~/components'; +import { Button, H1, Input, Link, P } from "~/components"; +import { addToast, authentication, signUp } from "~/signals"; +import { FormEvent, useRef, useState } from "react"; +import { AUTH_STATUS, ToastTypes } from "~/enums"; +import { useSignalEffect, useSignals } from "@preact/signals-react/runtime"; +import { useNavigate, useSearchParams } from "@remix-run/react"; + +const regEx = + /^(([^<>()[\].,;:\s@"]+(.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i; + +export default function SignUpScreen() { + useSignals(); + const navigate = useNavigate(); + const formRef = useRef(null); + const [usernameError, setUsernameError] = useState(""); + const [emailError, setEmailError] = useState(""); + const [passwordError, setPasswordError] = useState(""); + const [passwordConfirmationError, setPasswordConfirmationError] = + useState(""); + const [searchParams] = useSearchParams(); + const { status: authStatus } = authentication; + + const handleOnSubmit = (ev: FormEvent) => { + ev.preventDefault(); + if (formRef.current) { + const form = new FormData(formRef.current); + const email = form.get("email")?.toString(); + const password = form.get("password")?.toString(); + const passwordConfirmation = form + .get("password-confirmation") + ?.toString(); + const username = form.get("username")?.toString(); + setUsernameError(""); + if (!username || username.length < 6) { + setUsernameError("Username must be at least 6 characters long"); + } + setEmailError(""); + if (!email || !email.match(regEx)) { + setEmailError("Email must be a valid email address"); + } + setPasswordError(""); + if (!password || password.length < 8) { + setPasswordError("Password must be at least 8 characters long"); + } + setPasswordConfirmationError(""); + if (!passwordError && passwordConfirmation !== password) { + setPasswordConfirmationError("Passwords do not match"); + } + + if ( + !usernameError && + !passwordError && + !emailError && + !passwordConfirmationError && + signUp + ) { + signUp({ + username: username!, + email: email!, + password: password!, + passwordConfirmation: passwordConfirmation!, + }).then((error) => { + console.log("Error occured", error); + if (error) { + addToast(ToastTypes.ERROR, error); + } + }); + } + } + }; // end handleOnSubmit + + useSignalEffect(() => { + const redirectPath = searchParams.get("redirect"); + if (authStatus.value === AUTH_STATUS.LOGGED_IN) { + navigate(redirectPath ? redirectPath : "/"); + return; + } + if (authStatus.value === AUTH_STATUS.NO_ACCESS) { + window.open("https://storyteller.ai/", "_self"); + return; + } + }); -export default function LoginScreen() { return (
-
+

Sign Up to Storyteller

-
-
+
+
@@ -35,6 +107,7 @@ export default function LoginScreen() { icon={faEnvelope} placeholder="Email" name="email" + errorMessage={emailError} required />
@@ -45,6 +118,7 @@ export default function LoginScreen() { name="password" placeholder="Password" autoComplete="current-password" + errorMessage={passwordError} required />
@@ -54,6 +128,7 @@ export default function LoginScreen() { icon={faKey} placeholder="Password COnfirmation" name="password-confirmation" + errorMessage={passwordConfirmationError} required />
@@ -62,9 +137,9 @@ export default function LoginScreen() {

Already have an account?

- Log in instead + Log in instead
- +
); diff --git a/app/signals/authentication/fetchers.ts b/app/signals/authentication/fetchers.ts index 0dd764b19c..a46f2c4372 100644 --- a/app/signals/authentication/fetchers.ts +++ b/app/signals/authentication/fetchers.ts @@ -48,6 +48,39 @@ export const login = async ({ getUserInfoAndSubcriptions(); }; +export const signUp = async ({ + username, + email, + password, + passwordConfirmation, +}: { + username: string; + email: string; + password: string; + passwordConfirmation: string; +}) => { + updateAuthStatus(AUTH_STATUS.LOGGING); + + const usersApi = new UsersApi(); + const response = await usersApi.Signup({ + email, + password, + passwordConfirmation, + username, + }); + console.log(response); + if (!response.success || !response.data) { + setLogoutStates(); + return response.errorMessage ?? "Unknown error"; + } + + // technically user is login with the system now, HOWEVER, + // in storyteller studio, only having a sesison is not enough, + // we need session info and active subscription info as well + getUserInfoAndSubcriptions(); + return ""; +}; + export const persistLogin = async () => { //Only run First Load, return if not if (authentication.status.value !== AUTH_STATUS.INIT) {