login register api

dev
Aji Kamaludin 3 years ago
parent bec566d1c8
commit 665aa8efcc
No known key found for this signature in database
GPG Key ID: 670E1F26AD5A8099

@ -0,0 +1,4 @@
{
"singleQuote": true,
"semi": false
}

18
package-lock.json generated

@ -5,6 +5,7 @@
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "react-chakra",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@chakra-ui/icons": "^1.0.15", "@chakra-ui/icons": "^1.0.15",
@ -23,6 +24,7 @@
"@testing-library/jest-dom": "^5.14.1", "@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^11.2.7", "@testing-library/react": "^11.2.7",
"@testing-library/user-event": "^12.8.3", "@testing-library/user-event": "^12.8.3",
"axios": "^0.21.1",
"framer-motion": "^4.1.17", "framer-motion": "^4.1.17",
"is_js": "^0.9.0", "is_js": "^0.9.0",
"react": "^17.0.2", "react": "^17.0.2",
@ -5780,6 +5782,14 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/axios": {
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
"dependencies": {
"follow-redirects": "^1.10.0"
}
},
"node_modules/axobject-query": { "node_modules/axobject-query": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
@ -27579,6 +27589,14 @@
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.2.tgz", "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.2.tgz",
"integrity": "sha512-5LMaDRWm8ZFPAEdzTYmgjjEdj1YnQcpfrVajO/sn/LhbpGp0Y0H64c2hLZI1gRMxfA+w1S71Uc/nHaOXgcCvGg==" "integrity": "sha512-5LMaDRWm8ZFPAEdzTYmgjjEdj1YnQcpfrVajO/sn/LhbpGp0Y0H64c2hLZI1gRMxfA+w1S71Uc/nHaOXgcCvGg=="
}, },
"axios": {
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
"requires": {
"follow-redirects": "^1.10.0"
}
},
"axobject-query": { "axobject-query": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",

@ -1,6 +1,6 @@
{ {
"name": "react-chakra", "name": "react-kasiraja-web",
"version": "0.1.0", "version": "1.0.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@chakra-ui/icons": "^1.0.15", "@chakra-ui/icons": "^1.0.15",
@ -19,6 +19,7 @@
"@testing-library/jest-dom": "^5.14.1", "@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^11.2.7", "@testing-library/react": "^11.2.7",
"@testing-library/user-event": "^12.8.3", "@testing-library/user-event": "^12.8.3",
"axios": "^0.21.1",
"framer-motion": "^4.1.17", "framer-motion": "^4.1.17",
"is_js": "^0.9.0", "is_js": "^0.9.0",
"react": "^17.0.2", "react": "^17.0.2",

@ -11,10 +11,11 @@ import {
} from 'react-router-dom' } from 'react-router-dom'
import "@fontsource/raleway/400.css" import "@fontsource/raleway/400.css"
import "@fontsource/open-sans/700.css" import "@fontsource/open-sans/700.css"
import "./axiosSetup"
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { fas } from '@fortawesome/free-solid-svg-icons' import { fas } from '@fortawesome/free-solid-svg-icons'
import NotFound from "./views/errors/404"
import { AppProvider } from "./context/AppContext" import { AppProvider } from "./context/AppContext"
import NotFound from "./views/errors/404"
import Loading from "./components/Common/Loading" import Loading from "./components/Common/Loading"

@ -2,31 +2,37 @@ export const navs = [
{ {
name: "Dashboard", name: "Dashboard",
to: "/dashboard", to: "/dashboard",
icon: "clipboard-list" icon: "clipboard-list",
role: "admin",
}, },
{ {
name: "Kasir", name: "Kasir",
to: "/sales/create", to: "/sales/create",
icon: "cash-register" icon: "cash-register",
role: "kasir",
}, },
{ {
name: "Penjualan", name: "Penjualan",
to: "/sales", to: "/sales",
icon: "money-bill-wave" icon: "money-bill-wave",
role: "admin",
}, },
{ {
name: "Pembelian", name: "Pembelian",
to: "/purchases", to: "/purchases",
icon: "money-bill-wave" icon: "money-bill-wave",
role: "admin",
}, },
{ {
name: "Kategori", name: "Kategori",
to: "/categories", to: "/categories",
icon: "list" icon: "list",
role: "admin",
}, },
{ {
name: "Produk", name: "Produk",
to: "/products", to: "/products",
icon: "list" icon: "list",
role: "admin",
}, },
] ]

@ -0,0 +1,19 @@
import axios from 'axios'
import { API_URL } from './config'
const id = x => x
axios.defaults.baseURL = API_URL
axios.interceptors.response.use(id, error => {
const { status, data: { message } } = error.response
if (status === 401 && message === 'Unauthenticated.') {
window.localStorage.clear()
window.location.reload()
return
}
// if expired access token lets refresh token
if (status === 403) {
window.alert('Anda tidak mempunyai akses untuk aksi ini')
}
throw error
})

@ -10,7 +10,8 @@ import {
} from '@chakra-ui/react' } from '@chakra-ui/react'
import { ChevronRightIcon } from '@chakra-ui/icons' import { ChevronRightIcon } from '@chakra-ui/icons'
const Header = ({ showSidebarButton = true, onShowSidebar, onLogout }) => { const Header = ({ showSidebarButton = true, onShowSidebar, onLogout, user }) => {
return ( return (
<Flex bg="red" p={2} color="white" justifyContent="end"> <Flex bg="red" p={2} color="white" justifyContent="end">
<Box flex="1"> <Box flex="1">
@ -28,10 +29,10 @@ const Header = ({ showSidebarButton = true, onShowSidebar, onLogout }) => {
<MenuButton <MenuButton
_expanded={{ bg: "transparent" }} _expanded={{ bg: "transparent" }}
> >
<Avatar name="Admin" /> <Avatar name={user?.name} />
</MenuButton> </MenuButton>
<MenuList> <MenuList>
<MenuItem color="blackAlpha.900">User: Admin</MenuItem> <MenuItem color="blackAlpha.900">{user?.name}</MenuItem>
<MenuItem color="blackAlpha.900" onClick={e => onLogout(e)}>Logout</MenuItem> <MenuItem color="blackAlpha.900" onClick={e => onLogout(e)}>Logout</MenuItem>
</MenuList> </MenuList>
</Menu> </Menu>

@ -13,6 +13,7 @@ import {
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { navs } from '../../_nav' import { navs } from '../../_nav'
import { useAuth } from '../../context/AppContext'
const MenuItem = ({ name, icon, onClick }) => { const MenuItem = ({ name, icon, onClick }) => {
@ -28,7 +29,9 @@ const MenuItem = ({ name, icon, onClick }) => {
) )
} }
const SidebarContent = ({ onClick, variant }) => ( const SidebarContent = ({ onClick, variant }) => {
const { user } = useAuth()
return (
<VStack> <VStack>
{variant === 'sidebar' && ( {variant === 'sidebar' && (
<Heading <Heading
@ -39,12 +42,13 @@ const SidebarContent = ({ onClick, variant }) => (
>kasirAja</Heading> >kasirAja</Heading>
)} )}
{navs.map(nav => ( {navs.map(nav => (
<Link to={nav.to} style={{width: "100%"}} key={nav.name}> <Link to={nav.to} style={{width: "100%"}} key={nav.name} hidden={user.role !== nav.role}>
<MenuItem name={nav.name} icon={nav.icon} onClick={onClick}/> <MenuItem name={nav.name} icon={nav.icon} onClick={onClick}/>
</Link> </Link>
))} ))}
</VStack> </VStack>
) )
}
const Sidebar = ({ isOpen, variant, onClose }) => { const Sidebar = ({ isOpen, variant, onClose }) => {
return variant === 'sidebar' ? ( return variant === 'sidebar' ? (

@ -16,7 +16,7 @@ const userManager = {
const AppContext = React.createContext() const AppContext = React.createContext()
function AppProvider(props) { function AppProvider(props) {
const [user, setUser] = useState(userManager.get()) const [user, setUser] = useState(JSON.parse(userManager.get()))
const value = useMemo( const value = useMemo(
() => ({ user, setUser }), () => ({ user, setUser }),
@ -39,7 +39,7 @@ function useAuth() {
return is.not.empty(user) && is.not.null(user) return is.not.empty(user) && is.not.null(user)
} }
const persistUser = user => { const persistUser = user => {
userManager.set(user) userManager.set(JSON.stringify(user))
setUser(user) setUser(user)
} }
const logout = () => { const logout = () => {
@ -48,6 +48,7 @@ function useAuth() {
} }
return { return {
user,
isLoggedIn, isLoggedIn,
persistUser, persistUser,
logout logout

@ -1,4 +1,4 @@
import { useState, Suspense } from "react"; import { useEffect, useState, Suspense } from "react";
import { Switch, Route, Redirect } from 'react-router-dom' import { Switch, Route, Redirect } from 'react-router-dom'
import { import {
Container, Container,
@ -19,7 +19,7 @@ const smVariant = { navigation: 'drawer', navigationButton: true }
const mdVariant = { navigation: 'sidebar', navigationButton: false } const mdVariant = { navigation: 'sidebar', navigationButton: false }
export default function DashboardLayout(props) { export default function DashboardLayout(props) {
const { loading, isLoggedIn, logout } = useAuth() const { loading, isLoggedIn, logout, user } = useAuth()
const { history } = props; const { history } = props;
@ -29,15 +29,18 @@ export default function DashboardLayout(props) {
history.push('/login') history.push('/login')
} }
if(!isLoggedIn()){
history.push('/login');
}
const [isSidebarOpen, setSidebarOpen] = useState(false) const [isSidebarOpen, setSidebarOpen] = useState(false)
const variants = useBreakpointValue({ base: smVariant, md: mdVariant }) const variants = useBreakpointValue({ base: smVariant, md: mdVariant })
const toggleSidebar = () => setSidebarOpen(!isSidebarOpen) const toggleSidebar = () => setSidebarOpen(!isSidebarOpen)
useEffect(() => {
const { history } = props;
if(!isLoggedIn()){
history.push('/login');
}
})
if(loading) { if(loading) {
return <Loading/> return <Loading/>
} }
@ -50,8 +53,9 @@ export default function DashboardLayout(props) {
showSidebarButton={variants?.navigationButton} showSidebarButton={variants?.navigationButton}
onShowSidebar={toggleSidebar} onShowSidebar={toggleSidebar}
onLogout={handleLogout} onLogout={handleLogout}
user={user}
/> />
<Container maxW="container.xl" pt="10"> <Container maxW="105rem" pt="10">
{/* Content */} {/* Content */}
<Suspense fallback={<Loading/>}> <Suspense fallback={<Loading/>}>
<Switch> <Switch>

@ -0,0 +1,19 @@
import axios from 'axios'
export function login(payload) {
const { email, password } = payload
return axios({
method: 'POST',
url: '/authentications',
data: { email, password }
}).then(response => response.data)
}
export function register(payload) {
const { name, email, password } = payload
return axios({
method: 'POST',
url: '/registration',
data: { name, email, password }
}).then(res => res.data)
}

@ -7,13 +7,40 @@ import {
FormLabel, FormLabel,
Input, Input,
Button, Button,
Alert,
AlertIcon,
} from "@chakra-ui/react" } from "@chakra-ui/react"
import { useEffect } from "react" import { useEffect, useState } from "react"
import { Link } from "react-router-dom" import { Link } from "react-router-dom"
import { useAuth } from "../../context/AppContext" import { useAuth } from "../../context/AppContext"
import { login } from './Api'
export default function Login(props) { export default function Login(props) {
const { isLoggedIn } = useAuth() const { isLoggedIn, persistUser } = useAuth()
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [errors, setErrors] = useState([])
const [submit, setSubmit] = useState(false);
const handleSubmit = (e) => {
e.preventDefault()
setSubmit(true)
login({ email, password })
.then(res => {
const { data } = res
persistUser({
...data.user,
accessToken: data.accessToken,
refreshToken: data.refreshToken,
})
})
.catch(err => {
setErrors(err.response.data)
})
.finally(() => setSubmit(false))
}
useEffect(() => { useEffect(() => {
const { history } = props const { history } = props
@ -36,13 +63,33 @@ export default function Login(props) {
</Box> </Box>
<Box flexShrink="0" shadow="lg" p="8" maxW="96" w="full" bg="white" rounded="lg"> <Box flexShrink="0" shadow="lg" p="8" maxW="96" w="full" bg="white" rounded="lg">
<Box rounded="lg" > <Box rounded="lg" >
{errors.message?.length > 0 && (
<Alert status="error" mb="5" rounded="md">
<AlertIcon />
{errors.message}
</Alert>
)}
<FormControl id="email" pb="2"> <FormControl id="email" pb="2">
<FormLabel mb="1">Email</FormLabel> <FormLabel mb="1">Email</FormLabel>
<Input focusBorderColor="red.500" type="email" placeholder="email"/> <Input
focusBorderColor="red.500"
type="email"
placeholder="email"
value={email}
onChange={(e) => {
setEmail(e.target.value)
}}
/>
</FormControl> </FormControl>
<FormControl id="password" pb="4"> <FormControl id="password" pb="4">
<FormLabel mb="1">Password</FormLabel> <FormLabel mb="1">Password</FormLabel>
<Input focusBorderColor="red.500" type="password" placeholder="password" /> <Input
focusBorderColor="red.500"
type="password"
placeholder="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</FormControl> </FormControl>
<Box mt={5} mb="1" ml="1" fontSize="sm"> <Box mt={5} mb="1" ml="1" fontSize="sm">
<Link to="/register"> <Link to="/register">
@ -53,6 +100,8 @@ export default function Login(props) {
p={6} p={6}
w="100%" w="100%"
type="submit" type="submit"
disabled={submit}
onClick={(e) => handleSubmit(e)}
> >
Login Login
</Button> </Button>

@ -7,14 +7,55 @@ import {
FormLabel, FormLabel,
Input, Input,
Button, Button,
Alert,
AlertIcon,
InputGroup,
InputRightElement,
useToast,
} from "@chakra-ui/react" } from "@chakra-ui/react"
import { useEffect } from "react" import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { useEffect, useState } from "react"
import { Link } from "react-router-dom" import { Link } from "react-router-dom"
import { useAuth } from "../../context/AppContext" import { useAuth } from "../../context/AppContext"
import { register } from "./Api"
export default function Register(props) { export default function RegisterPage(props) {
const { history } = props
const { isLoggedIn } = useAuth() const { isLoggedIn } = useAuth()
const toast = useToast()
const [name, setName] = useState('')
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [errors, setErrors] = useState([])
const [submit, setSubmit] = useState(false)
const [show, setShow] = useState(false)
const handleClick = (e) => { setShow(!show) }
const handleSubmit = (e) => {
e.preventDefault()
setSubmit(true)
register({ name, email, password })
.then((res) => {
setErrors([])
toast({
title: res.message,
description: "anda dapat menggunakan login sekarang",
type: "info",
position: "top-right"
})
history.push('/login')
})
.catch((err) => {
setErrors(err.response.data)
})
.finally(() => setSubmit(false))
}
useEffect(() => { useEffect(() => {
const { history } = props const { history } = props
if (isLoggedIn()) { if (isLoggedIn()) {
@ -36,17 +77,50 @@ export default function Register(props) {
</Box> </Box>
<Box flexShrink="0" shadow="lg" p="8" maxW="96" w="full" bg="white" rounded="lg"> <Box flexShrink="0" shadow="lg" p="8" maxW="96" w="full" bg="white" rounded="lg">
<Box rounded="lg" > <Box rounded="lg" >
{errors.message?.length > 0 && (
<Alert status="error" mb="5" rounded="md">
<AlertIcon />
{errors.message}
</Alert>
)}
<FormControl id="name" pb="2"> <FormControl id="name" pb="2">
<FormLabel mb="1">Nama Toko</FormLabel> <FormLabel mb="1">Nama Toko</FormLabel>
<Input focusBorderColor="red.500" type="text" placeholder="nama toko"/> <Input
focusBorderColor="red.500"
type="text"
placeholder="nama toko"
value={name}
onChange={e => setName(e.target.value)}
/>
</FormControl> </FormControl>
<FormControl id="email" pb="2"> <FormControl id="email" pb="2">
<FormLabel mb="1">Email</FormLabel> <FormLabel mb="1">Email</FormLabel>
<Input focusBorderColor="red.500" type="email" placeholder="email"/> <Input
focusBorderColor="red.500"
type="email"
placeholder="email"
value={email}
onChange={e => setEmail(e.target.value)}
/>
</FormControl> </FormControl>
<FormControl id="password" pb="4"> <FormControl id="password" pb="4">
<FormLabel mb="1">Password</FormLabel> <FormLabel mb="1">Password</FormLabel>
<Input focusBorderColor="red.500" type="password" placeholder="password" /> <InputGroup size="md">
<Input
pr="4.5rem"
type={show ? "text" : "password"}
placeholder="password"
focusBorderColor="red.500"
value={password}
onChange={e => setPassword(e.target.value)}
/>
<InputRightElement width="3.5rem">
<Button h="1.25rem" size="sm" onClick={handleClick} bg="transparent" color="black" _hover={{ bg: "transparent" }} _active={{ bg: "transparent"}}>
{show ? <FontAwesomeIcon icon={"eye"}/> : <FontAwesomeIcon icon={"eye-slash"}/>}
</Button>
</InputRightElement>
</InputGroup>
</FormControl> </FormControl>
<Box mt={5} mb="1" ml="1" fontSize="sm"> <Box mt={5} mb="1" ml="1" fontSize="sm">
<Link to="/login"> <Link to="/login">
@ -57,6 +131,8 @@ export default function Register(props) {
p={6} p={6}
w="100%" w="100%"
type="submit" type="submit"
disabled={submit}
onClick={e => handleSubmit(e)}
> >
Daftar Daftar
</Button> </Button>

@ -1,12 +1,9 @@
import { import {
Button,
Flex, Flex,
Box, Box,
useToast
} from "@chakra-ui/react" } from "@chakra-ui/react"
export default function Dashboard() { export default function Dashboard() {
const toast = useToast()
return ( return (
<Flex direction="column"> <Flex direction="column">
<Flex direction="row" justifyContent="space-between"> <Flex direction="row" justifyContent="space-between">
@ -20,20 +17,6 @@ export default function Dashboard() {
<div> <div>
Dashboard Dashboard
</div> </div>
<Button
onClick={() =>
toast({
title: "Account created.",
description: "We've created your account for you.",
status: "success",
duration: 9000,
isClosable: true,
position: "bottom-right",
})
}
>
Show Toast
</Button>
</Flex> </Flex>
) )
} }
Loading…
Cancel
Save