mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2025-12-13 07:46:10 +00:00
implemented permissions
This commit is contained in:
parent
42fe4fae4e
commit
0138f20b97
@ -3,7 +3,7 @@ import NavBar from './NavBar'
|
|||||||
import { BrowserRouter } from 'react-router-dom'
|
import { BrowserRouter } from 'react-router-dom'
|
||||||
import { ToastContainer } from 'react-toastify'
|
import { ToastContainer } from 'react-toastify'
|
||||||
|
|
||||||
export function AppShell({ appName, useAuth, children }) {
|
export function AppShell({ appName, children }) {
|
||||||
return (
|
return (
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<ToastContainer position="top-right"
|
<ToastContainer position="top-right"
|
||||||
@ -16,7 +16,7 @@ export function AppShell({ appName, useAuth, children }) {
|
|||||||
draggable
|
draggable
|
||||||
pauseOnHover
|
pauseOnHover
|
||||||
theme="light" />
|
theme="light" />
|
||||||
<NavBar appName={appName} useAuth={useAuth}></NavBar>
|
<NavBar appName={appName}></NavBar>
|
||||||
<div id="app-content" className="tw-flex tw-!pl-[77px]">
|
<div id="app-content" className="tw-flex tw-!pl-[77px]">
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
//import { useAuth } from "../api/auth";
|
import { useAuth } from "../Auth"
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import QuestionMarkIcon from '@heroicons/react/24/outline/QuestionMarkCircleIcon'
|
import QuestionMarkIcon from '@heroicons/react/24/outline/QuestionMarkCircleIcon'
|
||||||
@ -8,7 +8,7 @@ import * as React from "react";
|
|||||||
import DialogModal from "./DialogModal";
|
import DialogModal from "./DialogModal";
|
||||||
|
|
||||||
|
|
||||||
export default function NavBar({ appName, useAuth }: { appName: string, useAuth: any }) {
|
export default function NavBar({ appName}: { appName: string }) {
|
||||||
|
|
||||||
|
|
||||||
const [signupOpen, setSignupOpen] = useState(false);
|
const [signupOpen, setSignupOpen] = useState(false);
|
||||||
@ -110,7 +110,7 @@ export default function NavBar({ appName, useAuth }: { appName: string, useAuth:
|
|||||||
|
|
||||||
{isAuthenticated ?
|
{isAuthenticated ?
|
||||||
<div className="tw-flex-none">
|
<div className="tw-flex-none">
|
||||||
{user.avatar ? <div className="tw-avatar">
|
{user?.avatar ? <div className="tw-avatar">
|
||||||
<div className="tw-w-10 tw-rounded-full">
|
<div className="tw-w-10 tw-rounded-full">
|
||||||
<img src={"https://api.utopia-lab.org/assets/" + user?.avatar + "?access_token=" + token} />
|
<img src={"https://api.utopia-lab.org/assets/" + user?.avatar + "?access_token=" + token} />
|
||||||
</div>
|
</div>
|
||||||
@ -122,7 +122,7 @@ export default function NavBar({ appName, useAuth }: { appName: string, useAuth:
|
|||||||
<path d="M10 6a2 2 0 110-4 2 2 0 010 4zM10 12a2 2 0 110-4 2 2 0 010 4zM10 18a2 2 0 110-4 2 2 0 010 4z" />
|
<path d="M10 6a2 2 0 110-4 2 2 0 010 4zM10 12a2 2 0 110-4 2 2 0 010 4zM10 18a2 2 0 110-4 2 2 0 010 4z" />
|
||||||
</svg>
|
</svg>
|
||||||
</label>
|
</label>
|
||||||
<ul tabIndex={0} className="tw-menu tw-menu-compact tw-dropdown-content tw-mt-3 tw-p-2 tw-shadow tw-bg-base-100 tw-rounded-box tw-w-52 !tw-z-[1500]">
|
<ul tabIndex={0} className="tw-menu tw-menu-compact tw-dropdown-content tw-mt-3 tw-p-2 tw-shadow tw-bg-base-100 tw-rounded-box tw-w-52 !tw-z-[10000]">
|
||||||
<li><Link to={"/settings"}>Settings</Link></li>
|
<li><Link to={"/settings"}>Settings</Link></li>
|
||||||
<li><a onClick={() => { onLogout() }}>Logout</a></li>
|
<li><a onClick={() => { onLogout() }}>Logout</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -148,7 +148,7 @@ export default function NavBar({ appName, useAuth }: { appName: string, useAuth:
|
|||||||
|
|
||||||
|
|
||||||
</label>
|
</label>
|
||||||
<ul tabIndex={1} className="tw-menu tw-dropdown-content tw-mt-3 tw-p-2 tw-shadow tw-bg-base-100 tw-rounded-box tw-w-52 !tw-z-[1500]">
|
<ul tabIndex={1} className="tw-menu tw-dropdown-content tw-mt-3 tw-p-2 tw-shadow tw-bg-base-100 tw-rounded-box tw-w-52 !tw-z-[10000]">
|
||||||
<li><a onClick={() => {setLoginOpen(true)}}>Login</a></li>
|
<li><a onClick={() => {setLoginOpen(true)}}>Login</a></li>
|
||||||
<li><a onClick={() => setSignupOpen(true)}>Sign Up</a></li>
|
<li><a onClick={() => setSignupOpen(true)}>Sign Up</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import {useState, useRef} from 'react'
|
import {useState} from 'react'
|
||||||
import {Link} from 'react-router-dom'
|
import {Link} from 'react-router-dom'
|
||||||
import ErrorText from '../Typography/ErrorText'
|
import ErrorText from '../Typography/ErrorText'
|
||||||
import {TextInput} from '../Input/TextInput'
|
import {TextInput} from '../Input/TextInput'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useState, useRef } from 'react'
|
import { useState } from 'react'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import ErrorText from '../Typography/ErrorText'
|
import ErrorText from '../Typography/ErrorText'
|
||||||
import {TextInput} from '../Input/TextInput'
|
import {TextInput} from '../Input/TextInput'
|
||||||
|
|||||||
@ -22,7 +22,7 @@ type AuthContextProps = {
|
|||||||
login: (credentials: AuthCredentials) => Promise<UserItem | undefined>,
|
login: (credentials: AuthCredentials) => Promise<UserItem | undefined>,
|
||||||
register: (credentials: AuthCredentials, userName: string) => Promise<UserItem | undefined>,
|
register: (credentials: AuthCredentials, userName: string) => Promise<UserItem | undefined>,
|
||||||
loading: Boolean,
|
loading: Boolean,
|
||||||
logout: () => void,
|
logout: () => Promise<any>,
|
||||||
updateUser: (user: UserItem) => any,
|
updateUser: (user: UserItem) => any,
|
||||||
token: String | null
|
token: String | null
|
||||||
}
|
}
|
||||||
@ -33,7 +33,7 @@ const AuthContext = createContext<AuthContextProps>({
|
|||||||
login: () => Promise.reject(),
|
login: () => Promise.reject(),
|
||||||
register: () => Promise.reject(),
|
register: () => Promise.reject(),
|
||||||
loading: false,
|
loading: false,
|
||||||
logout: () => { },
|
logout: () => Promise.reject(),
|
||||||
updateUser: () => Promise.reject(),
|
updateUser: () => Promise.reject(),
|
||||||
token: ""
|
token: ""
|
||||||
});
|
});
|
||||||
|
|||||||
@ -23,7 +23,6 @@ export const Layer = (props: LayerProps) => {
|
|||||||
|
|
||||||
const searchPhrase = useSearchPhrase();
|
const searchPhrase = useSearchPhrase();
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
resetItems(props);
|
resetItems(props);
|
||||||
props.data && setItemsData(props);
|
props.data && setItemsData(props);
|
||||||
|
|||||||
@ -1,16 +1,22 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { ItemsApi, Permission } from '../../types';
|
import { ItemsApi, Permission } from '../../types';
|
||||||
import { useSetPermissionData, useSetPermissionApi } from './hooks/usePermissions'
|
import { useSetPermissionData, useSetPermissionApi, useSetAdminRole } from './hooks/usePermissions'
|
||||||
|
import { useAuth } from '../Auth';
|
||||||
|
|
||||||
export function Permissions({data, api} : {data?: Permission[], api?: ItemsApi<Permission>}) {
|
export function Permissions({data, api, adminRole} : {data?: Permission[], api?: ItemsApi<Permission>, adminRole?: string}) {
|
||||||
const setPermissionData = useSetPermissionData();
|
const setPermissionData = useSetPermissionData();
|
||||||
const setPermissionApi = useSetPermissionApi();
|
const setPermissionApi = useSetPermissionApi();
|
||||||
|
const setAdminRole = useSetAdminRole();
|
||||||
|
const {user} = useAuth();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
console.log(adminRole);
|
||||||
|
|
||||||
|
adminRole && setAdminRole(adminRole);
|
||||||
data && setPermissionData(data);
|
data && setPermissionData(data);
|
||||||
api && setPermissionApi(api);
|
api && setPermissionApi(api);
|
||||||
}, [api, data])
|
}, [api, data, adminRole, user])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<></>
|
<></>
|
||||||
|
|||||||
@ -1,11 +1,14 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import DynamicHeroIcon from '../../../Utils/DynamicHeroIcon'
|
import DynamicHeroIcon from '../../../Utils/DynamicHeroIcon'
|
||||||
import { useLayers } from '../hooks/useLayers'
|
import { useLayers } from '../hooks/useLayers'
|
||||||
|
import { useHasUserPermission } from '../hooks/usePermissions';
|
||||||
|
|
||||||
|
|
||||||
export default function AddButton({ setSelectNewItemPosition }: { setSelectNewItemPosition: React.Dispatch<React.SetStateAction<any>> }) {
|
export default function AddButton({ setSelectNewItemPosition }: { setSelectNewItemPosition: React.Dispatch<React.SetStateAction<any>> }) {
|
||||||
|
|
||||||
const layers = useLayers();
|
const layers = useLayers();
|
||||||
|
const hasUserPermission = useHasUserPermission();
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="tw-dropdown tw-dropdown-top tw-dropdown-end tw-dropdown-hover tw-z-500 tw-absolute tw-right-5 tw-bottom-5" >
|
<div className="tw-dropdown tw-dropdown-top tw-dropdown-end tw-dropdown-hover tw-z-500 tw-absolute tw-right-5 tw-bottom-5" >
|
||||||
@ -16,7 +19,7 @@ export default function AddButton({ setSelectNewItemPosition }: { setSelectNewIt
|
|||||||
</label>
|
</label>
|
||||||
<ul tabIndex={0} className="tw-dropdown-content tw-pr-1 tw-list-none">
|
<ul tabIndex={0} className="tw-dropdown-content tw-pr-1 tw-list-none">
|
||||||
{layers.map((layer) => (
|
{layers.map((layer) => (
|
||||||
layer.api?.createItem && (
|
layer.api?.createItem && hasUserPermission(layer.api.collectionName!,"create") && (
|
||||||
<li key={layer.name} >
|
<li key={layer.name} >
|
||||||
<a>
|
<a>
|
||||||
<div className="tw-tooltip tw-tooltip-left" data-tip={layer.menuText}>
|
<div className="tw-tooltip tw-tooltip-left" data-tip={layer.menuText}>
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { ItemFormPopupProps } from "../ItemFormPopup";
|
|||||||
import { LatLng } from "leaflet";
|
import { LatLng } from "leaflet";
|
||||||
import { Item } from "../../../../types";
|
import { Item } from "../../../../types";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
|
import { useHasUserPermission, usePermissions } from "../../hooks/usePermissions";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -17,12 +18,15 @@ export function HeaderView({ item, setItemFormPopup }: {
|
|||||||
const removeItem = useRemoveItem();
|
const removeItem = useRemoveItem();
|
||||||
|
|
||||||
const map = useMap();
|
const map = useMap();
|
||||||
|
const hasUserPermission = useHasUserPermission();
|
||||||
|
const permissions = usePermissions();
|
||||||
|
|
||||||
|
|
||||||
const removeItemFromMap = async (event: React.MouseEvent<HTMLElement>) => {
|
const removeItemFromMap = async (event: React.MouseEvent<HTMLElement>) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
let success = false;
|
let success = false;
|
||||||
try {
|
try {
|
||||||
await item.layer.api?.deleteItem!(item.id)
|
await item.layer?.api?.deleteItem!(item.id)
|
||||||
success = true;
|
success = true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast.error(error.toString());
|
toast.error(error.toString());
|
||||||
@ -41,16 +45,22 @@ export function HeaderView({ item, setItemFormPopup }: {
|
|||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
map.closePopup();
|
map.closePopup();
|
||||||
if (setItemFormPopup)
|
if (setItemFormPopup)
|
||||||
setItemFormPopup({ position: new LatLng(item.position.coordinates[1], item.position.coordinates[0]), layer: item.layer, item: item, setItemFormPopup: setItemFormPopup })
|
setItemFormPopup({ position: new LatLng(item.position.coordinates[1], item.position.coordinates[0]), layer: item.layer!, item: item, setItemFormPopup: setItemFormPopup })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(item.layer.api.collectionName);
|
||||||
|
console.log(permissions);
|
||||||
|
|
||||||
|
console.log( hasUserPermission(item.api?.collectionName!,"update") );
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='tw-grid tw-grid-cols-6 tw-pb-2'>
|
<div className='tw-grid tw-grid-cols-6 tw-pb-2'>
|
||||||
<div className='tw-col-span-5'>
|
<div className='tw-col-span-5'>
|
||||||
<b className="tw-text-xl tw-font-bold">{item.name}</b>
|
<b className="tw-text-xl tw-font-bold">{item.name}</b>
|
||||||
</div>
|
</div>
|
||||||
<div className='tw-col-span-1'>
|
<div className='tw-col-span-1'>
|
||||||
{item.layer.api &&
|
{item.layer?.api &&
|
||||||
<div className="tw-dropdown tw-dropdown-bottom">
|
<div className="tw-dropdown tw-dropdown-bottom">
|
||||||
<label tabIndex={0} className="tw-bg-base-100 tw-btn tw-m-1 tw-leading-3 tw-border-none tw-min-h-0 tw-h-6">
|
<label tabIndex={0} className="tw-bg-base-100 tw-btn tw-m-1 tw-leading-3 tw-border-none tw-min-h-0 tw-h-6">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" className="tw-h-5 tw-w-5" viewBox="0 0 20 20" fill="currentColor">
|
<svg xmlns="http://www.w3.org/2000/svg" className="tw-h-5 tw-w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||||
@ -58,7 +68,7 @@ export function HeaderView({ item, setItemFormPopup }: {
|
|||||||
</svg>
|
</svg>
|
||||||
</label>
|
</label>
|
||||||
<ul tabIndex={0} className="tw-dropdown-content tw-menu tw-p-2 tw-shadow tw-bg-base-100 tw-rounded-box">
|
<ul tabIndex={0} className="tw-dropdown-content tw-menu tw-p-2 tw-shadow tw-bg-base-100 tw-rounded-box">
|
||||||
{item.layer.api.updateItem && <li>
|
{item.layer.api.updateItem && hasUserPermission(item.layer.api?.collectionName!,"update") && <li>
|
||||||
<a className="!tw-text-base-content" onClick={openEditPopup}>
|
<a className="!tw-text-base-content" onClick={openEditPopup}>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" className="tw-h-5 tw-w-5" viewBox="0 0 20 20" fill="currentColor">
|
<svg xmlns="http://www.w3.org/2000/svg" className="tw-h-5 tw-w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||||
<path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z" />
|
<path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z" />
|
||||||
@ -66,7 +76,7 @@ export function HeaderView({ item, setItemFormPopup }: {
|
|||||||
</a>
|
</a>
|
||||||
</li>}
|
</li>}
|
||||||
|
|
||||||
{item.layer.api.deleteItem && <li>
|
{item.layer.api.deleteItem && hasUserPermission(item.layer.api?.collectionName!,"delete") && <li>
|
||||||
<a className=' !tw-text-error' onClick={removeItemFromMap}>
|
<a className=' !tw-text-error' onClick={removeItemFromMap}>
|
||||||
{loading ? <span className="tw-loading tw-loading-spinner tw-loading-sm"></span>
|
{loading ? <span className="tw-loading tw-loading-spinner tw-loading-sm"></span>
|
||||||
:
|
:
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import { TagsProvider } from "./hooks/useTags";
|
|||||||
import { LayersProvider } from "./hooks/useLayers";
|
import { LayersProvider } from "./hooks/useLayers";
|
||||||
import { FilterProvider } from "./hooks/useFilter";
|
import { FilterProvider } from "./hooks/useFilter";
|
||||||
import { FilterControl } from "./Subcomponents/FilterControl";
|
import { FilterControl } from "./Subcomponents/FilterControl";
|
||||||
|
import { PermissionsProvider } from "./hooks/usePermissions";
|
||||||
|
|
||||||
|
|
||||||
export interface MapEventListenerProps {
|
export interface MapEventListenerProps {
|
||||||
@ -57,37 +58,39 @@ function UtopiaMap({
|
|||||||
return (
|
return (
|
||||||
<LayersProvider initialLayers={[]}>
|
<LayersProvider initialLayers={[]}>
|
||||||
<TagsProvider initialTags={[]}>
|
<TagsProvider initialTags={[]}>
|
||||||
<FilterProvider initialTags={[]}>
|
<PermissionsProvider initialPermissions={[]}>
|
||||||
<ItemsProvider initialItems={[]}>
|
<FilterProvider initialTags={[]}>
|
||||||
<div className={(selectNewItemPosition != null ? "crosshair-cursor-enabled" : undefined)}>
|
<ItemsProvider initialItems={[]}>
|
||||||
<MapContainer ref={mapDivRef} style={{ height: height, width: width }} center={center} zoom={zoom} zoomControl={false}>
|
<div className={(selectNewItemPosition != null ? "crosshair-cursor-enabled" : undefined)}>
|
||||||
<FilterControl></FilterControl>
|
<MapContainer ref={mapDivRef} style={{ height: height, width: width }} center={center} zoom={zoom} zoomControl={false}>
|
||||||
<TileLayer
|
<FilterControl></FilterControl>
|
||||||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
<TileLayer
|
||||||
url="https://tile.osmand.net/hd/{z}/{x}/{y}.png" />
|
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||||
<MarkerClusterGroup showCoverageOnHover chunkedLoading maxClusterRadius={50} removeOutsideVisibleBounds={false}>
|
url="https://tile.osmand.net/hd/{z}/{x}/{y}.png" />
|
||||||
{
|
<MarkerClusterGroup showCoverageOnHover chunkedLoading maxClusterRadius={50} removeOutsideVisibleBounds={false}>
|
||||||
React.Children.toArray(children).map((child) =>
|
{
|
||||||
React.isValidElement<{ setItemFormPopup: React.Dispatch<React.SetStateAction<ItemFormPopupProps>>, itemFormPopup: ItemFormPopupProps | null }>(child) ?
|
React.Children.toArray(children).map((child) =>
|
||||||
React.cloneElement(child, { setItemFormPopup: setItemFormPopup, itemFormPopup: itemFormPopup }) : child
|
React.isValidElement<{ setItemFormPopup: React.Dispatch<React.SetStateAction<ItemFormPopupProps>>, itemFormPopup: ItemFormPopupProps | null }>(child) ?
|
||||||
)
|
React.cloneElement(child, { setItemFormPopup: setItemFormPopup, itemFormPopup: itemFormPopup }) : child
|
||||||
}
|
)
|
||||||
</MarkerClusterGroup>
|
}
|
||||||
<MapEventListener setSelectNewItemPosition={setSelectNewItemPosition} selectNewItemPosition={selectNewItemPosition} setItemFormPopup={setItemFormPopup} />
|
</MarkerClusterGroup>
|
||||||
</MapContainer>
|
<MapEventListener setSelectNewItemPosition={setSelectNewItemPosition} selectNewItemPosition={selectNewItemPosition} setItemFormPopup={setItemFormPopup} />
|
||||||
<AddButton setSelectNewItemPosition={setSelectNewItemPosition}></AddButton>
|
</MapContainer>
|
||||||
{selectNewItemPosition != null &&
|
<AddButton setSelectNewItemPosition={setSelectNewItemPosition}></AddButton>
|
||||||
<div className="tw-button tw-z-1000 tw-absolute tw-right-5 tw-top-4 tw-drop-shadow-md">
|
{selectNewItemPosition != null &&
|
||||||
<div className="tw-alert tw-bg-base-100 tw-text-base-content">
|
<div className="tw-button tw-z-1000 tw-absolute tw-right-5 tw-top-4 tw-drop-shadow-md">
|
||||||
<div>
|
<div className="tw-alert tw-bg-base-100 tw-text-base-content">
|
||||||
<span>Select {selectNewItemPosition.name} position!</span>
|
<div>
|
||||||
|
<span>Select {selectNewItemPosition.name} position!</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
}
|
||||||
}
|
</div>
|
||||||
</div>
|
</ItemsProvider>
|
||||||
</ItemsProvider>
|
</FilterProvider>
|
||||||
</FilterProvider>
|
</PermissionsProvider>
|
||||||
</TagsProvider>
|
</TagsProvider>
|
||||||
</LayersProvider>
|
</LayersProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { useCallback, useReducer, createContext, useContext } from "react";
|
import { useCallback, useReducer, createContext, useContext } from "react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { ItemsApi, Permission } from "../../../types";
|
import { ItemsApi, LayerProps, Permission, PermissionAction } from "../../../types";
|
||||||
|
import { useAuth } from "../../Auth";
|
||||||
|
|
||||||
type ActionType =
|
type ActionType =
|
||||||
| { type: "ADD"; permission: Permission }
|
| { type: "ADD"; permission: Permission }
|
||||||
@ -11,13 +12,17 @@ type UsePermissionManagerResult = ReturnType<typeof usePermissionsManager>;
|
|||||||
const PermissionContext = createContext<UsePermissionManagerResult>({
|
const PermissionContext = createContext<UsePermissionManagerResult>({
|
||||||
permissions: [],
|
permissions: [],
|
||||||
setPermissionApi: () => { },
|
setPermissionApi: () => { },
|
||||||
setPermissionData: () => { }
|
setPermissionData: () => { },
|
||||||
|
setAdminRole: () => { },
|
||||||
|
hasUserPermission: () => true
|
||||||
});
|
});
|
||||||
|
|
||||||
function usePermissionsManager(initialPermissions: Permission[]): {
|
function usePermissionsManager(initialPermissions: Permission[]): {
|
||||||
permissions: Permission[];
|
permissions: Permission[];
|
||||||
setPermissionApi: (api: ItemsApi<Permission>) => void;
|
setPermissionApi: (api: ItemsApi<any>) => void;
|
||||||
setPermissionData: (data: Permission[]) => void;
|
setPermissionData: (data: Permission[]) => void;
|
||||||
|
setAdminRole: (adminRole: string) => void;
|
||||||
|
hasUserPermission: (collectionName: string, action: PermissionAction) => boolean;
|
||||||
} {
|
} {
|
||||||
const [permissions, dispatch] = useReducer((state: Permission[], action: ActionType) => {
|
const [permissions, dispatch] = useReducer((state: Permission[], action: ActionType) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
@ -38,10 +43,13 @@ function usePermissionsManager(initialPermissions: Permission[]): {
|
|||||||
}
|
}
|
||||||
}, initialPermissions);
|
}, initialPermissions);
|
||||||
|
|
||||||
const [api, setApi] = React.useState<ItemsApi<Permission>>({} as ItemsApi<Permission>)
|
const [adminRole, setAdminRole] = React.useState<string | null>(null);
|
||||||
|
const { user } = useAuth();
|
||||||
|
|
||||||
|
|
||||||
const setPermissionApi = useCallback(async (api: ItemsApi<Permission>) => {
|
const setPermissionApi = useCallback(async (api: ItemsApi<Permission>) => {
|
||||||
setApi(api);
|
console.log("check");
|
||||||
|
|
||||||
const result = await api.getItems();
|
const result = await api.getItems();
|
||||||
if (result) {
|
if (result) {
|
||||||
result.map(permission => {
|
result.map(permission => {
|
||||||
@ -56,8 +64,17 @@ function usePermissionsManager(initialPermissions: Permission[]): {
|
|||||||
})
|
})
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const hasUserPermission = useCallback((collectionName: string, action: PermissionAction) => {
|
||||||
|
console.log(permissions);
|
||||||
|
|
||||||
|
if (permissions.length == 0) return true;
|
||||||
|
else if (user && user.role == adminRole) return true;
|
||||||
|
else return permissions.some(p => p.action === action && p.collection === collectionName && p.role == user?.role)
|
||||||
|
}, [permissions, user]);
|
||||||
|
|
||||||
return { permissions, setPermissionApi, setPermissionData };
|
|
||||||
|
|
||||||
|
return { permissions, setPermissionApi, setPermissionData, setAdminRole, hasUserPermission };
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PermissionsProvider: React.FunctionComponent<{
|
export const PermissionsProvider: React.FunctionComponent<{
|
||||||
@ -82,4 +99,14 @@ export const useSetPermissionApi = (): UsePermissionManagerResult["setPermission
|
|||||||
export const useSetPermissionData = (): UsePermissionManagerResult["setPermissionData"] => {
|
export const useSetPermissionData = (): UsePermissionManagerResult["setPermissionData"] => {
|
||||||
const { setPermissionData } = useContext(PermissionContext);
|
const { setPermissionData } = useContext(PermissionContext);
|
||||||
return setPermissionData;
|
return setPermissionData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useHasUserPermission = (): UsePermissionManagerResult["hasUserPermission"] => {
|
||||||
|
const { hasUserPermission } = useContext(PermissionContext);
|
||||||
|
return hasUserPermission;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useSetAdminRole = (): UsePermissionManagerResult["setAdminRole"] => {
|
||||||
|
const { setAdminRole } = useContext(PermissionContext);
|
||||||
|
return setAdminRole;
|
||||||
}
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
export { UtopiaMap } from './UtopiaMap';
|
export { UtopiaMap } from './UtopiaMap';
|
||||||
export { Layer } from './Layer';
|
export { Layer } from './Layer';
|
||||||
export { Tags } from "./Tags";
|
export { Tags } from "./Tags";
|
||||||
|
export { Permissions } from "./Permissions";
|
||||||
export {ItemForm} from './ItemForm';
|
export {ItemForm} from './ItemForm';
|
||||||
export {ItemView} from './ItemView';
|
export {ItemView} from './ItemView';
|
||||||
export {PopupTextAreaInput} from './Subcomponents/ItemPopupComponents/PopupTextAreaInput';
|
export {PopupTextAreaInput} from './Subcomponents/ItemPopupComponents/PopupTextAreaInput';
|
||||||
|
|||||||
@ -4,11 +4,13 @@ import {TextInput} from '../Input/TextInput'
|
|||||||
import {TextAreaInput} from '../Input/TextAreaInput'
|
import {TextAreaInput} from '../Input/TextAreaInput'
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import {useNavigate} from 'react-router-dom'
|
import {useNavigate} from 'react-router-dom'
|
||||||
|
import { useAuth } from '../Auth';
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
|
|
||||||
import 'react-toastify/dist/ReactToastify.css';
|
import 'react-toastify/dist/ReactToastify.css';
|
||||||
|
import { UserItem } from '../../types';
|
||||||
|
|
||||||
export function Settings({useAuth}) {
|
export function Settings() {
|
||||||
|
|
||||||
const { user, updateUser, loading } = useAuth();
|
const { user, updateUser, loading } = useAuth();
|
||||||
|
|
||||||
@ -35,7 +37,7 @@ export function Settings({useAuth}) {
|
|||||||
|
|
||||||
|
|
||||||
const onUpdateUser = () => {
|
const onUpdateUser = () => {
|
||||||
let changedUser = {};
|
let changedUser = {} as UserItem;
|
||||||
|
|
||||||
if(passwordChanged) {
|
if(passwordChanged) {
|
||||||
changedUser = { id: id, first_name: name, description: text, email: email, password: password };
|
changedUser = { id: id, first_name: name, description: text, email: email, password: password };
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
export { UtopiaMap, Layer, Tags, ItemForm, ItemView, PopupTextAreaInput, PopupStartEndInput, TextView, StartEndView } from './Components/Map/index';
|
export { UtopiaMap, Layer, Tags, Permissions, ItemForm, ItemView, PopupTextAreaInput, PopupStartEndInput, TextView, StartEndView } from './Components/Map';
|
||||||
export {AppShell, Content, SideBar} from "./Components/AppShell"
|
export {AppShell, Content, SideBar} from "./Components/AppShell"
|
||||||
export {AuthProvider, useAuth, LoginPage, SignupPage} from "./Components/Auth"
|
export {AuthProvider, useAuth, LoginPage, SignupPage} from "./Components/Auth"
|
||||||
export {Settings} from './Components/Profile'
|
export {Settings} from './Components/Profile'
|
||||||
|
|||||||
11
src/types.ts
11
src/types.ts
@ -66,6 +66,7 @@ export interface ItemsApi<T> {
|
|||||||
createItem?(item : T): Promise<any>,
|
createItem?(item : T): Promise<any>,
|
||||||
updateItem?(item : T): Promise<any>,
|
updateItem?(item : T): Promise<any>,
|
||||||
deleteItem?(id : number | string): Promise<any>,
|
deleteItem?(id : number | string): Promise<any>,
|
||||||
|
collectionName?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserApi {
|
export interface UserApi {
|
||||||
@ -79,7 +80,8 @@ export interface UserApi {
|
|||||||
|
|
||||||
export type UserItem = {
|
export type UserItem = {
|
||||||
id?: string;
|
id?: string;
|
||||||
avatar: string;
|
avatar?: string;
|
||||||
|
role?: string;
|
||||||
first_name: string;
|
first_name: string;
|
||||||
description: string;
|
description: string;
|
||||||
email: string;
|
email: string;
|
||||||
@ -90,5 +92,8 @@ export type Permission = {
|
|||||||
id?: string;
|
id?: string;
|
||||||
role: string;
|
role: string;
|
||||||
collection: string;
|
collection: string;
|
||||||
action: string;
|
action: PermissionAction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type PermissionAction = "create"|"read"|"update"|"delete";
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user