add login
This commit is contained in:
parent
d86738dccf
commit
3e810c80e9
@ -1,13 +1,16 @@
|
||||
import React from "preact/compat";
|
||||
import { useState } from "preact/hooks";
|
||||
import './style.css';
|
||||
import { useSelector } from "react-redux";
|
||||
import { UserRootState } from "../../store/type";
|
||||
|
||||
|
||||
function Header() {
|
||||
|
||||
const [searchVal, setSearchVal] = useState('');
|
||||
const [dropdown, setDropdown] = useState(false);
|
||||
|
||||
const user = useSelector((state: UserRootState) => state.auth)
|
||||
|
||||
const onInput = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
const val = e.target as HTMLInputElement;
|
||||
setSearchVal(val.value)
|
||||
@ -33,18 +36,25 @@ function Header() {
|
||||
<a href={"/"}>
|
||||
<h1 className={`title ${dropdown ? 'title-dropdown' : ""}`}>Hilingin</h1>
|
||||
</a>
|
||||
<form onSubmit={onSearchSubmit} className={`search-input ${dropdown ? "search-input-dropdown" : ""}`}>
|
||||
<label>
|
||||
<input
|
||||
type="text"
|
||||
value={searchVal}
|
||||
onInput={onInput}
|
||||
placeholder="Yogyakarta, Pantai Cidaun ..."
|
||||
class="text-input-search"
|
||||
/>
|
||||
</label>
|
||||
</form>
|
||||
<button onClick={onDropdown} className="dropdown-menu bg-secondary" style={{ padding: 5, margin: 'auto 0', borderRadius: 10, marginLeft: 'auto' }}>
|
||||
<div className={'user-img self-center mr-5'} style={dropdown ? { display: 'none'} : ''}>
|
||||
<img
|
||||
loading={'lazy'}
|
||||
style={{ width: 40, borderRadius: 15 }}
|
||||
src={'https://cdn.discordapp.com/attachments/743422487882104837/1153985664849805392/421-4212617_person-placeholder-image-transparent-hd-png-download.png'}
|
||||
/>
|
||||
</div>
|
||||
<form onSubmit={onSearchSubmit} className={`search-input ${dropdown ? "search-input-dropdown" : ""}`}>
|
||||
<label>
|
||||
<input
|
||||
type="text"
|
||||
value={searchVal}
|
||||
onInput={onInput}
|
||||
placeholder="Yogyakarta, Pantai Cidaun ..."
|
||||
class="text-input-search"
|
||||
/>
|
||||
</label>
|
||||
</form>
|
||||
<button onClick={onDropdown} className={`dropdown-menu bg-secondary ${dropdown ? 'ml-auto' : ''}`} style={{ padding: 5, borderRadius: 10}}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="30" fill="white" viewBox="0 -960 960 960" width="30"><path d="M120-240v-80h720v80H120Zm0-200v-80h720v80H120Zm0-200v-80h720v80H120Z" /></svg>
|
||||
</button>
|
||||
</div>
|
||||
@ -58,7 +68,7 @@ function Header() {
|
||||
<a href="/stories" className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>Stories</a>
|
||||
<a href="/news-events" className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>News / Events</a>
|
||||
<a href="#" className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>Forum</a>
|
||||
<a href="#" className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>Sign in</a>
|
||||
<a href={user.username ? '#' : '/login'} className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>{user.username ? user.username : 'Sign in'}</a>
|
||||
</div>
|
||||
</header>
|
||||
)
|
||||
|
@ -37,6 +37,11 @@
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
div.user-img {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
button.dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
@ -66,9 +71,6 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
label {
|
||||
position: relative;
|
||||
@ -115,3 +117,11 @@ label:before {
|
||||
max-width: '100%';
|
||||
text-align: 'center'; */
|
||||
}
|
||||
|
||||
.search-input {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.user-img {
|
||||
display: none;
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
const BASE_URL = "http://localhost:8888"
|
||||
|
||||
const SIGNUP_URI = `${BASE_URL}/user/signup`
|
||||
const LOGIN_URI = `${BASE_URL}/user/login`
|
||||
|
||||
|
||||
const GET_LIST_LOCATIONS_URI = `${BASE_URL}/locations`;
|
||||
@ -14,6 +15,7 @@ const GET_IMAGES_BY_LOCATION_URI = `${BASE_URL}/images/location`
|
||||
export {
|
||||
BASE_URL,
|
||||
SIGNUP_URI,
|
||||
LOGIN_URI,
|
||||
GET_LIST_RECENT_LOCATIONS_RATING_URI,
|
||||
GET_LIST_TOP_LOCATIONS,
|
||||
GET_LIST_LOCATIONS_URI,
|
||||
|
@ -18,6 +18,13 @@
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
input:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
/* a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
|
4
src/pages/Login/index.css
Normal file
4
src/pages/Login/index.css
Normal file
@ -0,0 +1,4 @@
|
||||
input {
|
||||
padding: 5px;
|
||||
font-size: 14px;
|
||||
}
|
104
src/pages/Login/index.tsx
Normal file
104
src/pages/Login/index.tsx
Normal file
@ -0,0 +1,104 @@
|
||||
import { ChangeEvent, TargetedEvent, useState } from "preact/compat";
|
||||
import { createAccountService, loginService } from "../../services";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { authAdded } from "../../features/auth/authSlice/authSlice";
|
||||
import './index.css';
|
||||
|
||||
function Login() {
|
||||
const dispatch = useDispatch();
|
||||
const [form, setFrom] = useState({
|
||||
username: '',
|
||||
password: ''
|
||||
})
|
||||
|
||||
const [errorMsg, setErrorMsg] = useState([{
|
||||
field: '',
|
||||
msg: ''
|
||||
}])
|
||||
|
||||
const navigation = useNavigate()
|
||||
|
||||
async function handleSignIn(e: TargetedEvent) {
|
||||
e.preventDefault();
|
||||
try {
|
||||
const res = await loginService({username: form.username, password: form.password})
|
||||
if (res.error) {
|
||||
setErrorMsg(res.error.response.data.errors)
|
||||
return
|
||||
}
|
||||
dispatch(authAdded(res.data))
|
||||
// localStorage.setItem("user", JSON.stringify(res.data))
|
||||
navigation("/")
|
||||
} catch(err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSignUp(e: TargetedEvent) {
|
||||
e.preventDefault();
|
||||
try {
|
||||
const res = await createAccountService({
|
||||
username: form.username,
|
||||
password: form.password
|
||||
})
|
||||
|
||||
if(res.error) {
|
||||
setErrorMsg(res.error.response.data.errors)
|
||||
return;
|
||||
}
|
||||
console.log(res.data)
|
||||
} catch (err) {
|
||||
alert(err)
|
||||
}
|
||||
}
|
||||
|
||||
function onChangeInput(e: ChangeEvent<HTMLInputElement>) {
|
||||
const val = e.target as HTMLInputElement;
|
||||
setFrom({ ...form, [val.placeholder]: val.value })
|
||||
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={'p-2'}>
|
||||
<h1 className={'text-2xl mb-2'}>Sign in</h1>
|
||||
<form onSubmit={handleSignIn}>
|
||||
<table style={{ borderSpacing: '0 0.5em', borderCollapse: 'separate' }}>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>username: </td>
|
||||
<td><input value={form.username} onChange={onChangeInput} placeholder={'username'} className={'bg-secondary'} /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>password: </td>
|
||||
<td><input value={form.password} onChange={onChangeInput} type={'password'} placeholder={'password'} className={'bg-secondary'} /></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<a className={'block'}>Forgout account ?</a>
|
||||
<input type={'submit'} value={'sign in'} className={'p-1 text-sm text-primary mt-4'} style={{ backgroundColor: '#a8adb3', borderRadius: 7 }} />
|
||||
</form>
|
||||
<h1 className={'text-2xl mt-10'}>Create Account</h1>
|
||||
<form onSubmit={handleSignUp} >
|
||||
<table style={{ borderSpacing: '0 0.5em', borderCollapse: 'separate' }}>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>username: </td>
|
||||
<td><input value={form.username} onChange={onChangeInput} placeholder={'username'} className={'bg-secondary'} /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>password: </td>
|
||||
<td><input value={form.password} onChange={onChangeInput} type={'password'} placeholder={'password'} className={'bg-secondary'} /></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{errorMsg.map(x => (
|
||||
<p>{x.msg}</p>
|
||||
))}
|
||||
<input type={'submit'} value={'create account'} className={'p-1 text-sm text-primary mt-4'} style={{ backgroundColor: '#a8adb3', borderRadius: 7 }} />
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Login;
|
@ -4,8 +4,11 @@ import Discovery from "./Discovery";
|
||||
import Story from "./Stories";
|
||||
import NewsEvent from "./NewsEvents";
|
||||
import LocationDetail from "./LocationDetail";
|
||||
import Login from './Login';
|
||||
|
||||
export {
|
||||
Login,
|
||||
|
||||
Home,
|
||||
|
||||
BestLocation,
|
||||
|
47
src/services/auth.ts
Normal file
47
src/services/auth.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { AxiosError } from "axios";
|
||||
import { LOGIN_URI, SIGNUP_URI } from "../constants/api";
|
||||
import { client } from "./config";
|
||||
|
||||
const initialState: IEmptyResponseState = {
|
||||
data: null,
|
||||
error: AxiosError
|
||||
}
|
||||
|
||||
interface IAuthentication {
|
||||
username: String
|
||||
password: String
|
||||
}
|
||||
|
||||
async function createAccountService({ username, password }: IAuthentication) {
|
||||
const newState = { ...initialState };
|
||||
const url = `${SIGNUP_URI}`
|
||||
try {
|
||||
const response = await client({ method: 'POST', url: url, data: { username, password } })
|
||||
newState.data = response.data
|
||||
newState.error = null
|
||||
return newState
|
||||
} catch (error) {
|
||||
newState.error = error
|
||||
return newState
|
||||
}
|
||||
}
|
||||
|
||||
async function loginService({ username, password }: IAuthentication) {
|
||||
const newState = { ...initialState };
|
||||
const url = `${LOGIN_URI}`
|
||||
try {
|
||||
const response = await client({ method: 'POST', url: url, data: { username, password } })
|
||||
newState.data = response.data
|
||||
newState.error = null
|
||||
return newState
|
||||
} catch (error) {
|
||||
newState.error = error
|
||||
return newState
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export {
|
||||
loginService,
|
||||
createAccountService
|
||||
};
|
@ -7,8 +7,12 @@ import {
|
||||
} from "./locations";
|
||||
|
||||
import { getImagesByLocationService } from "./images"
|
||||
import { createAccountService, loginService } from "./auth";
|
||||
|
||||
export {
|
||||
createAccountService,
|
||||
loginService,
|
||||
|
||||
getListLocationsService,
|
||||
getListRecentLocationsRatingsService,
|
||||
getListTopLocationsService,
|
||||
|
@ -5,3 +5,9 @@ interface GetRequestPagination {
|
||||
page: number,
|
||||
page_size: number,
|
||||
}
|
||||
|
||||
|
||||
interface IEmptyResponseState {
|
||||
data: unknown,
|
||||
error: any,
|
||||
};
|
Loading…
Reference in New Issue
Block a user