Skip to content

Commit 60b1da3

Browse files
authored
Merge pull request #69 from chingu-voyages/task/issue-31/login-signup-pages
This change adds Login and Signup pages along with supporting components
2 parents fed965c + 2876fbc commit 60b1da3

File tree

13 files changed

+514
-4
lines changed

13 files changed

+514
-4
lines changed

pettopia-frontend/src/App.jsx

+17-4
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,32 @@ import NavBar from './components/navigation/NavBar';
33
import HomePage from './pages/HomePage/HomePage';
44
import SearchPage from './pages/SearchPage/MainContent/SearchPage';
55
import ProductDetail from './pages/ProductPage/ProductDetail';
6+
import CartPage from './pages/CartPage';
7+
import AppContext from './AppContext';
8+
import LoginPage from './pages/LoginPage'
9+
import SignUpPage from './pages/SignUpPage'
610

711
function App() {
12+
const cartId = '6424c6249193db4836879fe6';
813
return (
9-
<BrowserRouter>
10-
<NavBar />
11-
<div className='container z-0'>
14+
<AppContext.Provider value={{
15+
cartId
16+
}}>
17+
<BrowserRouter>
18+
<NavBar />
19+
<div className='container z-0'>
1220
<Routes>
1321
<Route path='/' element={<HomePage />} />
1422
<Route path='/search' element={<SearchPage />} />
23+
<Route path='/cart' element={<CartPage />} />
24+
<Route path='/login' element={<LoginPage />} />
25+
<Route path='/signup' element={<SignUpPage />} />
1526
<Route path='/product_for_now' element={<ProductDetail />} />
1627
</Routes>
17-
</div>
28+
</div>
1829
</BrowserRouter>
30+
</AppContext.Provider>
31+
1932
);
2033
}
2134

