96 lines
3.7 KiB
TypeScript
96 lines
3.7 KiB
TypeScript
import { Box, Button, Heading, Input, Stack, Image, Text } from "@chakra-ui/react";
|
|
import { Policy } from "@lib/Policies";
|
|
import { Resource } from "@lib/vix/AppResources";
|
|
import { SyntheticEvent, useState } from "react";
|
|
import { toast } from "react-toastify";
|
|
import { useAuth } from "@src/ctx/AuthContext";
|
|
import { Links, rootLink, useAutoRedirect } from "@src/util/links";
|
|
import { ClientError } from "@dunemask/vix/bridge";
|
|
import { AuthErrors } from "@lib/vix/ClientErrors";
|
|
import { PasswordInput } from "@src/components/common/Inputs";
|
|
import { ResourcePolicyType } from "@dunemask/vix/util";
|
|
import { postProjectAuthLogin } from "@src/util/api/GeneratedRequests";
|
|
import { Navigate, useSearchParams } from "react-router-dom";
|
|
import { useProjectContext } from "@src/ctx/ProjectContext";
|
|
|
|
export default function AuthenticateView() {
|
|
const { auth, login } = useAuth();
|
|
const { projectId } = useProjectContext();
|
|
const autoRedirect = useAutoRedirect();
|
|
const [search] = useSearchParams();
|
|
const [identity, setIdentity] = useState<string>("");
|
|
const [password, setPassword] = useState<string>("");
|
|
|
|
const identityChange = (e: SyntheticEvent) => setIdentity((e.target as HTMLInputElement).value);
|
|
|
|
function submitCredentials() {
|
|
const loginPromise = postProjectAuthLogin(projectId, { identity: identity, password }).then(async (creds) => {
|
|
if (!creds.token) return toast.error("Server didn't provide token!");
|
|
await login(
|
|
creds.user,
|
|
creds.token,
|
|
Policy.parseResourcePolicies<Resource>(creds.policies as ResourcePolicyType<Resource>[]),
|
|
);
|
|
autoRedirect();
|
|
});
|
|
toast.promise(loginPromise, {
|
|
pending: "Logging in",
|
|
success: "Logged in successfully!",
|
|
error: {
|
|
render({ data }) {
|
|
const clientError = data as ClientError;
|
|
if (clientError.isError(AuthErrors.UnauthorizedRequest)) return "Incorrect credentials!";
|
|
console.error(data);
|
|
return "Error logging in!";
|
|
},
|
|
},
|
|
});
|
|
setPassword("");
|
|
}
|
|
|
|
function detectEnter(e: KeyboardEvent) {
|
|
if (e.key === "Enter") submitCredentials();
|
|
}
|
|
|
|
if (auth) return <Navigate to={rootLink(Links.AutoRedirect)} />;
|
|
return (
|
|
<Box width="100%" height="90vh" display="flex" alignItems="center" justifyContent="center">
|
|
<Box p="2rem" width="100%" maxWidth="350px" boxShadow="md" borderRadius="md" bg="background.paper">
|
|
<Stack spacing="4" align="center" w="100%">
|
|
<Stack spacing="2" textAlign="center" w="100%">
|
|
<Heading size="md" display="flex" alignItems="center">
|
|
Sign in
|
|
<Image src={`${import.meta.env.BASE_URL}icons/android-chrome-512x512.png`} boxSize="24px" ml="1rem" alt="Logo" />
|
|
</Heading>
|
|
<Text fontSize="sm" w="100%" textAlign="left">
|
|
Please enter your credentials below
|
|
</Text>
|
|
</Stack>
|
|
<Stack spacing="4" w="100%">
|
|
<Input
|
|
value={identity}
|
|
placeholder="Identity"
|
|
onChange={identityChange}
|
|
isRequired
|
|
autoFocus
|
|
width="100%"
|
|
borderColor="primary"
|
|
/>
|
|
<PasswordInput value={password} setPassword={setPassword} isRequired />
|
|
</Stack>
|
|
<Stack direction="row" spacing="4" mt="4" justifyContent="space-between" w="100%">
|
|
<Button
|
|
onClick={submitCredentials}
|
|
variant="outline"
|
|
colorScheme="primary"
|
|
ml="auto"
|
|
isDisabled={!identity || !password}
|
|
>
|
|
Sign in
|
|
</Button>
|
|
</Stack>
|
|
</Stack>
|
|
</Box>
|
|
</Box>
|
|
);
|
|
}
|