user management implemented
parent
af40c30c4a
commit
1f062eeca1
@ -1,13 +1,15 @@
|
|||||||
import React from "react";
|
import React from "react"
|
||||||
const Dashboard = React.lazy(() => import("../views/dashboard"));
|
const Dashboard = React.lazy(() => import("../views/dashboard"))
|
||||||
const Product = React.lazy(() => import("../views/products"));
|
const User = React.lazy(() => import("../views/users"))
|
||||||
const Categories = React.lazy(() => import("../views/categories"));
|
const Product = React.lazy(() => import("../views/products"))
|
||||||
|
const Categories = React.lazy(() => import("../views/categories"))
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{ path: '/', exact: true, name: 'Home' },
|
{ path: '/', exact: true, name: 'Home' },
|
||||||
{ path: "/dashboard", name: "dashboard", component: Dashboard },
|
{ path: "/dashboard", name: "dashboard", component: Dashboard },
|
||||||
{ path: "/products", name: "produk", component: Product },
|
{ 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;
|
export default routes;
|
@ -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…
Reference in New Issue