@@ -18,6 +18,7 @@ | |||
"@types/node": "^12.20.15", | |||
"@types/react": "^17.0.13", | |||
"@types/react-dom": "^17.0.8", | |||
"axios": "^0.23.0", | |||
"moment": "^2.29.1", | |||
"node-sass": "^6.0.1", | |||
"query-string": "^7.0.1", | |||
@@ -3725,6 +3726,15 @@ | |||
"pretty-format": "^26.0.0" | |||
} | |||
}, | |||
"node_modules/@types/jquery": { | |||
"version": "3.5.8", | |||
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.8.tgz", | |||
"integrity": "sha512-cXk6NwqjDYg+UI9p2l3x0YmPa4m7RrXqmbK4IpVVpRJiYXU/QTo+UZrn54qfE1+9Gao4qpYqUnxm5ZCy2FTXAw==", | |||
"dev": true, | |||
"dependencies": { | |||
"@types/sizzle": "*" | |||
} | |||
}, | |||
"node_modules/@types/json-schema": { | |||
"version": "7.0.7", | |||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", | |||
@@ -3827,6 +3837,12 @@ | |||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.1.tgz", | |||
"integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==" | |||
}, | |||
"node_modules/@types/sizzle": { | |||
"version": "2.3.3", | |||
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", | |||
"integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", | |||
"dev": true | |||
}, | |||
"node_modules/@types/source-list-map": { | |||
"version": "0.1.2", | |||
"resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", | |||
@@ -3850,6 +3866,15 @@ | |||
"@types/jest": "*" | |||
} | |||
}, | |||
"node_modules/@types/toastr": { | |||
"version": "2.1.39", | |||
"resolved": "https://registry.npmjs.org/@types/toastr/-/toastr-2.1.39.tgz", | |||
"integrity": "sha512-jgbMLTjj7dsSY/EYYOoZXhK6OY/bR909Bn6YNnwL3Oq+f0AeFKbYa198XU/6bsmUqqCCWw5VvCi11FDN1/fetw==", | |||
"dev": true, | |||
"dependencies": { | |||
"@types/jquery": "*" | |||
} | |||
}, | |||
"node_modules/@types/uglify-js": { | |||
"version": "3.13.1", | |||
"resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.13.1.tgz", | |||
@@ -4805,6 +4830,14 @@ | |||
"node": ">=4" | |||
} | |||
}, | |||
"node_modules/axios": { | |||
"version": "0.23.0", | |||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.23.0.tgz", | |||
"integrity": "sha512-NmvAE4i0YAv5cKq8zlDoPd1VLKAqX5oLuZKs8xkJa4qi6RGn0uhCYFjWtHHC9EM/MwOwYWOs53W+V0aqEXq1sg==", | |||
"dependencies": { | |||
"follow-redirects": "^1.14.4" | |||
} | |||
}, | |||
"node_modules/axobject-query": { | |||
"version": "2.2.0", | |||
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", | |||
@@ -9432,9 +9465,9 @@ | |||
} | |||
}, | |||
"node_modules/follow-redirects": { | |||
"version": "1.14.1", | |||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", | |||
"integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==", | |||
"version": "1.14.4", | |||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz", | |||
"integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==", | |||
"funding": [ | |||
{ | |||
"type": "individual", | |||
@@ -25798,6 +25831,15 @@ | |||
"pretty-format": "^26.0.0" | |||
} | |||
}, | |||
"@types/jquery": { | |||
"version": "3.5.8", | |||
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.8.tgz", | |||
"integrity": "sha512-cXk6NwqjDYg+UI9p2l3x0YmPa4m7RrXqmbK4IpVVpRJiYXU/QTo+UZrn54qfE1+9Gao4qpYqUnxm5ZCy2FTXAw==", | |||
"dev": true, | |||
"requires": { | |||
"@types/sizzle": "*" | |||
} | |||
}, | |||
"@types/json-schema": { | |||
"version": "7.0.7", | |||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", | |||
@@ -25900,6 +25942,12 @@ | |||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.1.tgz", | |||
"integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==" | |||
}, | |||
"@types/sizzle": { | |||
"version": "2.3.3", | |||
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", | |||
"integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", | |||
"dev": true | |||
}, | |||
"@types/source-list-map": { | |||
"version": "0.1.2", | |||
"resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", | |||
@@ -25923,6 +25971,15 @@ | |||
"@types/jest": "*" | |||
} | |||
}, | |||
"@types/toastr": { | |||
"version": "2.1.39", | |||
"resolved": "https://registry.npmjs.org/@types/toastr/-/toastr-2.1.39.tgz", | |||
"integrity": "sha512-jgbMLTjj7dsSY/EYYOoZXhK6OY/bR909Bn6YNnwL3Oq+f0AeFKbYa198XU/6bsmUqqCCWw5VvCi11FDN1/fetw==", | |||
"dev": true, | |||
"requires": { | |||
"@types/jquery": "*" | |||
} | |||
}, | |||
"@types/uglify-js": { | |||
"version": "3.13.1", | |||
"resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.13.1.tgz", | |||
@@ -26656,6 +26713,14 @@ | |||
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.2.3.tgz", | |||
"integrity": "sha512-pXnVMfJKSIWU2Ml4JHP7pZEPIrgBO1Fd3WGx+fPBsS+KRGhE4vxooD8XBGWbQOIVSZsVK7pUDBBkCicNu80yzQ==" | |||
}, | |||
"axios": { | |||
"version": "0.23.0", | |||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.23.0.tgz", | |||
"integrity": "sha512-NmvAE4i0YAv5cKq8zlDoPd1VLKAqX5oLuZKs8xkJa4qi6RGn0uhCYFjWtHHC9EM/MwOwYWOs53W+V0aqEXq1sg==", | |||
"requires": { | |||
"follow-redirects": "^1.14.4" | |||
} | |||
}, | |||
"axobject-query": { | |||
"version": "2.2.0", | |||
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", | |||
@@ -30298,9 +30363,9 @@ | |||
} | |||
}, | |||
"follow-redirects": { | |||
"version": "1.14.1", | |||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", | |||
"integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" | |||
"version": "1.14.4", | |||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz", | |||
"integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==" | |||
}, | |||
"for-in": { | |||
"version": "1.0.2", | |||
@@ -13,6 +13,7 @@ | |||
"@types/node": "^12.20.15", | |||
"@types/react": "^17.0.13", | |||
"@types/react-dom": "^17.0.8", | |||
"axios": "^0.23.0", | |||
"moment": "^2.29.1", | |||
"node-sass": "^6.0.1", | |||
"query-string": "^7.0.1", | |||
@@ -19,6 +19,9 @@ import { ALL_WORDS } from "./data/all-words"; | |||
import { WordDetails } from "./components/word-details/WordDetails"; | |||
import { Calendar } from "./components/calendar/Calendar"; | |||
import { Login } from "./components/auth/Login"; | |||
import { Signup } from "./components/auth/Signup"; | |||
export const SERVER_URL = 'http://localhost:8001'; | |||
export var userProfileData: IProfile = { | |||
@@ -86,6 +89,7 @@ function App() { | |||
</BrowserRouter> : <BrowserRouter> | |||
<Switch> | |||
<Route path="/login" component={Login} /> | |||
<Route path="/register" component={Signup} /> | |||
<Redirect from="/" to="/login" /> | |||
</Switch> | |||
</BrowserRouter> | |||
@@ -4,12 +4,30 @@ import { ReactComponent as LogoIcon } from '../../assets/icons/anamnesis.svg'; | |||
import { ReactComponent as EyeOffIcon } from '../../assets/icons/eye-off-outline.svg'; | |||
import { ReactComponent as EyeIcon } from '../../assets/icons/eye-outline.svg'; | |||
import { NavLink } from "react-router-dom"; | |||
import axios from 'axios'; | |||
import { SERVER_URL } from "../../App"; | |||
const authenticateCredentials = async (username: string, password: string) => { | |||
return await axios.post(SERVER_URL + '/auth/api-auth/', { | |||
email: username, | |||
password: password | |||
}); | |||
} | |||
export const Login: React.FC = () => { | |||
const [showPassowrd, setShowPassword] = useState<boolean>(true); | |||
const [userName, setUsername] = useState<string>(''); | |||
const [password, setPassword] = useState<string>(''); | |||
function auth() { | |||
authenticateCredentials(userName, password).then((response: any) => { | |||
localStorage.anamnesisToken = response.data.token; | |||
window.location.assign('/home'); | |||
}, () => { | |||
window.alert("Please check your credentials"); | |||
}); | |||
} | |||
return <section className="page"> | |||
<header className={styles.pageHeader}> | |||
<LogoIcon /> | |||
@@ -30,11 +48,11 @@ export const Login: React.FC = () => { | |||
</button> | |||
</div> | |||
<button className={styles.submitButton}> | |||
<button className={styles.submitButton} onClick={() => auth()}> | |||
Knock Knock | |||
</button> | |||
<NavLink className={styles.otherLinks} to="/signup"> Signup? </NavLink> | |||
<NavLink className={styles.otherLinks} to="/register"> Signup? </NavLink> | |||
</section> | |||
@@ -0,0 +1,111 @@ | |||
import React, { useState } from "react"; | |||
import styles from './Auth.module.scss'; | |||
import { ReactComponent as LogoIcon } from '../../assets/icons/anamnesis.svg'; | |||
import { ReactComponent as EyeOffIcon } from '../../assets/icons/eye-off-outline.svg'; | |||
import { ReactComponent as EyeIcon } from '../../assets/icons/eye-outline.svg'; | |||
import { NavLink } from "react-router-dom"; | |||
import axios from 'axios'; | |||
import { SERVER_URL } from "../../App"; | |||
const registerUser = async (name: string, username: string, password: string) => { | |||
return await axios.post(SERVER_URL + '/auth/register/', { | |||
name: name, | |||
email: username, | |||
password: password | |||
}); | |||
} | |||
const requestVerification = async (email: string) => { | |||
return await axios.post(SERVER_URL + '/auth/request-verification/', { | |||
email: email, | |||
}); | |||
} | |||
const verifyUser = async (email: string, otp: string) => { | |||
return await axios.post(SERVER_URL + '/auth/verify-user/', { | |||
email: email, | |||
otp: otp | |||
}); | |||
} | |||
export const Signup: React.FC = () => { | |||
const [showPassowrd, setShowPassword] = useState<boolean>(true); | |||
const [fullName, setFullName] = useState<string>(''); | |||
const [userName, setUsername] = useState<string>(''); | |||
const [password, setPassword] = useState<string>(''); | |||
const [otp, setOtp] = useState<string>(''); | |||
const [viewState, setViewState] = useState<'REGISTER' | 'VERIFY'>('REGISTER'); | |||
function register() { | |||
registerUser(fullName, userName, password).then(() => { | |||
setTimeout(() => { | |||
requestVerification(userName).then(() => { | |||
setViewState('VERIFY'); | |||
}, () => { | |||
window.alert("Couldn't send Verfication request"); | |||
}); | |||
}, 1000); | |||
}, (e) => { | |||
window.alert(e.toString()); | |||
}); | |||
} | |||
function verify() { | |||
verifyUser(userName, otp).then(() => { | |||
window.alert("Verified user!"); | |||
window.location.assign("/login"); | |||
}, () => window.alert("Failed Verification, please try again")) | |||
} | |||
return <section className="page"> | |||
<header className={styles.pageHeader}> | |||
<LogoIcon /> | |||
</header> | |||
{ viewState === 'REGISTER' && <section className={styles.form}> | |||
<div className={styles.inputHolder}> | |||
<input defaultValue={fullName} onInput={(e) => setFullName(e.currentTarget.value)} | |||
type="text" placeholder="Full Name" /> | |||
</div> | |||
<div className={styles.inputHolder}> | |||
<input defaultValue={userName} onInput={(e) => setUsername(e.currentTarget.value)} | |||
type="email" placeholder="Email ID" /> | |||
</div> | |||
<div className={styles.inputHolder}> | |||
<input defaultValue={password} onInput={(e) => setPassword(e.currentTarget.value)} | |||
type={ showPassowrd ? "text" : "password" } placeholder="Password" /> | |||
<button className={styles.rightButton} onClick={() => setShowPassword(!showPassowrd)}> | |||
{ showPassowrd ? <EyeOffIcon /> : <EyeIcon /> } | |||
</button> | |||
</div> | |||
<button className={styles.submitButton} onClick={() => register()}> | |||
Next Step | |||
</button> | |||
<NavLink className={styles.otherLinks} to="/Login"> Login? </NavLink> | |||
</section> } | |||
{ viewState === 'VERIFY' && <section className={styles.form}> | |||
<div className={styles.inputHolder}> | |||
<input defaultValue={otp} onInput={(e) => setOtp(e.currentTarget.value)} | |||
type="tel" placeholder="Enter OTP sent to your Mail ID" /> | |||
</div> | |||
<button className={styles.submitButton} onClick={() => verify()}> | |||
Verify | |||
</button> | |||
</section> } | |||
</section> | |||
}; |