OTPpages
This commit is contained in:
56
src/App.tsx
56
src/App.tsx
@@ -1,24 +1,42 @@
|
||||
import { useContext } from 'react';
|
||||
import { useContext } from "react";
|
||||
import { Route, BrowserRouter as Router, Routes } from "react-router-dom";
|
||||
import GlobalStateContext from './Contexts/GlobalStateContext';
|
||||
import DefaultLayout from './Layouts/DefaultLayout';
|
||||
import Login from './Pages/Login';
|
||||
import { RouteLink } from './Routes/Routes';
|
||||
import GlobalStateContext from "./Contexts/GlobalStateContext";
|
||||
import DefaultLayout from "./Layouts/DefaultLayout";
|
||||
import Login from "./Pages/Login";
|
||||
import { RouteLink } from "./Routes/Routes";
|
||||
import LoginOtp from "./Pages/OnBoarding/LoginOtp";
|
||||
|
||||
function App() {
|
||||
const context = useContext(GlobalStateContext);
|
||||
if (!context) throw new Error('App must be used within a GlobalStateProvider');
|
||||
const { isAuthenticate } = context;
|
||||
function App() {
|
||||
const context = useContext(GlobalStateContext);
|
||||
if (!context)
|
||||
throw new Error("App must be used within a GlobalStateProvider");
|
||||
const { isAuthenticate } = context;
|
||||
|
||||
return (
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route path="/login" element={<Login />} />
|
||||
<Route path="/*" element={isAuthenticate === true ? (<DefaultLayout><Routes>{RouteLink.map(({ path, Component }, index) => (<Route key={index} path={path} element={<Component />} />))}</Routes></DefaultLayout>) : (<Login />)} />
|
||||
<Route path="*" element={<Login />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route path="/login" element={<Login />} />
|
||||
<Route path="/login/login-otp" element={<LoginOtp />} />
|
||||
<Route
|
||||
path="/*"
|
||||
element={
|
||||
isAuthenticate === true ? (
|
||||
<DefaultLayout>
|
||||
<Routes>
|
||||
{RouteLink.map(({ path, Component }, index) => (
|
||||
<Route key={index} path={path} element={<Component />} />
|
||||
))}
|
||||
</Routes>
|
||||
</DefaultLayout>
|
||||
) : (
|
||||
<Login />
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Route path="*" element={<Login />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
||||
@@ -5,7 +5,7 @@ import GlobalStateContext from './GlobalStateContext';
|
||||
|
||||
|
||||
const GlobalStateProvider = ({ children }:{children:ReactNode}) => {
|
||||
const [isAuthenticate, setIsAuthenticate] = useState<boolean>(true);
|
||||
const [isAuthenticate, setIsAuthenticate] = useState<boolean>(false);
|
||||
|
||||
return (
|
||||
<GlobalStateContext.Provider value={{ isAuthenticate, setIsAuthenticate }}>
|
||||
|
||||
132
src/Pages/OnBoarding/LoginOtp.tsx
Normal file
132
src/Pages/OnBoarding/LoginOtp.tsx
Normal file
@@ -0,0 +1,132 @@
|
||||
import { Center, HStack, Image, Input, Text, VStack } from "@chakra-ui/react";
|
||||
import { useContext, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import GlobalStateContext from "../../Contexts/GlobalStateContext";
|
||||
import logo from "../../assets/logo.svg";
|
||||
import uiEdit from "../../assets/icons/edit.png";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import { Field } from "../../components/ui/field";
|
||||
import { Toaster, toaster } from "../../components/ui/toaster";
|
||||
import { PinInput } from "../../components/ui/pin-input";
|
||||
|
||||
interface FormValues {
|
||||
mobileNumber: number;
|
||||
}
|
||||
|
||||
const LoginOtp = () => {
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const context = useContext(GlobalStateContext);
|
||||
if (!context) {
|
||||
throw new Error("App must be used within a GlobalStateProvider");
|
||||
}
|
||||
const { setIsAuthenticate } = context;
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
} = useForm<FormValues>();
|
||||
|
||||
const onSubmit = handleSubmit((data) => {
|
||||
setIsLoading(true);
|
||||
if (data?.mobileNumber === 1234567890) {
|
||||
setTimeout(() => {
|
||||
setIsAuthenticate(true);
|
||||
setIsLoading(false);
|
||||
}, 3000); // 3-second delay
|
||||
} else {
|
||||
toaster.create({
|
||||
title: `Invalid Credentials`,
|
||||
type: "error",
|
||||
});
|
||||
setIsLoading(false);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<VStack w={"100%"} h={"100vh"} bg={"#ffffff"}>
|
||||
<HStack
|
||||
boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}
|
||||
w={"100%"}
|
||||
ps={8}
|
||||
h={"7%"}
|
||||
justifyContent={"flex-start"}
|
||||
>
|
||||
<Image w={50} src={logo} />
|
||||
</HStack>
|
||||
|
||||
<HStack w={"100%"} h={"93%"} p={8} gap={8}>
|
||||
<Center
|
||||
display={{ base: "none", md: "flex" }}
|
||||
bg={"#02A0A033"}
|
||||
w={"50%"}
|
||||
h={"100%"}
|
||||
rounded={"3xl"}
|
||||
>
|
||||
<Image w={250} src={logo} />
|
||||
</Center>
|
||||
|
||||
<Center
|
||||
as={"form"}
|
||||
onSubmit={onSubmit}
|
||||
p={{ base: 4, md: 16 }}
|
||||
w={{ base: "100%", md: "50%" }}
|
||||
h={"100%"}
|
||||
>
|
||||
<VStack gap={2} w={"100%"} alignItems={"center"}>
|
||||
<Text
|
||||
w={"100%"}
|
||||
textAlign={"center"}
|
||||
fontSize={"24px"}
|
||||
fontWeight={"normal"}
|
||||
color={"#313039"}
|
||||
>
|
||||
Enter otp
|
||||
</Text>
|
||||
<Text
|
||||
w={"100%"}
|
||||
textAlign={"center"}
|
||||
fontSize={"sm"}
|
||||
fontWeight={"normal"}
|
||||
color={"#49475A"}
|
||||
>
|
||||
OTP has been send to your E-mail Address
|
||||
</Text>
|
||||
<HStack>
|
||||
<Image src={uiEdit} h="24px" w="24px" />
|
||||
<Text
|
||||
w={"100%"}
|
||||
textAlign={"center"}
|
||||
fontSize={"sm"}
|
||||
fontWeight={"normal"}
|
||||
color={"#49475A"}
|
||||
>
|
||||
9619565889
|
||||
</Text>
|
||||
</HStack>
|
||||
|
||||
<VStack mt={6} gap={4} w={"full"}>
|
||||
<PinInput />
|
||||
<Button
|
||||
loading={isLoading}
|
||||
mt={4}
|
||||
size={"sm"}
|
||||
bg={"#02A0A0"}
|
||||
rounded={"md"}
|
||||
w={"100%"}
|
||||
color={"#ffffff"}
|
||||
type="submit"
|
||||
>
|
||||
Send OTP
|
||||
</Button>
|
||||
|
||||
<Text>Forgot password</Text>
|
||||
</VStack>
|
||||
</VStack>
|
||||
</Center>
|
||||
<Toaster />
|
||||
</HStack>
|
||||
</VStack>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginOtp;
|
||||
BIN
src/assets/icons/edit.png
Normal file
BIN
src/assets/icons/edit.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 667 B |
27
src/components/ui/pin-input.tsx
Normal file
27
src/components/ui/pin-input.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import { PinInput as ChakraPinInput, Group } from "@chakra-ui/react"
|
||||
import * as React from "react"
|
||||
|
||||
export interface PinInputProps extends ChakraPinInput.RootProps {
|
||||
rootRef?: React.Ref<HTMLDivElement>
|
||||
count?: number
|
||||
inputProps?: React.InputHTMLAttributes<HTMLInputElement>
|
||||
attached?: boolean
|
||||
}
|
||||
|
||||
export const PinInput = React.forwardRef<HTMLInputElement, PinInputProps>(
|
||||
function PinInput(props, ref) {
|
||||
const { count = 4, inputProps, rootRef, attached, ...rest } = props
|
||||
return (
|
||||
<ChakraPinInput.Root ref={rootRef} {...rest}>
|
||||
<ChakraPinInput.HiddenInput ref={ref} {...inputProps} />
|
||||
<ChakraPinInput.Control>
|
||||
<Group attached={attached}>
|
||||
{Array.from({ length: count }).map((_, index) => (
|
||||
<ChakraPinInput.Input color="black" key={index} index={index} />
|
||||
))}
|
||||
</Group>
|
||||
</ChakraPinInput.Control>
|
||||
</ChakraPinInput.Root>
|
||||
)
|
||||
},
|
||||
)
|
||||
Reference in New Issue
Block a user