R: Replace AccessMode with RoleStore
Some checks are pending
Frontend CI / build (22.x) (push) Waiting to run

This commit is contained in:
Ivan 2025-01-15 23:03:35 +03:00
parent b9ee1b9d08
commit b260640ebf
14 changed files with 147 additions and 164 deletions

View File

@ -1,25 +0,0 @@
'use client';
import { createContext, useContext, useState } from 'react';
import { UserLevel } from '@/models/user';
import { contextOutsideScope } from '@/utils/labels';
interface IAccessModeContext {
accessLevel: UserLevel;
setAccessLevel: React.Dispatch<React.SetStateAction<UserLevel>>;
}
const AccessContext = createContext<IAccessModeContext | null>(null);
export const useAccessMode = () => {
const context = useContext(AccessContext);
if (!context) {
throw new Error(contextOutsideScope('useAccessMode', 'AccessModeState'));
}
return context;
};
export const AccessModeState = ({ children }: React.PropsWithChildren) => {
const [accessLevel, setAccessLevel] = useState<UserLevel>(UserLevel.READER);
return <AccessContext value={{ accessLevel, setAccessLevel }}>{children}</AccessContext>;
};

View File

@ -103,7 +103,7 @@ export interface ITargetUsers {
/**
* Represents user access mode.
*/
export enum UserLevel {
export enum UserRole {
READER = 0,
EDITOR,
OWNER,

View File

@ -19,13 +19,13 @@ import Button from '@/components/ui/Button';
import Divider from '@/components/ui/Divider';
import Dropdown from '@/components/ui/Dropdown';
import DropdownButton from '@/components/ui/DropdownButton';
import { useAccessMode } from '@/context/AccessModeContext';
import { useAuth } from '@/context/AuthContext';
import { useConceptNavigation } from '@/context/NavigationContext';
import { useOSS } from '@/context/OssContext';
import useDropdown from '@/hooks/useDropdown';
import { UserLevel } from '@/models/user';
import { describeAccessMode, labelAccessMode } from '@/utils/labels';
import { UserRole } from '@/models/user';
import { useRoleStore } from '@/stores/role';
import { describeAccessMode as describeUserRole, labelAccessMode as labelUserRole } from '@/utils/labels';
import { useOssEdit } from './OssEditContext';
@ -39,7 +39,8 @@ function MenuOssTabs({ onDestroy }: MenuOssTabsProps) {
const { user } = useAuth();
const model = useOSS();
const { accessLevel, setAccessLevel } = useAccessMode();
const role = useRoleStore(state => state.role);
const setRole = useRoleStore(state => state.setRole);
const schemaMenu = useDropdown();
const editMenu = useDropdown();
@ -55,9 +56,9 @@ function MenuOssTabs({ onDestroy }: MenuOssTabsProps) {
controller.share();
}
function handleChangeMode(newMode: UserLevel) {
function handleChangeRole(newMode: UserRole) {
accessMenu.hide();
setAccessLevel(newMode);
setRole(newMode);
}
function handleCreateNew() {
@ -97,7 +98,7 @@ function MenuOssTabs({ onDestroy }: MenuOssTabsProps) {
<DropdownButton
text='Удалить схему'
icon={<IconDestroy size='1rem' className='icon-red' />}
disabled={controller.isProcessing || accessLevel < UserLevel.OWNER}
disabled={controller.isProcessing || role < UserRole.OWNER}
onClick={handleDelete}
/>
) : null}
@ -151,15 +152,15 @@ function MenuOssTabs({ onDestroy }: MenuOssTabsProps) {
noBorder
noOutline
tabIndex={-1}
title={`Режим ${labelAccessMode(accessLevel)}`}
title={`Режим ${labelUserRole(role)}`}
hideTitle={accessMenu.isOpen}
className='h-full pr-2'
icon={
accessLevel === UserLevel.ADMIN ? (
role === UserRole.ADMIN ? (
<IconAdmin size='1.25rem' className='icon-primary' />
) : accessLevel === UserLevel.OWNER ? (
) : role === UserRole.OWNER ? (
<IconOwner size='1.25rem' className='icon-primary' />
) : accessLevel === UserLevel.EDITOR ? (
) : role === UserRole.EDITOR ? (
<IconEditor size='1.25rem' className='icon-primary' />
) : (
<IconReader size='1.25rem' className='icon-primary' />
@ -169,31 +170,31 @@ function MenuOssTabs({ onDestroy }: MenuOssTabsProps) {
/>
<Dropdown isOpen={accessMenu.isOpen}>
<DropdownButton
text={labelAccessMode(UserLevel.READER)}
title={describeAccessMode(UserLevel.READER)}
text={labelUserRole(UserRole.READER)}
title={describeUserRole(UserRole.READER)}
icon={<IconReader size='1rem' className='icon-primary' />}
onClick={() => handleChangeMode(UserLevel.READER)}
onClick={() => handleChangeRole(UserRole.READER)}
/>
<DropdownButton
text={labelAccessMode(UserLevel.EDITOR)}
title={describeAccessMode(UserLevel.EDITOR)}
text={labelUserRole(UserRole.EDITOR)}
title={describeUserRole(UserRole.EDITOR)}
icon={<IconEditor size='1rem' className='icon-primary' />}
disabled={!model.isOwned && !model.schema?.editors.includes(user.id)}
onClick={() => handleChangeMode(UserLevel.EDITOR)}
onClick={() => handleChangeRole(UserRole.EDITOR)}
/>
<DropdownButton
text={labelAccessMode(UserLevel.OWNER)}
title={describeAccessMode(UserLevel.OWNER)}
text={labelUserRole(UserRole.OWNER)}
title={describeUserRole(UserRole.OWNER)}
icon={<IconOwner size='1rem' className='icon-primary' />}
disabled={!model.isOwned}
onClick={() => handleChangeMode(UserLevel.OWNER)}
onClick={() => handleChangeRole(UserRole.OWNER)}
/>
<DropdownButton
text={labelAccessMode(UserLevel.ADMIN)}
title={describeAccessMode(UserLevel.ADMIN)}
text={labelUserRole(UserRole.ADMIN)}
title={describeUserRole(UserRole.ADMIN)}
icon={<IconAdmin size='1rem' className='icon-primary' />}
disabled={!user?.is_staff}
onClick={() => handleChangeMode(UserLevel.ADMIN)}
onClick={() => handleChangeRole(UserRole.ADMIN)}
/>
</Dropdown>
</div>

View File

@ -4,7 +4,6 @@ import { createContext, useCallback, useContext, useEffect, useMemo, useState }
import { toast } from 'react-toastify';
import { urls } from '@/app/urls';
import { useAccessMode } from '@/context/AccessModeContext';
import { useAuth } from '@/context/AuthContext';
import { useLibrary } from '@/context/LibraryContext';
import { useConceptNavigation } from '@/context/NavigationContext';
@ -30,8 +29,9 @@ import {
OperationID,
OperationType
} from '@/models/oss';
import { UserID, UserLevel } from '@/models/user';
import { UserID, UserRole } from '@/models/user';
import { usePreferencesStore } from '@/stores/preferences';
import { useRoleStore } from '@/stores/role';
import { PARAMETER } from '@/utils/constants';
import { errors, information } from '@/utils/labels';
@ -96,14 +96,13 @@ export const OssEditState = ({ selected, setSelected, children }: React.PropsWit
const router = useConceptNavigation();
const { user } = useAuth();
const adminMode = usePreferencesStore(state => state.adminMode);
const { accessLevel, setAccessLevel } = useAccessMode();
const role = useRoleStore(state => state.role);
const adjustRole = useRoleStore(state => state.adjustRole);
const model = useOSS();
const library = useLibrary();
const isMutable = useMemo(
() => accessLevel > UserLevel.READER && !model.schema?.read_only,
[accessLevel, model.schema?.read_only]
);
const isMutable = role > UserRole.READER && !model.schema?.read_only;
const [showTooltip, setShowTooltip] = useState(true);
@ -128,23 +127,13 @@ export const OssEditState = ({ selected, setSelected, children }: React.PropsWit
useEffect(
() =>
setAccessLevel(prev => {
if (
prev === UserLevel.EDITOR &&
(model.isOwned || user?.is_staff || (user && model.schema?.editors.includes(user.id)))
) {
return UserLevel.EDITOR;
} else if (user?.is_staff && (prev === UserLevel.ADMIN || adminMode)) {
return UserLevel.ADMIN;
} else if (model.isOwned) {
return UserLevel.OWNER;
} else if (user?.id && model.schema?.editors.includes(user?.id)) {
return UserLevel.EDITOR;
} else {
return UserLevel.READER;
}
adjustRole({
isOwner: model.isOwned,
isEditor: (user && model.schema?.editors.includes(user?.id)) ?? false,
isStaff: user?.is_staff ?? false,
adminMode: adminMode
}),
[model.schema, setAccessLevel, model.isOwned, user, adminMode]
[model.schema, adjustRole, model.isOwned, user, adminMode]
);
const handleSetLocation = useCallback(

View File

@ -2,7 +2,6 @@
import { useParams } from 'react-router';
import { AccessModeState } from '@/context/AccessModeContext';
import { OssState } from '@/context/OssContext';
import OssTabs from './OssTabs';
@ -10,11 +9,9 @@ import OssTabs from './OssTabs';
function OssPage() {
const params = useParams();
return (
<AccessModeState>
<OssState itemID={params.id ?? ''}>
<OssTabs />
</OssState>
</AccessModeState>
<OssState itemID={params.id ?? ''}>
<OssTabs />
</OssState>
);
}

View File

@ -17,13 +17,13 @@ import MiniButton from '@/components/ui/MiniButton';
import Overlay from '@/components/ui/Overlay';
import Tooltip from '@/components/ui/Tooltip';
import ValueIcon from '@/components/ui/ValueIcon';
import { useAccessMode } from '@/context/AccessModeContext';
import { useConceptNavigation } from '@/context/NavigationContext';
import { useUsers } from '@/context/UsersContext';
import useDropdown from '@/hooks/useDropdown';
import { ILibraryItemData, ILibraryItemEditor } from '@/models/library';
import { UserID, UserLevel } from '@/models/user';
import { UserID, UserRole } from '@/models/user';
import { useLibrarySearchStore } from '@/stores/librarySearch';
import { useRoleStore } from '@/stores/role';
import { prefixes } from '@/utils/constants';
import { prompts } from '@/utils/labels';
@ -35,7 +35,7 @@ interface EditorLibraryItemProps {
function EditorLibraryItem({ item, isModified, controller }: EditorLibraryItemProps) {
const { getUserLabel, users } = useUsers();
const { accessLevel } = useAccessMode();
const role = useRoleStore(state => state.role);
const intl = useIntl();
const router = useConceptNavigation();
const setLocation = useLibrarySearchStore(state => state.setLocation);
@ -86,9 +86,7 @@ function EditorLibraryItem({ item, isModified, controller }: EditorLibraryItemPr
value={item.location}
title={controller.isAttachedToOSS ? 'Путь наследуется от ОСС' : 'Путь'}
onClick={controller.promptLocation}
disabled={
isModified || controller.isProcessing || controller.isAttachedToOSS || accessLevel < UserLevel.OWNER
}
disabled={isModified || controller.isProcessing || controller.isAttachedToOSS || role < UserRole.OWNER}
/>
</div>
@ -110,7 +108,7 @@ function EditorLibraryItem({ item, isModified, controller }: EditorLibraryItemPr
value={getUserLabel(item.owner)}
title={controller.isAttachedToOSS ? 'Владелец наследуется от ОСС' : 'Владелец'}
onClick={ownerSelector.toggle}
disabled={isModified || controller.isProcessing || controller.isAttachedToOSS || accessLevel < UserLevel.OWNER}
disabled={isModified || controller.isProcessing || controller.isAttachedToOSS || role < UserRole.OWNER}
/>
<div className='sm:mb-1 flex justify-between items-center'>
@ -120,7 +118,7 @@ function EditorLibraryItem({ item, isModified, controller }: EditorLibraryItemPr
icon={<IconEditor size='1.25rem' className='icon-primary' />}
value={item.editors.length}
onClick={controller.promptEditors}
disabled={isModified || controller.isProcessing || accessLevel < UserLevel.OWNER}
disabled={isModified || controller.isProcessing || role < UserRole.OWNER}
/>
<Tooltip anchorSelect='#editor_stats' layer='z-modalTooltip'>
<InfoUsers items={item?.editors ?? []} prefix={prefixes.user_editors} header='Редакторы' />

View File

@ -5,10 +5,10 @@ import SelectAccessPolicy from '@/components/select/SelectAccessPolicy';
import Label from '@/components/ui/Label';
import MiniButton from '@/components/ui/MiniButton';
import Overlay from '@/components/ui/Overlay';
import { useAccessMode } from '@/context/AccessModeContext';
import { AccessPolicy, ILibraryItemEditor } from '@/models/library';
import { HelpTopic } from '@/models/miscellaneous';
import { UserLevel } from '@/models/user';
import { UserRole } from '@/models/user';
import { useRoleStore } from '@/stores/role';
import { PARAMETER } from '@/utils/constants';
interface ToolbarItemAccessProps {
@ -20,7 +20,7 @@ interface ToolbarItemAccessProps {
}
function ToolbarItemAccess({ visible, toggleVisible, readOnly, toggleReadOnly, controller }: ToolbarItemAccessProps) {
const { accessLevel } = useAccessMode();
const role = useRoleStore(state => state.role);
const policy = controller.schema?.access_policy ?? AccessPolicy.PRIVATE;
return (
@ -28,7 +28,7 @@ function ToolbarItemAccess({ visible, toggleVisible, readOnly, toggleReadOnly, c
<Label text='Доступ' className='self-center select-none' />
<div className='ml-auto cc-icons'>
<SelectAccessPolicy
disabled={accessLevel <= UserLevel.EDITOR || controller.isProcessing || controller.isAttachedToOSS}
disabled={role <= UserRole.EDITOR || controller.isProcessing || controller.isAttachedToOSS}
value={policy}
onChange={newPolicy => controller.setAccessPolicy(newPolicy)}
/>
@ -37,7 +37,7 @@ function ToolbarItemAccess({ visible, toggleVisible, readOnly, toggleReadOnly, c
title={visible ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
icon={<VisibilityIcon value={visible} />}
onClick={toggleVisible}
disabled={accessLevel === UserLevel.READER || controller.isProcessing}
disabled={role === UserRole.READER || controller.isProcessing}
/>
<MiniButton
@ -50,7 +50,7 @@ function ToolbarItemAccess({ visible, toggleVisible, readOnly, toggleReadOnly, c
)
}
onClick={toggleReadOnly}
disabled={accessLevel === UserLevel.READER || controller.isProcessing}
disabled={role === UserRole.READER || controller.isProcessing}
/>
<BadgeHelp topic={HelpTopic.ACCESS} className={PARAMETER.TOOLTIP_WIDTH} offset={4} />

View File

@ -5,11 +5,11 @@ import BadgeHelp from '@/components/info/BadgeHelp';
import MiniSelectorOSS from '@/components/select/MiniSelectorOSS';
import MiniButton from '@/components/ui/MiniButton';
import Overlay from '@/components/ui/Overlay';
import { useAccessMode } from '@/context/AccessModeContext';
import { AccessPolicy, ILibraryItemEditor, LibraryItemType } from '@/models/library';
import { HelpTopic } from '@/models/miscellaneous';
import { IRSForm } from '@/models/rsform';
import { UserLevel } from '@/models/user';
import { UserRole } from '@/models/user';
import { useRoleStore } from '@/stores/role';
import { PARAMETER } from '@/utils/constants';
import { prepareTooltip, tooltips } from '@/utils/labels';
@ -23,7 +23,7 @@ interface ToolbarRSFormCardProps {
}
function ToolbarRSFormCard({ modified, controller, onSubmit, onDestroy }: ToolbarRSFormCardProps) {
const { accessLevel } = useAccessMode();
const role = useRoleStore(state => state.role);
const canSave = modified && !controller.isProcessing;
const ossSelector = (() => {
@ -63,7 +63,7 @@ function ToolbarRSFormCard({ modified, controller, onSubmit, onDestroy }: Toolba
<MiniButton
title='Удалить схему'
icon={<IconDestroy size='1.25rem' className='icon-red' />}
disabled={!controller.isMutable || controller.isProcessing || accessLevel < UserLevel.OWNER}
disabled={!controller.isMutable || controller.isProcessing || role < UserRole.OWNER}
onClick={onDestroy}
/>
) : null}

View File

@ -31,14 +31,14 @@ import Button from '@/components/ui/Button';
import Divider from '@/components/ui/Divider';
import Dropdown from '@/components/ui/Dropdown';
import DropdownButton from '@/components/ui/DropdownButton';
import { useAccessMode } from '@/context/AccessModeContext';
import { useAuth } from '@/context/AuthContext';
import { useGlobalOss } from '@/context/GlobalOssContext';
import { useConceptNavigation } from '@/context/NavigationContext';
import { useRSForm } from '@/context/RSFormContext';
import useDropdown from '@/hooks/useDropdown';
import { AccessPolicy } from '@/models/library';
import { UserLevel } from '@/models/user';
import { UserRole } from '@/models/user';
import { useRoleStore } from '@/stores/role';
import { describeAccessMode, labelAccessMode, tooltips } from '@/utils/labels';
import { OssTabID } from '../OssPage/OssTabs';
@ -55,7 +55,8 @@ function MenuRSTabs({ onDestroy }: MenuRSTabsProps) {
const model = useRSForm();
const oss = useGlobalOss();
const { accessLevel, setAccessLevel } = useAccessMode();
const role = useRoleStore(state => state.role);
const setRole = useRoleStore(state => state.setRole);
const schemaMenu = useDropdown();
const editMenu = useDropdown();
@ -126,9 +127,9 @@ function MenuRSTabs({ onDestroy }: MenuRSTabsProps) {
controller.inlineSynthesis();
}
function handleChangeMode(newMode: UserLevel) {
function handleChangeMode(newMode: UserRole) {
accessMenu.hide();
setAccessLevel(newMode);
setRole(newMode);
}
function handleCreateNew() {
@ -198,7 +199,7 @@ function MenuRSTabs({ onDestroy }: MenuRSTabsProps) {
<DropdownButton
text='Удалить схему'
icon={<IconDestroy size='1rem' className='icon-red' />}
disabled={controller.isProcessing || accessLevel < UserLevel.OWNER}
disabled={controller.isProcessing || role < UserRole.OWNER}
onClick={handleDelete}
/>
) : null}
@ -310,15 +311,15 @@ function MenuRSTabs({ onDestroy }: MenuRSTabsProps) {
noBorder
noOutline
tabIndex={-1}
title={`Режим ${labelAccessMode(accessLevel)}`}
title={`Режим ${labelAccessMode(role)}`}
hideTitle={accessMenu.isOpen}
className='h-full pr-2'
icon={
accessLevel === UserLevel.ADMIN ? (
role === UserRole.ADMIN ? (
<IconAdmin size='1.25rem' className='icon-primary' />
) : accessLevel === UserLevel.OWNER ? (
) : role === UserRole.OWNER ? (
<IconOwner size='1.25rem' className='icon-primary' />
) : accessLevel === UserLevel.EDITOR ? (
) : role === UserRole.EDITOR ? (
<IconEditor size='1.25rem' className='icon-primary' />
) : (
<IconReader size='1.25rem' className='icon-primary' />
@ -328,31 +329,31 @@ function MenuRSTabs({ onDestroy }: MenuRSTabsProps) {
/>
<Dropdown isOpen={accessMenu.isOpen}>
<DropdownButton
text={labelAccessMode(UserLevel.READER)}
title={describeAccessMode(UserLevel.READER)}
text={labelAccessMode(UserRole.READER)}
title={describeAccessMode(UserRole.READER)}
icon={<IconReader size='1rem' className='icon-primary' />}
onClick={() => handleChangeMode(UserLevel.READER)}
onClick={() => handleChangeMode(UserRole.READER)}
/>
<DropdownButton
text={labelAccessMode(UserLevel.EDITOR)}
title={describeAccessMode(UserLevel.EDITOR)}
text={labelAccessMode(UserRole.EDITOR)}
title={describeAccessMode(UserRole.EDITOR)}
icon={<IconEditor size='1rem' className='icon-primary' />}
disabled={!model.isOwned && !model.schema?.editors.includes(user.id)}
onClick={() => handleChangeMode(UserLevel.EDITOR)}
onClick={() => handleChangeMode(UserRole.EDITOR)}
/>
<DropdownButton
text={labelAccessMode(UserLevel.OWNER)}
title={describeAccessMode(UserLevel.OWNER)}
text={labelAccessMode(UserRole.OWNER)}
title={describeAccessMode(UserRole.OWNER)}
icon={<IconOwner size='1rem' className='icon-primary' />}
disabled={!model.isOwned}
onClick={() => handleChangeMode(UserLevel.OWNER)}
onClick={() => handleChangeMode(UserRole.OWNER)}
/>
<DropdownButton
text={labelAccessMode(UserLevel.ADMIN)}
title={describeAccessMode(UserLevel.ADMIN)}
text={labelAccessMode(UserRole.ADMIN)}
title={describeAccessMode(UserRole.ADMIN)}
icon={<IconAdmin size='1rem' className='icon-primary' />}
disabled={!user?.is_staff}
onClick={() => handleChangeMode(UserLevel.ADMIN)}
onClick={() => handleChangeMode(UserRole.ADMIN)}
/>
</Dropdown>
</div>

View File

@ -5,7 +5,6 @@ import { createContext, useCallback, useContext, useEffect, useMemo, useState }
import { toast } from 'react-toastify';
import { urls } from '@/app/urls';
import { useAccessMode } from '@/context/AccessModeContext';
import { useAuth } from '@/context/AuthContext';
import { useConceptNavigation } from '@/context/NavigationContext';
import { useRSForm } from '@/context/RSFormContext';
@ -49,8 +48,9 @@ import {
TermForm
} from '@/models/rsform';
import { generateAlias } from '@/models/rsformAPI';
import { UserID, UserLevel } from '@/models/user';
import { UserID, UserRole } from '@/models/user';
import { usePreferencesStore } from '@/stores/preferences';
import { useRoleStore } from '@/stores/role';
import { EXTEOR_TRS_FILE } from '@/utils/constants';
import { information, prompts } from '@/utils/labels';
import { promptUnsaved } from '@/utils/utils';
@ -143,13 +143,11 @@ export const RSEditState = ({
const router = useConceptNavigation();
const { user } = useAuth();
const adminMode = usePreferencesStore(state => state.adminMode);
const { accessLevel, setAccessLevel } = useAccessMode();
const role = useRoleStore(state => state.role);
const adjustRole = useRoleStore(state => state.adjustRole);
const model = useRSForm();
const isMutable = useMemo(
() => accessLevel > UserLevel.READER && !model.schema?.read_only,
[accessLevel, model.schema?.read_only]
);
const isMutable = useMemo(() => role > UserRole.READER && !model.schema?.read_only, [role, model.schema?.read_only]);
const isContentEditable = useMemo(() => isMutable && !model.isArchive, [isMutable, model.isArchive]);
const canDeleteSelected = useMemo(
() => selected.length > 0 && selected.every(id => !model.schema?.cstByID.get(id)?.is_inherited),
@ -199,23 +197,13 @@ export const RSEditState = ({
useEffect(
() =>
setAccessLevel(prev => {
if (
prev === UserLevel.EDITOR &&
(model.isOwned || user?.is_staff || (user && model.schema?.editors.includes(user.id)))
) {
return UserLevel.EDITOR;
} else if (user?.is_staff && (prev === UserLevel.ADMIN || adminMode)) {
return UserLevel.ADMIN;
} else if (model.isOwned) {
return UserLevel.OWNER;
} else if (user?.id && model.schema?.editors.includes(user?.id)) {
return UserLevel.EDITOR;
} else {
return UserLevel.READER;
}
adjustRole({
isOwner: model.isOwned,
isEditor: (user && model.schema?.editors.includes(user?.id)) ?? false,
isStaff: user?.is_staff ?? false,
adminMode: adminMode
}),
[model.schema, setAccessLevel, model.isOwned, user, adminMode]
[model.schema, adjustRole, model.isOwned, user, adminMode]
);
const updateSchema = useCallback(

View File

@ -2,7 +2,6 @@
import { useParams } from 'react-router';
import { AccessModeState } from '@/context/AccessModeContext';
import { RSFormState } from '@/context/RSFormContext';
import useQueryStrings from '@/hooks/useQueryStrings';
@ -13,11 +12,9 @@ function RSFormPage() {
const query = useQueryStrings();
const version = query.get('v') ?? undefined;
return (
<AccessModeState>
<RSFormState itemID={params.id ?? ''} versionID={version}>
<RSTabs />
</RSFormState>
</AccessModeState>
<RSFormState itemID={params.id ?? ''} versionID={version}>
<RSTabs />
</RSFormState>
);
}

View File

@ -3,11 +3,11 @@
import clsx from 'clsx';
import { useState } from 'react';
import { useAccessMode } from '@/context/AccessModeContext';
import useWindowSize from '@/hooks/useWindowSize';
import { ConstituentaID, IConstituenta, IRSForm } from '@/models/rsform';
import { UserLevel } from '@/models/user';
import { UserRole } from '@/models/user';
import { useFitHeight } from '@/stores/appLayout';
import { useRoleStore } from '@/stores/role';
import { PARAMETER } from '@/utils/constants';
import ConstituentsSearch from './ConstituentsSearch';
@ -27,8 +27,8 @@ interface ViewConstituentsProps {
function ViewConstituents({ expression, schema, activeCst, isBottom, onOpenEdit, isMounted }: ViewConstituentsProps) {
const windowSize = useWindowSize();
const { accessLevel } = useAccessMode();
const listHeight = useFitHeight(!isBottom ? '8.2rem' : accessLevel !== UserLevel.READER ? '42rem' : '35rem', '10rem');
const role = useRoleStore(state => state.role);
const listHeight = useFitHeight(!isBottom ? '8.2rem' : role !== UserRole.READER ? '42rem' : '35rem', '10rem');
const [filteredData, setFilteredData] = useState<IConstituenta[]>(schema?.items ?? []);

View File

@ -0,0 +1,37 @@
import { create } from 'zustand';
import { UserRole } from '@/models/user';
export interface RoleFlags {
isOwner: boolean;
isEditor: boolean;
isStaff: boolean;
adminMode: boolean;
}
interface RoleStore {
role: UserRole;
setRole: (value: UserRole) => void;
adjustRole: (flags: RoleFlags) => void;
}
export const useRoleStore = create<RoleStore>()(set => ({
role: UserRole.READER,
setRole: value => set({ role: value }),
adjustRole: ({ isOwner, isEditor, isStaff, adminMode }: RoleFlags) =>
set(state => {
if (state.role === UserRole.EDITOR && (isOwner || isStaff || isEditor)) {
return { role: UserRole.EDITOR };
}
if (isStaff && (state.role === UserRole.ADMIN || adminMode)) {
return { role: UserRole.ADMIN };
}
if (isOwner) {
return { role: UserRole.OWNER };
}
if (isEditor) {
return { role: UserRole.EDITOR };
}
return { role: UserRole.READER };
})
}));

View File

@ -19,7 +19,7 @@ import {
RSErrorType,
TokenID
} from '@/models/rslang';
import { UserLevel } from '@/models/user';
import { UserRole } from '@/models/user';
import { PARAMETER } from './constants';
@ -822,31 +822,31 @@ export function describeSubstitutionError(error: ISubstitutionErrorDescription):
}
/**
* Retrieves label for {@link UserLevel}.
* Retrieves label for {@link UserRole}.
*/
export function labelAccessMode(mode: UserLevel): string {
export function labelAccessMode(mode: UserRole): string {
// prettier-ignore
switch (mode) {
case UserLevel.READER: return 'Читатель';
case UserLevel.EDITOR: return 'Редактор';
case UserLevel.OWNER: return 'Владелец';
case UserLevel.ADMIN: return 'Администратор';
case UserRole.READER: return 'Читатель';
case UserRole.EDITOR: return 'Редактор';
case UserRole.OWNER: return 'Владелец';
case UserRole.ADMIN: return 'Администратор';
}
}
/**
* Retrieves description for {@link UserLevel}.
* Retrieves description for {@link UserRole}.
*/
export function describeAccessMode(mode: UserLevel): string {
export function describeAccessMode(mode: UserRole): string {
// prettier-ignore
switch (mode) {
case UserLevel.READER:
case UserRole.READER:
return 'Режим запрещает редактирование';
case UserLevel.EDITOR:
case UserRole.EDITOR:
return 'Режим редактирования';
case UserLevel.OWNER:
case UserRole.OWNER:
return 'Режим владельца';
case UserLevel.ADMIN:
case UserRole.ADMIN:
return 'Режим администратора';
}
}