feat: Add signUp page and Sign out button
This commit is contained in:
parent
303f1862c5
commit
468f6ec573
6 changed files with 243 additions and 96 deletions
|
|
@ -34,6 +34,9 @@ export default function Header() {
|
|||
<Link to="/">
|
||||
<span className="ml-4 text-2xl">⛓️</span>
|
||||
</Link>
|
||||
<Button variant="outline" className="">
|
||||
Sign out
|
||||
</Button>
|
||||
{flows.findIndex((f) => tabId === f.id) !== -1 && tabId !== "" && (
|
||||
<MenuBar flows={flows} tabId={tabId} />
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -9,90 +9,91 @@ export default function InputComponent({
|
|||
disabled,
|
||||
password,
|
||||
editNode = false,
|
||||
placeholder = "Type something...",
|
||||
}: InputComponentType) {
|
||||
const [pwdVisible, setPwdVisible] = useState(false);
|
||||
|
||||
// Clear component state
|
||||
useEffect(() => {
|
||||
if (disabled) {
|
||||
onChange("");
|
||||
}
|
||||
if (disabled) {
|
||||
onChange("");
|
||||
}
|
||||
}, [disabled, onChange]);
|
||||
|
||||
return (
|
||||
<div className="relative w-full">
|
||||
<Input
|
||||
value={value}
|
||||
disabled={disabled}
|
||||
className={classNames(
|
||||
password && !pwdVisible && value !== "" ? " text-clip password " : "",
|
||||
editNode ? " input-edit-node " : "",
|
||||
password && editNode ? "pr-8" : "",
|
||||
password && !editNode ? "pr-10" : ""
|
||||
)}
|
||||
placeholder={password && editNode ? "Key" : "Type something..."}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.value);
|
||||
}}
|
||||
/>
|
||||
{password && (
|
||||
<button
|
||||
className={classNames(
|
||||
editNode
|
||||
? "input-component-true-button"
|
||||
: "input-component-false-button"
|
||||
)}
|
||||
onClick={() => {
|
||||
setPwdVisible(!pwdVisible);
|
||||
}}
|
||||
>
|
||||
{password &&
|
||||
(pwdVisible ? (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
className={classNames(
|
||||
editNode
|
||||
? "input-component-true-svg"
|
||||
: "input-component-false-svg"
|
||||
)}
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M3.98 8.223A10.477 10.477 0 001.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.45 10.45 0 0112 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 01-4.293 5.774M6.228 6.228L3 3m3.228 3.228l3.65 3.65m7.894 7.894L21 21m-3.228-3.228l-3.65-3.65m0 0a3 3 0 10-4.243-4.243m4.242 4.242L9.88 9.88"
|
||||
/>
|
||||
</svg>
|
||||
) : (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
className={classNames(
|
||||
editNode
|
||||
? "input-component-true-svg"
|
||||
: "input-component-false-svg"
|
||||
)}
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z"
|
||||
/>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
</svg>
|
||||
))}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="relative w-full">
|
||||
<Input
|
||||
value={value}
|
||||
disabled={disabled}
|
||||
className={classNames(
|
||||
password && !pwdVisible && value !== "" ? " text-clip password " : "",
|
||||
editNode ? " input-edit-node " : "",
|
||||
password && editNode ? "pr-8" : "",
|
||||
password && !editNode ? "pr-10" : ""
|
||||
)}
|
||||
placeholder={password && editNode ? "Key" : placeholder}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.value);
|
||||
}}
|
||||
/>
|
||||
{password && (
|
||||
<button
|
||||
className={classNames(
|
||||
editNode
|
||||
? "input-component-true-button"
|
||||
: "input-component-false-button"
|
||||
)}
|
||||
onClick={() => {
|
||||
setPwdVisible(!pwdVisible);
|
||||
}}
|
||||
>
|
||||
{password &&
|
||||
(pwdVisible ? (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
className={classNames(
|
||||
editNode
|
||||
? "input-component-true-svg"
|
||||
: "input-component-false-svg"
|
||||
)}
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M3.98 8.223A10.477 10.477 0 001.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.45 10.45 0 0112 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 01-4.293 5.774M6.228 6.228L3 3m3.228 3.228l3.65 3.65m7.894 7.894L21 21m-3.228-3.228l-3.65-3.65m0 0a3 3 0 10-4.243-4.243m4.242 4.242L9.88 9.88"
|
||||
/>
|
||||
</svg>
|
||||
) : (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
className={classNames(
|
||||
editNode
|
||||
? "input-component-true-svg"
|
||||
: "input-component-false-svg"
|
||||
)}
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z"
|
||||
/>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
</svg>
|
||||
))}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -508,3 +508,10 @@ export const URL_EXCLUDED_FROM_ERROR_RETRIES = [
|
|||
"/api/v1/custom_component",
|
||||
"/api/v1/validate/prompt",
|
||||
];
|
||||
|
||||
export const CONTROL_INPUT_STATE = {
|
||||
email: '',
|
||||
password: '',
|
||||
cnfPassword: '',
|
||||
username: '',
|
||||
};
|
||||
|
|
|
|||
119
src/frontend/src/pages/signUpPage/index.tsx
Normal file
119
src/frontend/src/pages/signUpPage/index.tsx
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
import _ from "lodash";
|
||||
import { FaApple, FaGithub } from "react-icons/fa";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import { Input } from "../../components/ui/input";
|
||||
import { GoogleIcon } from "../../icons/Google";
|
||||
import { useContext, useState } from "react";
|
||||
import { CONTROL_INPUT_STATE } from "../../constants/constants";
|
||||
import { inputHandlerEventType, inputStateType } from "../../types/components";
|
||||
import { alertContext } from "../../contexts/alertContext";
|
||||
import { Link } from "react-router-dom";
|
||||
import InputComponent from "../../components/inputComponent";
|
||||
|
||||
export default function SignUp(): JSX.Element {
|
||||
const [inputState, setInputState] = useState<inputStateType>(CONTROL_INPUT_STATE);
|
||||
let errClasses = {
|
||||
email: false,
|
||||
password: false,
|
||||
cnfPassword: false,
|
||||
username: false,
|
||||
};
|
||||
|
||||
const {
|
||||
setErrorData,
|
||||
errorOpen,
|
||||
} = useContext(alertContext);
|
||||
|
||||
const { email, password, cnfPassword, username } = inputState;
|
||||
|
||||
function handleInput({ target: { name, value } }: inputHandlerEventType): void {
|
||||
setInputState((prev) => ({ ...prev, [name]: value }));
|
||||
};
|
||||
|
||||
function handleSignUpPass() {
|
||||
if (password !== cnfPassword) {
|
||||
const errorDat = {
|
||||
title: "Passwords are not equal",
|
||||
};
|
||||
return setErrorData(errorDat);
|
||||
}
|
||||
let err = [];
|
||||
Object.keys(inputState)
|
||||
.forEach((key) => {
|
||||
if (inputState[key] === '') {
|
||||
err.push(key);
|
||||
errClasses[key] = true;
|
||||
}
|
||||
});
|
||||
setErrorData({
|
||||
title: "Mandatory fields are empty",
|
||||
list: err,
|
||||
});
|
||||
}
|
||||
return (
|
||||
<div className="flex h-full w-full flex-col items-center justify-center bg-muted">
|
||||
<div className="flex w-72 flex-col items-center justify-center gap-2">
|
||||
<span className="mb-4 text-5xl">⛓️</span>
|
||||
<span className="mb-6 text-2xl font-semibold text-primary">
|
||||
Sign up to LangFlow
|
||||
</span>
|
||||
<div className="flex w-full items-center justify-center gap-2">
|
||||
<Button variant="primary" className="w-full py-6">
|
||||
<FaApple className="h-6 w-6" />
|
||||
</Button>
|
||||
<Button variant="primary" className="w-full py-6">
|
||||
<FaGithub className="h-6 w-6" />
|
||||
</Button>
|
||||
<Button variant="primary" className="w-full py-6">
|
||||
<div className="h-6 w-6">
|
||||
<GoogleIcon />
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
<span className="text-sm text-muted-foreground">or</span>
|
||||
<Input
|
||||
className={errClasses.email ? "border-destructive" : "" + " bg-background"}
|
||||
placeholder="Email address"
|
||||
name="email"
|
||||
value={email}
|
||||
onChange={handleInput}
|
||||
type="text"
|
||||
/>
|
||||
<InputComponent
|
||||
value={password}
|
||||
onChange={(value) => handleInput({ target: { name: 'password', value } })}
|
||||
password={true}
|
||||
placeholder="Password"
|
||||
/>
|
||||
<InputComponent
|
||||
value={cnfPassword}
|
||||
onChange={(value) => handleInput({ target: { name: 'cnfPassword', value } })}
|
||||
password={true}
|
||||
placeholder="Confirm your password"
|
||||
/>
|
||||
<Input
|
||||
className="bg-background"
|
||||
placeholder="Username"
|
||||
name="username"
|
||||
value={username}
|
||||
onChange={handleInput}
|
||||
type="text"
|
||||
/>
|
||||
<Button
|
||||
variant="default"
|
||||
className="w-full"
|
||||
onClick={() => {
|
||||
handleSignUpPass();
|
||||
}}
|
||||
>
|
||||
Sign up
|
||||
</Button>
|
||||
<Link to="/login" className="mt-6 w-full">
|
||||
<Button variant="outline" className="mt-6 w-full">
|
||||
Already have an account? <b>Sign in</b>
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import FlowPage from "./pages/FlowPage";
|
|||
import HomePage from "./pages/MainPage";
|
||||
import DeleteAccountPage from "./pages/deleteAccountPage";
|
||||
import LoginPage from "./pages/loginPage";
|
||||
import SignUp from "./pages/signUpPage";
|
||||
|
||||
const Router = () => {
|
||||
return (
|
||||
|
|
@ -15,6 +16,7 @@ const Router = () => {
|
|||
</Route>
|
||||
<Route path="*" element={<HomePage />} />
|
||||
<Route path="/login" element={<LoginPage />} />
|
||||
<Route path="/signup" element={<SignUp/>} />
|
||||
<Route path="/account">
|
||||
<Route path="delete" element={<DeleteAccountPage />}></Route>
|
||||
</Route>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export type InputComponentType = {
|
|||
editNode?: boolean;
|
||||
onChangePass?: (value: boolean | boolean) => void;
|
||||
showPass?: boolean;
|
||||
placeholder?: string;
|
||||
};
|
||||
export type ToggleComponentType = {
|
||||
enabled: boolean;
|
||||
|
|
@ -81,13 +82,13 @@ export type DisclosureComponentType = {
|
|||
children: ReactNode;
|
||||
openDisc: boolean;
|
||||
button: {
|
||||
title: string;
|
||||
Icon: any;
|
||||
buttons?: {
|
||||
Icon: ReactElement;
|
||||
title: string;
|
||||
onClick: (event?: React.MouseEvent) => void;
|
||||
}[];
|
||||
title: string;
|
||||
Icon: any;
|
||||
buttons?: {
|
||||
Icon: ReactElement;
|
||||
title: string;
|
||||
onClick: (event?: React.MouseEvent) => void;
|
||||
}[];
|
||||
};
|
||||
};
|
||||
export type FloatComponentType = {
|
||||
|
|
@ -101,18 +102,18 @@ export type TooltipComponentType = {
|
|||
children: ReactElement;
|
||||
title: string | ReactElement;
|
||||
placement?:
|
||||
| "bottom-end"
|
||||
| "bottom-start"
|
||||
| "bottom"
|
||||
| "left-end"
|
||||
| "left-start"
|
||||
| "left"
|
||||
| "right-end"
|
||||
| "right-start"
|
||||
| "right"
|
||||
| "top-end"
|
||||
| "top-start"
|
||||
| "top";
|
||||
| "bottom-end"
|
||||
| "bottom-start"
|
||||
| "bottom"
|
||||
| "left-end"
|
||||
| "left-start"
|
||||
| "left"
|
||||
| "right-end"
|
||||
| "right-start"
|
||||
| "right"
|
||||
| "top-end"
|
||||
| "top-start"
|
||||
| "top";
|
||||
};
|
||||
|
||||
export type ProgressBarType = {
|
||||
|
|
@ -171,3 +172,17 @@ export type IconComponentProps = {
|
|||
export interface languageMap {
|
||||
[key: string]: string | undefined;
|
||||
}
|
||||
|
||||
export type inputStateType = {
|
||||
email: string;
|
||||
password: string;
|
||||
cnfPassword: string;
|
||||
username: string;
|
||||
};
|
||||
|
||||
export type inputHandlerEventType = {
|
||||
target: {
|
||||
value: string;
|
||||
name: string;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue