user management implemented

dev
Aji Kamaludin 3 years ago
parent af40c30c4a
commit 1f062eeca1
No known key found for this signature in database
GPG Key ID: 670E1F26AD5A8099

@ -1,6 +1,17 @@
import useSWR from "swr"
import qs from "query-string"
export function useUsers(user, params) {
const { data, error } = useSWR([
`/users?${qs.stringify(params)}`, user.accessToken
])
return [
data,
error,
]
}
export function useProducts(user, params) {
const { data, error } = useSWR([
`/products?${qs.stringify(params)}`, user.accessToken

@ -1,5 +1,14 @@
import { useEffect, useState } from "react";
import { FormControl, FormLabel, Input, Box, InputGroup, InputRightElement, InputRightAddon } from "@chakra-ui/react";
import {
FormControl,
FormLabel,
Input,
Box,
InputGroup,
InputRightElement,
InputRightAddon,
Button,
} from "@chakra-ui/react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import NumberFormat from "react-number-format";
@ -37,17 +46,27 @@ export function useDebounce(value, delay) {
}
export function FormInput(props) {
const [show, setShow] = useState(false)
const { data: [name, val, setVal = () => {}, type = "text"]} = props
return (
<FormControl id={name} mb="3">
<FormLabel fontWeight="bold">{name}</FormLabel>
<Input
focusBorderColor="red.500"
type={type}
value={val}
onChange={e => setVal(e.target.value)}
{...props}
/>
<InputGroup size="md">
<Input
focusBorderColor="red.500"
type={!show ? type : "text"}
value={val}
onChange={e => setVal(e.target.value)}
{...props}
/>
{type === "password" && (
<InputRightElement width="3.5rem">
<Button h="1.25rem" size="sm" onClick={() => setShow(!show)} bg="transparent" color="black" _hover={{ bg: "transparent" }} _active={{ bg: "transparent"}}>
{show ? <FontAwesomeIcon icon={"eye"}/> : <FontAwesomeIcon icon={"eye-slash"}/>}
</Button>
</InputRightElement>
)}
</InputGroup>
</FormControl>
)
}

@ -9,6 +9,7 @@ import {
MenuButton
} from '@chakra-ui/react'
import { ChevronRightIcon } from '@chakra-ui/icons'
import { Link } from 'react-router-dom'
const Header = ({ showSidebarButton = true, onShowSidebar, onLogout, user }) => {
@ -32,7 +33,8 @@ const Header = ({ showSidebarButton = true, onShowSidebar, onLogout, user }) =>
<Avatar name={user?.name} />
</MenuButton>
<MenuList>
<MenuItem color="blackAlpha.900">{user?.name}</MenuItem>
<MenuItem color="blackAlpha.900">Toko : {user?.company_name}</MenuItem>
<MenuItem as={Link} to={`/users/${user?.id}/edit`} color="blackAlpha.900">{user?.name}</MenuItem>
<MenuItem color="blackAlpha.900" onClick={e => onLogout(e)}>logout</MenuItem>
</MenuList>
</Menu>

@ -1,13 +1,15 @@
import React from "react";
const Dashboard = React.lazy(() => import("../views/dashboard"));
const Product = React.lazy(() => import("../views/products"));
const Categories = React.lazy(() => import("../views/categories"));
import React from "react"
const Dashboard = React.lazy(() => import("../views/dashboard"))
const User = React.lazy(() => import("../views/users"))
const Product = React.lazy(() => import("../views/products"))
const Categories = React.lazy(() => import("../views/categories"))
const routes = [
{ path: '/', exact: true, name: 'Home' },
{ path: "/dashboard", name: "dashboard", component: Dashboard },
{ path: "/products", name: "produk", component: Product },
{ path: "/categories", name: "kategori", component: Categories }
{ path: "/categories", name: "kategori", component: Categories },
{ path: "/users", name: "pengguna", component: User },
]
export default routes;

@ -1,32 +1,54 @@
import {
Flex, Stat, StatLabel, StatNumber, StatHelpText, StatArrow
} from "@chakra-ui/react"
import { useEffect } from "react"
import Card from "../../components/Common/Card"
import { useAuth } from "../../context/AppContext"
export default function Dashboard(props) {
const { user } = useAuth()
useEffect(() => {
const { role } = user
if(role === "kasir") {
props.history.push("/sales/create")
}
return () => {}
}, [user, props])
export default function Dashboard() {
return (
<Flex direction="column">
<Flex flexShrink="revert" direction="row" justifyContent="flex-start">
<Card>
<Stat>
<StatLabel>penjualan</StatLabel>
<StatNumber>345.670</StatNumber>
<StatHelpText>
<StatArrow type="increase" />
23.36% from yesterday
</StatHelpText>
</Stat>
</Card>
<Card>
<Stat>
<StatLabel>pembelian</StatLabel>
<StatNumber>145.670</StatNumber>
<StatHelpText>
<StatArrow type="decrease" />
3.36% from yesterday
</StatHelpText>
<StatLabel>{user.name}</StatLabel>
<StatNumber>hai</StatNumber>
</Stat>
</Card>
{user.role === "admin" && (
<>
<Card>
<Stat>
<StatLabel>penjualan</StatLabel>
<StatNumber>345.670</StatNumber>
<StatHelpText>
<StatArrow type="increase" />
23.36% from yesterday
</StatHelpText>
</Stat>
</Card>
<Card>
<Stat>
<StatLabel>pembelian</StatLabel>
<StatNumber>145.670</StatNumber>
<StatHelpText>
<StatArrow type="decrease" />
3.36% from yesterday
</StatHelpText>
</Stat>
</Card>
</>
)}
</Flex>
</Flex>
)

@ -0,0 +1,59 @@
import axios from "axios";
export function createUser(payload, token) {
return axios({
method: 'POST',
url: '/users',
data: payload,
headers: {
'Authorization': `Bearer ${token}`
}
})
.then(res => res.data)
.catch(err => {
throw err.response.data
})
}
export function getUser(id, token){
return axios({
method: 'GET',
url: `/users/${id}`,
headers: {
'Authorization': `Bearer ${token}`
}
})
.then(res => res.data.data)
.catch(err => {
throw err.response.data
})
}
export function updateUser(id, payload, token) {
return axios({
method: 'PUT',
url: `/users/${id}`,
data: payload,
headers: {
'Authorization': `Bearer ${token}`
}
})
.then(res => res.data)
.catch(err => {
throw err.response.data
})
}
export function deleteUser(id, token) {
return axios({
method: 'DELETE',
url: `/users/${id}`,
headers: {
'Authorization': `Bearer ${token}`
}
})
.then(res => res.data)
.catch(err => {
throw err.response.data
})
}

@ -0,0 +1,68 @@
import {
Button,
Alert,
AlertIcon,
useToast
} from "@chakra-ui/react"
import { createUser } from "./Api"
import { useState } from "react"
import { Breadcrumb, Card, FormInput } from "../../components/Common"
import { useAuth } from "../../context/AppContext"
export default function Create({ history }) {
const { user } = useAuth()
const toast = useToast()
const [name, setName] = useState('')
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [submit, setSubmit] = useState(false)
const [error, setError] = useState(null)
const handleSubmit = () => {
setSubmit(true)
createUser({ name, email, password }, user.accessToken)
.then(res => {
toast({
title: res.status,
description: "item ditambahkan",
status: "success",
duration: 4000,
isClosable: true,
position: "top-right"
})
history.push('/users')
})
.catch(err => {
setError(err.message)
})
.finally(() => {
setSubmit(false)
})
}
return (
<>
<Breadcrumb main={["/users", "pengguna", "baru"]}/>
<Card>
{error !== null && (
<Alert status="error" mb="5" rounded="md">
<AlertIcon />
{error}
</Alert>
)}
<FormInput data={['nama', name, setName]}/>
<FormInput data={['email', email, setEmail]}/>
<FormInput data={['password', password, setPassword, "password"]}/>
<Button
mt="4"
isLoading={submit}
onClick={() => handleSubmit()}
>
simpan
</Button>
</Card>
</>
)
}

@ -0,0 +1,97 @@
import {
Button,
Alert,
AlertIcon,
useToast
} from "@chakra-ui/react"
import { getUser, updateUser } from "./Api"
import { useState } from "react"
import { Breadcrumb, Card, FormInput, Loading } from "../../components/Common"
import { useAuth } from "../../context/AppContext"
import { useEffect } from "react"
export default function Edit(props) {
const id = props.match.params.id
const { user } = useAuth()
const toast = useToast()
const [name, setName] = useState('')
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [loading, setLoading] = useState(false)
const [submit, setSubmit] = useState(false)
const [error, setError] = useState(null)
const handleSubmit = () => {
setSubmit(true)
updateUser(id, {
name,
email,
password
}, user.accessToken)
.then(res => {
toast({
title: res.status,
description: "item diubah",
status: "success",
duration: 4000,
isClosable: true,
position: "top-right"
})
props.history.push('/users')
})
.catch(err => {
setError(err.message)
})
.finally(() => {
setSubmit(false)
})
}
useEffect(() => {
const { accessToken: token } = user
setLoading(true)
getUser(id, token)
.then(res => {
setName(res.user.name)
setEmail(res.user.email)
})
.catch(err => setError(err.message))
.finally(() => setLoading(false))
return () => {}
}, [id, user])
return (
<>
{user.role === "admin" && (
<Breadcrumb main={["/users", "pengguna", "ubah"]}/>
)}
<Card>
{error !== null && (
<Alert status="error" mb="5" rounded="md">
<AlertIcon />
{error}
</Alert>
)}
{loading ? (
<Loading/>
) : (
<>
<FormInput data={['nama', name, setName]}/>
<FormInput data={['email', email, setEmail]}/>
<FormInput data={['password', password, setPassword, "password"]}/>
<Button
mt="4"
isLoading={submit}
onClick={() => handleSubmit()}
>
simpan
</Button>
</>
)}
</Card>
</>
)
}

@ -0,0 +1,141 @@
import { useState } from "react"
import {
Button,
Alert,
AlertIcon,
Table,
Thead,
Tr,
Td,
Th,
Tbody,
Menu,
MenuItem,
MenuButton,
MenuList,
useToast,
} from "@chakra-ui/react"
import { Link } from "react-router-dom"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { mutate } from 'swr'
import qs from "query-string"
import {
Breadcrumb,
Card,
Loading,
Pagination,
useDebounce,
AlertDialog,
SearchInput,
useModalState,
} from "../../components/Common"
import { useUsers } from "../../api"
import { deleteUser } from "./Api"
import { useAuth } from "../../context/AppContext"
export default function List() {
const { user } = useAuth()
const toast = useToast()
const [page, setPage] = useState(1)
const [search, setSearch] = useState('')
const q = useDebounce(search, 600)
const params = { page, q }
const [data, error] = useUsers(user, params)
const [isOpen, toggle, selected] = useModalState(false)
const handleDelete = async () => {
await deleteUser(selected.id, user.accessToken)
.then((res) => {
toast({
title: res.status,
description: "item dihapus",
status: "success",
position: "top-right",
duration: 4000,
isClosable: true
})
mutate([`/users?${qs.stringify(params)}`, user.accessToken])
})
.catch((err) => {
toast({
title: err.status,
description: err.message,
status: "error",
position: "top-right",
duration: 4000,
isClosable: true
})
})
}
if(error) {
return (
<Alert status="error">
<AlertIcon />
{error.message}
</Alert>
)
}
return (
<>
<Breadcrumb main={["/users", "pengguna"]}/>
<Card>
<Button as={Link} to="/users/create" size="md" mb="3">
tambah
</Button>
<SearchInput setter={[search, setSearch]}/>
{data ? (
<>
<Table variant="simple" mt="2" mb="4">
<Thead>
<Tr>
<Th>nama</Th>
<Th>email</Th>
<Th>role</Th>
<Th></Th>
</Tr>
</Thead>
<Tbody>
{data.users.map((auser) => auser.id !== user.id && (
<Tr key={auser.id}>
<Td>{auser.name}</Td>
<Td>{auser.email}</Td>
<Td>{auser.role}</Td>
<Td isNumeric>
<Menu>
<MenuButton as={Button}>
<FontAwesomeIcon icon="ellipsis-v"/>
</MenuButton>
<MenuList>
<MenuItem as={Link} to={`/users/${auser.id}/edit`}>ubah</MenuItem>
<MenuItem
onClick={() => {
toggle(auser)
}}
>
hapus
</MenuItem>
</MenuList>
</Menu>
</Td>
</Tr>
))}
</Tbody>
</Table>
<Pagination page={page} setPage={setPage} totalPages={data.meta.totalPages}/>
</>
) : (
<Loading/>
)}
</Card>
<AlertDialog
isOpen={isOpen}
onClose={handleDelete}
toggle={() => toggle()}
/>
</>
)
}

@ -0,0 +1,17 @@
import { Switch, Route } from 'react-router-dom'
import Create from './Create'
import List from './List'
import Edit from './Edit'
function routes(props) {
return (
<Switch>
<Route path="/users/:id/edit" exect component={Edit} />
<Route path="/users/create" exact component={Create} />
<Route path="/users" exact component={List} />
</Switch>
)
}
export default routes
Loading…
Cancel
Save