diff --git a/src/App.tsx b/src/App.tsx
index d267c41..e7d8b58 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -24,9 +24,11 @@ import {SightList, SightCreate, SightEdit, SightShow} from './pages/sight'
import {StationList, StationCreate, StationEdit, StationShow} from './pages/station'
import {VehicleList, VehicleCreate, VehicleEdit, VehicleShow} from './pages/vehicle'
import {RouteList, RouteCreate, RouteEdit, RouteShow} from './pages/route'
+import {UserList, UserCreate, UserEdit, UserShow} from './pages/user'
-import {CountryIcon, CityIcon, CarrierIcon, MediaIcon, ArticleIcon, SightIcon, StationIcon, VehicleIcon, RouteIcon} from './components/ui/Icons'
+import {CountryIcon, CityIcon, CarrierIcon, MediaIcon, ArticleIcon, SightIcon, StationIcon, VehicleIcon, RouteIcon, UsersIcon} from './components/ui/Icons'
import SidebarTitle from './components/ui/SidebarTitle'
+import {AdminOnly} from './components/AdminOnly'
function App() {
return (
@@ -134,7 +136,6 @@ function App() {
create: '/vehicle/create',
edit: '/vehicle/edit/:id',
show: '/vehicle/show/:id',
- // добавить SHOW для vehicle->routes (https://wn.krbl.ru/vehicle/routes?id=1)
meta: {
canDelete: true,
label: 'Транспорт',
@@ -147,14 +148,24 @@ function App() {
create: '/route/create',
edit: '/route/edit/:id',
show: '/route/show/:id',
- // добавить SHOW для route->station (https://wn.krbl.ru/route/station)
- // добавить SHOW для route->vehicle (https://wn.krbl.ru/route/vehicle)
meta: {
canDelete: true,
label: 'Маршруты',
icon: ,
},
},
+ {
+ name: 'user',
+ list: '/user',
+ create: '/user/create',
+ edit: '/user/edit/:id',
+ show: '/user/show/:id',
+ meta: {
+ canDelete: true,
+ label: 'Пользователи',
+ icon: ,
+ },
+ },
]}
options={{
syncWithLocation: true,
@@ -238,6 +249,41 @@ function App() {
} />
+
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
} />
(token)
+ if (decoded.is_admin) {
+ document.body.classList.add('is-admin')
+ } else {
+ document.body.classList.remove('is-admin')
+ }
return decoded.is_admin ? ['admin'] : ['user']
} catch {
+ document.body.classList.remove('is-admin')
return ['user']
}
},
diff --git a/src/components/ui/Icons.tsx b/src/components/ui/Icons.tsx
index 8c61c98..f2bf143 100644
--- a/src/components/ui/Icons.tsx
+++ b/src/components/ui/Icons.tsx
@@ -8,5 +8,18 @@ import CastleIcon from '@mui/icons-material/Castle'
import HailIcon from '@mui/icons-material/Hail'
import DirectionsBusIcon from '@mui/icons-material/DirectionsBus'
import ForkLeftIcon from '@mui/icons-material/ForkLeft'
+import PeopleAltIcon from '@mui/icons-material/PeopleAlt'
-export {BedtimeIcon as ProjectIcon, PublicIcon as CountryIcon, LocationCityIcon as CityIcon, TramIcon as CarrierIcon, PermMediaIcon as MediaIcon, FeedIcon as ArticleIcon, CastleIcon as SightIcon, HailIcon as StationIcon, DirectionsBusIcon as VehicleIcon, ForkLeftIcon as RouteIcon}
+export {
+ BedtimeIcon as ProjectIcon,
+ PublicIcon as CountryIcon,
+ LocationCityIcon as CityIcon,
+ TramIcon as CarrierIcon,
+ PermMediaIcon as MediaIcon,
+ FeedIcon as ArticleIcon,
+ CastleIcon as SightIcon,
+ HailIcon as StationIcon,
+ DirectionsBusIcon as VehicleIcon,
+ ForkLeftIcon as RouteIcon,
+ PeopleAltIcon as UsersIcon, // users icon
+}
diff --git a/src/locales/ru/translation.json b/src/locales/ru/translation.json
index 1da23c4..f987165 100644
--- a/src/locales/ru/translation.json
+++ b/src/locales/ru/translation.json
@@ -112,5 +112,12 @@
"edit": "Редактировать маршрут",
"show": "Показать маршрут"
}
+ },
+ "user": {
+ "titles": {
+ "create": "Создать пользователя",
+ "edit": "Редактировать пользователя",
+ "show": "Показать пользователя"
+ }
}
}
diff --git a/src/pages/route/create.tsx b/src/pages/route/create.tsx
index dd85235..086a673 100644
--- a/src/pages/route/create.tsx
+++ b/src/pages/route/create.tsx
@@ -70,13 +70,13 @@ export const RouteCreate = () => {
label={'Номер маршрута *'}
name="route_number"
/>
+
field.onChange(e.target.checked)} />} />}
/>
-
(Прямой / Обратный)
diff --git a/src/pages/user/create.tsx b/src/pages/user/create.tsx
new file mode 100644
index 0000000..6a64d78
--- /dev/null
+++ b/src/pages/user/create.tsx
@@ -0,0 +1,68 @@
+import {Box, TextField, FormControlLabel, Checkbox} from '@mui/material'
+import {Create} from '@refinedev/mui'
+import {useForm} from '@refinedev/react-hook-form'
+import {Controller} from 'react-hook-form'
+
+export const UserCreate = () => {
+ const {
+ saveButtonProps,
+ refineCore: {formLoading},
+ register,
+ control,
+ formState: {errors},
+ } = useForm({})
+
+ return (
+
+
+
+
+
+
+
+ field.onChange(e.target.checked)} />} />}
+ />
+
+
+ )
+}
diff --git a/src/pages/user/edit.tsx b/src/pages/user/edit.tsx
new file mode 100644
index 0000000..275d5ec
--- /dev/null
+++ b/src/pages/user/edit.tsx
@@ -0,0 +1,67 @@
+import {Box, TextField, FormControlLabel, Checkbox} from '@mui/material'
+import {Edit} from '@refinedev/mui'
+import {useForm} from '@refinedev/react-hook-form'
+import {Controller} from 'react-hook-form'
+
+export const UserEdit = () => {
+ const {
+ saveButtonProps,
+ register,
+ control,
+ formState: {errors},
+ } = useForm({})
+
+ return (
+
+
+
+
+
+
+
+ field.onChange(e.target.checked)} />} />}
+ />
+
+
+ )
+}
diff --git a/src/pages/user/index.tsx b/src/pages/user/index.tsx
new file mode 100644
index 0000000..0f886cc
--- /dev/null
+++ b/src/pages/user/index.tsx
@@ -0,0 +1,4 @@
+export * from './create'
+export * from './edit'
+export * from './list'
+export * from './show'
diff --git a/src/pages/user/list.tsx b/src/pages/user/list.tsx
new file mode 100644
index 0000000..845879c
--- /dev/null
+++ b/src/pages/user/list.tsx
@@ -0,0 +1,77 @@
+import React from 'react'
+import {type GridColDef} from '@mui/x-data-grid'
+import {DeleteButton, EditButton, List, ShowButton, useDataGrid} from '@refinedev/mui'
+import {CustomDataGrid} from '../../components/CustomDataGrid'
+import {localeText} from '../../locales/ru/localeText'
+import {Typography} from '@mui/material'
+
+export const UserList = () => {
+ const {dataGridProps} = useDataGrid({})
+
+ const columns = React.useMemo(
+ () => [
+ {
+ field: 'id',
+ headerName: 'ID',
+ type: 'number',
+ minWidth: 50,
+ align: 'left',
+ headerAlign: 'left',
+ },
+ {
+ field: 'name',
+ headerName: 'Имя',
+ type: 'string',
+ minWidth: 250,
+ align: 'left',
+ headerAlign: 'left',
+ },
+ {
+ field: 'email',
+ headerName: 'Email',
+ type: 'string',
+ minWidth: 250,
+ align: 'left',
+ headerAlign: 'left',
+ },
+ {
+ field: 'is_admin',
+ headerName: 'Роль',
+ type: 'boolean',
+ align: 'left',
+ headerAlign: 'left',
+ minWidth: 150,
+ flex: 1,
+ // renderCell: ({value}) => ,
+ renderCell: ({value}) => {value ? 'администратор' : 'пользователь'},
+ },
+ {
+ field: 'actions',
+ headerName: 'Действия',
+ minWidth: 120,
+ display: 'flex',
+ align: 'right',
+ headerAlign: 'center',
+ sortable: false,
+ filterable: false,
+ disableColumnMenu: true,
+ renderCell: function render({row}) {
+ return (
+ <>
+
+
+
+ >
+ )
+ },
+ },
+ ],
+ [],
+ )
+
+ return (
+
+ row.id} />
+
+ )
+}
diff --git a/src/pages/user/show.tsx b/src/pages/user/show.tsx
new file mode 100644
index 0000000..f757c5f
--- /dev/null
+++ b/src/pages/user/show.tsx
@@ -0,0 +1,34 @@
+import {Stack, Typography} from '@mui/material'
+import {useShow} from '@refinedev/core'
+import {Show, TextFieldComponent as TextField} from '@refinedev/mui'
+
+export const UserShow = () => {
+ const {query} = useShow({})
+ const {data, isLoading} = query
+ const record = data?.data
+
+ const fields = [
+ {label: 'Имя', data: 'name'},
+ {label: 'Электронная почта', data: 'email'},
+ {
+ label: 'Администратор',
+ data: 'is_admin',
+ render: (value: number[][]) => {value ? 'администратор' : 'пользователь'},
+ },
+ ]
+
+ return (
+
+
+ {fields.map(({label, data, render}) => (
+
+
+ {label}
+
+ {render ? render(record?.[data]) : }
+
+ ))}
+
+
+ )
+}
diff --git a/src/stylesheets/hidden-functionality.css b/src/stylesheets/hidden-functionality.css
index 5ddb1e5..55a5dfc 100644
--- a/src/stylesheets/hidden-functionality.css
+++ b/src/stylesheets/hidden-functionality.css
@@ -37,3 +37,13 @@
.MuiBox-root div .css-1enbsbt-MuiButtonBase-root-MuiButton-root {
display: none !important;
}
+
+/* Hide users menu item by default */
+a[aria-label='Пользователи'] {
+ display: none !important;
+}
+
+/* Show for admin users - this class will be added to body */
+body.is-admin a[aria-label='Пользователи'] {
+ display: flex !important;
+}