api manager works, persist login works

This commit is contained in:
wil committed 2024-08-28 23:16:41 -04:00
1 parent a52013fd0e
commit 9f35ceed04
8 files changed
+247 -18

No files matched your search

-4
View File
@@ -154,10 +154,6 @@ export class ApiManager {
return this.fetchMultipartFormData<T>(endpoint, {
method: "POST",
headers: {
Accept: "application/json",
},
credentials: "include",
body: formData,
});
}
+20 -6
View File
@@ -1,16 +1,30 @@
import { StrictMode } from "react";
import { StrictMode, useRef } from "react";
import { createRoot } from "react-dom/client";
import { useEffect } from "react";
import EnvironmentVariables from "~/Classes/EnvironmentVariables";
import environmentVariables from "~/Classes/EnvironmentVariables";
import { RouterProvider } from "react-router-dom";
import { router } from "./router";
import "./global.css";
const App = () => {
useEffect(() => {
EnvironmentVariables.initialize(import.meta.env);
}, []);
const AppRerenderCount = useRef(0);
AppRerenderCount.current++;
if (AppRerenderCount.current === 1) {
console.log(`App rerendered ${AppRerenderCount.current} times`);
} else {
console.warn(`App rerendered ${AppRerenderCount.current} times`);
}
if (Object.keys(environmentVariables.values).length === 0) {
environmentVariables.initialize({
BASE_API: import.meta.env.VITE_BASE_API,
GOOGLE_API: import.meta.env.VITE_GOOGLE_API,
FUNNEL_API: import.meta.env.VITE_FUNNEL_API,
CDN_API: import.meta.env.VITE_CDN_API,
GRAVATAR_API: import.meta.env.VITE_GRAVATAR_API,
});
}
return <RouterProvider router={router} />;
};
+80
View File
@@ -0,0 +1,80 @@
import React from "react";
import { twMerge } from "tailwind-merge";
import { IconDefinition } from "@fortawesome/pro-thin-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
const kebabCase = (str: string) =>
str
.replace(/([a-z])([A-Z])/g, "$1-$2")
.replace(/[\s_]+/g, "-")
.toLowerCase();
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
inputClassName?: string;
iconClassName?: string;
label?: string;
icon?: IconDefinition;
isError?: boolean;
errorMessage?: string;
}
export const Input = React.forwardRef(
(
{
label,
icon,
inputClassName,
iconClassName,
className,
id,
isError,
onBlur,
onFocus,
errorMessage,
...rest
}: InputProps,
ref: React.ForwardedRef<HTMLInputElement>,
) => {
return (
<div className={twMerge("flex flex-col", className)}>
{label && <label htmlFor={id ? id : kebabCase(label)}>{label}</label>}
<div className="relative w-full">
{icon && (
<FontAwesomeIcon
icon={icon}
className={twMerge("text-md absolute pl-3 pt-3", iconClassName)}
/>
)}
<input
ref={ref}
id={id ? id : label ? kebabCase(label) : undefined}
className={twMerge(
"bg-brand-secondary h-10 w-full rounded-lg px-3 py-2.5 text-white outline-none",
"focus:outline-brand-primary outline-offset-0 transition-all duration-150 ease-in-out",
icon && "pl-10",
isError && "outline-red focus:outline-red",
inputClassName,
)}
onFocus={(e: React.FocusEvent<HTMLInputElement>) => {
if (onFocus) {
onFocus(e);
}
}}
onBlur={(e: React.FocusEvent<HTMLInputElement>) => {
if (onBlur) {
onBlur(e);
}
}}
{...rest}
/>
{errorMessage && (
<h6 className="text-red absolute z-10">{errorMessage}</h6>
)}
</div>
</div>
);
},
);
Input.displayName = "Input";
@@ -1,5 +1,5 @@
import { faSpinnerThird } from "@fortawesome/pro-thin-svg-icons";
import { twMerge } from "tailwind-merge";
import { faSpinnerThird } from "@fortawesome/pro-thin-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
export const Spinner = ({ className }: { className?: string }) => {
+2 -1
View File
@@ -1 +1,2 @@
export * from "./spinner";
export * from "./Spinne";
export * from "./Input";
+135 -1
View File
@@ -1,3 +1,137 @@
import { useRef } from "react";
import { useNavigate, useSearchParams, Link } from "react-router-dom";
import { useSignalEffect } from "@preact/signals-react/runtime";
import { faKey, faUser } from "@fortawesome/pro-thin-svg-icons";
import { AUTH_STATUS } from "~/enums";
import { authentication, login, logout } from "~/signals";
import {
Input,
// Spinner,
} from "~/components/ui";
export const Login = () => {
return <div>Login</div>;
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const formRef = useRef<HTMLFormElement | null>(null);
const { status: authStatus } = authentication;
// const authLoaderMessage = getAuthLoaderMessage();
// const shouldShowLoader = checkShouldShowLoader();
// const showNoAccessModal = authStatus.value === AUTH_STATUS.NO_ACCESS;
const handleOnSumbit = (ev: React.FormEvent<HTMLFormElement>) => {
ev.preventDefault();
if (formRef.current) {
const form = new FormData(formRef.current);
const usernameOrEmail = form.get("usernameOrEmail")?.toString();
const password = form.get("password")?.toString();
if (usernameOrEmail && password && login) {
login({
usernameOrEmail,
password,
});
}
}
}; // end handleOnSubmit
useSignalEffect(() => {
const redirectPath = searchParams.get("redirect");
if (authStatus.value === AUTH_STATUS.LOGGED_IN) {
navigate(redirectPath ? redirectPath : "/");
}
});
return (
<div className="fixed w-full">
<div className="mx-auto my-6 w-10/12 max-w-2xl">
<h1>Login to Storyteller</h1>
</div>
<div className="border-ui-border bg-ui-panel relative mx-auto my-6 w-10/12 max-w-2xl overflow-hidden rounded-lg border p-6">
<form
ref={formRef}
onSubmit={handleOnSumbit}
className="flex flex-col gap-4"
>
<Input
label="Username or Email"
icon={faUser}
name="usernameOrEmail"
placeholder="Username or Email"
autoComplete="username"
required
/>
<Input
label="Password"
icon={faKey}
type="password"
name="password"
placeholder="Password"
autoComplete="current-password"
required
/>
<div className="align-items mb-3 flex">
<a
href="https://storyteller.ai/password-reset"
className="text-brand-primary hover:text-brand-primary-400 grow text-sm transition-all duration-150"
>
Forgot your password?
</a>
<div className="flex justify-end gap-1 text-sm">
<p>Don&apos;t have an account?</p>
<Link to="/signup">Sign Up</Link>
</div>
</div>
<button className="h-11 w-full text-sm">Login</button>
</form>
{/* <LoadingDots
className="absolute left-0 top-0 h-full w-full"
isShowing={shouldShowLoader}
message={authLoaderMessage}
type="bricks"
/>
<ConfirmationModal
text="We're in a closed beta and you'll need a beta key to use this app."
title="Unauthorized"
open={showNoAccessModal}
onClose={handleClose}
cancelText="Close"
onCancel={handleClose}
okText="Get Beta Key"
onOk={() => {
handleClose();
if (window) {
window.open("https://storyteller.ai/beta-key/redeem", "_blank");
}
}}
/>*/}
</div>
</div>
);
};
// const handleClose = () => {
// if (authentication.status.value !== AUTH_STATUS.LOGGED_OUT) {
// logout();
// }
// };
// const checkShouldShowLoader = () => {
// return (
// authentication.status.value === AUTH_STATUS.LOGGING ||
// authentication.status.value === AUTH_STATUS.LOGGED_IN
// );
// };
// const getAuthLoaderMessage = () => {
// if (authentication.status.value === AUTH_STATUS.LOGGED_IN) {
// return "Authenticated, Redirecting...";
// }
// if (authentication.status.value === AUTH_STATUS.GET_USER_INFO) {
// return "Getting User Info...";
// }
// return "Getting Session...";
// };