pettopia-frontend/src/AppContext.jsx

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { createContext } from 'react';
2+
const AppContext = createContext(null);
3+
export default AppContext;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
export default function FormAction({
2+
handleSubmit,
3+
type='Button',
4+
action='submit',
5+
text
6+
}){
7+
return(
8+
<>
9+
{
10+
type==='Button' ?
11+
<button
12+
type={action}
13+
className="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-purple-600 hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-500 mt-10"
14+
onSubmit={handleSubmit}
15+
>
16+
17+
{text}
18+
</button>
19+
:
20+
<></>
21+
}
22+
</>
23+
)
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
export default function FormExtra(){
2+
return(
3+
<div className="flex items-center justify-between ">
4+
<div className="flex items-center">
5+
<input
6+
id="remember-me"
7+
name="remember-me"
8+
type="checkbox"
9+
className="h-4 w-4 text-purple-600 focus:ring-purple-500 border-gray-300 rounded"
10+
/>
11+
<label htmlFor="remember-me" className="ml-2 block text-sm text-gray-900">
12+
Remember me
13+
</label>
14+
</div>
15+
16+
<div className="text-sm">
17+
<a href="#" className="font-medium text-purple-600 hover:text-purple-500">
18+
Forgot your password?
19+
</a>
20+
</div>
21+
</div>
22+
23+
)
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import {Link} from 'react-router-dom';
2+
3+
export default function Header({
4+
heading,
5+
paragraph,
6+
linkName,
7+
linkUrl="#"
8+
}){
9+
return(
10+
<div className="mb-10">
11+
<div className="flex justify-center">
12+
<img
13+
alt=""
14+
className="h-14 w-14"
15+
src="https://ik.imagekit.io/pibjyepn7p9/Lilac_Navy_Simple_Line_Business_Logo_CGktk8RHK.png?ik-sdk-version=javascript-1.4.3&updatedAt=1649962071315"/>
16+
</div>
17+
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">
18+
{heading}
19+
</h2>
20+
<p className="mt-2 text-center text-sm text-gray-600 mt-5">
21+
{paragraph} {' '}
22+
<Link to={linkUrl} className="font-medium text-purple-600 hover:text-purple-500">
23+
{linkName}
24+
</Link>
25+
</p>
26+
</div>
27+
)
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
const fixedInputClass="rounded-md appearance-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-purple-500 focus:border-purple-500 focus:z-10 sm:text-sm"
3+
4+
export default function Input({
5+
handleChange,
6+
value,
7+
labelText,
8+
labelFor,
9+
id,
10+
name,
11+
type,
12+
isRequired=false,
13+
placeholder,
14+
customClass
15+
}){
16+
return(
17+
<div className="my-5">
18+
<label htmlFor={labelFor} className="sr-only">
19+
{labelText}
20+
</label>
21+
<input
22+
onChange={handleChange}
23+
value={value}
24+
id={id}
25+
name={name}
26+
type={type}
27+
required={isRequired}
28+
className={fixedInputClass+customClass}
29+
placeholder={placeholder}
30+
/>
31+
</div>
32+
)
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { useState } from 'react';
2+
import { loginFields } from "./constants/formFields";
3+
import FormAction from "./FormAction";
4+
import FormExtra from "./FormExtra";
5+
import Input from "./Input";
6+
7+
const fields=loginFields;
8+
let fieldsState = {};
9+
fields.forEach(field=>fieldsState[field.id]='');
10+
11+
export default function Login(){
12+
const [loginState,setLoginState]=useState(fieldsState);
13+
14+
const handleChange=(e)=>{
15+
setLoginState({...loginState,[e.target.id]:e.target.value})
16+
}
17+
18+
const handleSubmit=(e)=>{
19+
e.preventDefault();
20+
authenticateUser();
21+
}
22+
23+
//Handle Login API Integration here
24+
const authenticateUser = () =>{
25+
26+
27+
// let loginFields={
28+
// email:loginState['email-address'],
29+
// password:loginState['password']
30+
// };
31+
32+
// const endpoint=`https://api.loginradius.com/identity/v2/auth/login?apikey=${apiKey}&apisecret=${apiSecret}`;
33+
// fetch(endpoint,
34+
// {
35+
// method:'POST',
36+
// headers: {
37+
// 'Content-Type': 'application/json'
38+
// },
39+
// body:JSON.stringify(loginFields)
40+
// }).then(response=>response.json())
41+
// .then(data=>{
42+
// //API Success from LoginRadius Login API
43+
// })
44+
// .catch(error=>console.log(error))
45+
}
46+
47+
48+
return(
49+
<form className="mt-8 space-y-6" onSubmit={handleSubmit}>
50+
<div className="-space-y-px">
51+
{
52+
fields.map(field=>
53+
<Input
54+
key={field.id}
55+
handleChange={handleChange}
56+
value={loginState[field.id]}
57+
labelText={field.labelText}
58+
labelFor={field.labelFor}
59+
id={field.id}
60+
name={field.name}
61+
type={field.type}
62+
isRequired={field.isRequired}
63+
placeholder={field.placeholder}
64+
/>
65+
66+
)
67+
}
68+
</div>
69+
70+
<FormExtra/>
71+
<FormAction handleSubmit={handleSubmit} text="Login"/>
72+
73+
</form>
74+
)
75+
}
76+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { useState } from 'react';
2+
import { signupFields } from "./constants/formFields"
3+
import FormAction from "./FormAction";
4+
import Input from "./Input";
5+
6+
const fields=signupFields;
7+
let fieldsState={};
8+
9+
fields.forEach(field => fieldsState[field.id]='');
10+
11+
export default function Signup(){
12+
const [signupState,setSignupState]=useState(fieldsState);
13+
14+
const handleChange=(e)=>setSignupState({...signupState,[e.target.id]:e.target.value});
15+
16+
const handleSubmit=(e)=>{
17+
e.preventDefault();
18+
console.log(signupState)
19+
createAccount()
20+
}
21+
22+
//handle Signup API Integration here
23+
const createAccount=()=>{
24+
25+
}
26+
27+
return(
28+
<form className="mt-8 space-y-6" onSubmit={handleSubmit}>
29+
<div className="">
30+
{
31+
fields.map(field=>
32+
<Input
33+
key={field.id}
34+
handleChange={handleChange}
35+
value={signupState[field.id]}
36+
labelText={field.labelText}
37+
labelFor={field.labelFor}
38+
id={field.id}
39+
name={field.name}
40+
type={field.type}
41+
isRequired={field.isRequired}
42+
placeholder={field.placeholder}
43+
/>
44+
45+
)
46+
}
47+
<FormAction handleSubmit={handleSubmit} text="Signup" />
48+
</div>
49+
50+
51+
52+
</form>
53+
)
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
const loginFields=[
2+
{
3+
labelText:"Email address",
4+
labelFor:"email-address",
5+
id:"email-address",
6+
name:"email",
7+
type:"email",
8+
autoComplete:"email",
9+
isRequired:true,
10+
placeholder:"Email address"
11+
},
12+
{
13+
labelText:"Password",
14+
labelFor:"password",
15+
id:"password",
16+
name:"password",
17+
type:"password",
18+
autoComplete:"current-password",
19+
isRequired:true,
20+
placeholder:"Password"
21+
}
22+
]
23+
24+
const signupFields=[
25+
{
26+
labelText:"Username",
27+
labelFor:"username",
28+
id:"username",
29+
name:"username",
30+
type:"text",
31+
autoComplete:"username",
32+
isRequired:true,
33+
placeholder:"Username"
34+
},
35+
{
36+
labelText:"Email address",
37+
labelFor:"email-address",
38+
id:"email-address",
39+
name:"email",
40+
type:"email",
41+
autoComplete:"email",
42+
isRequired:true,
43+
placeholder:"Email address"
44+
},
45+
{
46+
labelText:"Password",
47+
labelFor:"password",
48+
id:"password",
49+
name:"password",
50+
type:"password",
51+
autoComplete:"current-password",
52+
isRequired:true,
53+
placeholder:"Password"
54+
},
55+
{
56+
labelText:"Confirm Password",
57+
labelFor:"confirm-password",
58+
id:"confirm-password",
59+
name:"confirm-password",
60+
type:"password",
61+
autoComplete:"confirm-password",
62+
isRequired:true,
63+
placeholder:"Confirm Password"
64+
}
65+
]
66+
67+
export {loginFields,signupFields}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default function DeleteIcon (){
2+
return (
3+
<svg class="w-6 h-6 dark:text-black" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01"></path></svg>
4+
)
5+
}

0 commit comments

Comments
 (0)