fixed stricts
This commit is contained in:
parent
97a164f682
commit
92bf11c809
14 changed files with 556 additions and 316 deletions
|
|
@ -2,7 +2,7 @@ import { useState, useEffect } from 'react';
|
|||
import { IoIosDownload } from 'react-icons/io';
|
||||
import { Popup, PopupAction } from '../UiComponents/Popup/Popup';
|
||||
import { useLanguage } from '../../providers/language/LanguageContext';
|
||||
import { PdfRenderer, PdfJsRenderer, LoadingRenderer, ErrorRenderer } from './renderers';
|
||||
import { PdfRenderer, LoadingRenderer } from './renderers';
|
||||
import styles from './ContentPreview.module.css';
|
||||
|
||||
export interface UrlContentPreviewProps {
|
||||
|
|
@ -64,11 +64,8 @@ export function UrlContentPreview({
|
|||
}
|
||||
};
|
||||
|
||||
const handlePdfLoad = () => {
|
||||
setIsLoading(false);
|
||||
setHasLoaded(true);
|
||||
setError(null);
|
||||
};
|
||||
// PDF load is handled by the PdfRenderer's onError callback;
|
||||
// successful load is implicit when no error occurs.
|
||||
|
||||
const handlePdfError = () => {
|
||||
// Try PDF.js as fallback instead of showing error immediately
|
||||
|
|
@ -208,7 +205,6 @@ export function UrlContentPreview({
|
|||
previewUrl={url}
|
||||
fileName={fileName}
|
||||
onError={handlePdfError}
|
||||
onLoad={handlePdfLoad}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
export { ContentPreview } from './ContentPreview';
|
||||
export type { ContentPreviewProps } from './ContentPreview';
|
||||
export { UrlContentPreview } from './UrlContentPreview';
|
||||
export type { UrlContentPreviewProps } from './UrlContentPreview';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { useEffect, useRef, useState } from 'react';
|
||||
// @ts-ignore
|
||||
import * as pdfjsLib from 'pdfjs-dist';
|
||||
import styles from '../ContentPreview.module.css';
|
||||
|
||||
|
|
@ -23,7 +24,7 @@ interface PdfJsRendererProps {
|
|||
onLoad?: () => void;
|
||||
}
|
||||
|
||||
export function PdfJsRenderer({ previewUrl, fileName, onError, onLoad }: PdfJsRendererProps) {
|
||||
export function PdfJsRenderer({ previewUrl, fileName: _fileName, onError, onLoad }: PdfJsRendererProps) {
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
||||
import TextField, { BaseTextFieldProps } from '../TextField/TextField';
|
||||
import TextField from '../TextField/TextField';
|
||||
import { BaseTextFieldProps } from '../TextField/TextFieldTypes';
|
||||
import { autocompleteAddress, AddressSuggestion } from '../../../api/realEstateApi';
|
||||
import styles from './AddressAutocomplete.module.css';
|
||||
|
||||
interface AddressAutocompleteProps extends BaseTextFieldProps {
|
||||
onSelect?: (suggestion: AddressSuggestion) => void;
|
||||
onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
||||
debounceMs?: number;
|
||||
minQueryLength?: number;
|
||||
maxSuggestions?: number;
|
||||
|
|
|
|||
1
src/components/UiComponents/OerebSection/index.ts
Normal file
1
src/components/UiComponents/OerebSection/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { OerebSection } from './OerebSection';
|
||||
|
|
@ -414,7 +414,7 @@ const ParcelInfoPanel: React.FC<ParcelInfoPanelProps> = ({
|
|||
<div className={styles.documentsSection}>
|
||||
<h4 className={styles.documentsSectionTitle}>Dokumente ({parcelData.documents.length})</h4>
|
||||
<div className={styles.documentsList}>
|
||||
{parcelData.documents.map((document) => (
|
||||
{parcelData.documents.map((document: any) => (
|
||||
<button
|
||||
key={document.id}
|
||||
className={styles.documentLink}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useApiRequest } from './useApi';
|
||||
import { getUserDataCache } from '../utils/userCache';
|
||||
import api from '../api';
|
||||
import { usePermissions, type UserPermissions } from './usePermissions';
|
||||
import { useInstanceId } from './useCurrentInstance';
|
||||
import {
|
||||
fetchAccess as fetchAccessApi,
|
||||
fetchAccessById as fetchAccessByIdApi,
|
||||
|
|
@ -10,15 +10,38 @@ import {
|
|||
updateAccess as updateAccessApi,
|
||||
deleteAccess as deleteAccessApi,
|
||||
type TrusteeAccess,
|
||||
type AttributeDefinition,
|
||||
type PaginationParams
|
||||
} from '../api/trusteeApi';
|
||||
|
||||
export interface AttributeDefinition {
|
||||
name: string;
|
||||
type: 'text' | 'email' | 'date' | 'checkbox' | 'select' | 'multiselect' | 'number' | 'textarea' | 'timestamp' | 'file';
|
||||
label: string;
|
||||
description?: string;
|
||||
required?: boolean;
|
||||
default?: any;
|
||||
options?: any[] | string;
|
||||
readonly?: boolean;
|
||||
editable?: boolean;
|
||||
visible?: boolean;
|
||||
order?: number;
|
||||
sortable?: boolean;
|
||||
filterable?: boolean;
|
||||
searchable?: boolean;
|
||||
width?: number;
|
||||
minWidth?: number;
|
||||
maxWidth?: number;
|
||||
filterOptions?: string[];
|
||||
dependsOn?: string;
|
||||
}
|
||||
|
||||
// Re-export types
|
||||
export type { TrusteeAccess, AttributeDefinition, PaginationParams };
|
||||
export type { TrusteeAccess, PaginationParams };
|
||||
|
||||
// Access list hook
|
||||
export function useTrusteeAccess() {
|
||||
const instanceId = useInstanceId();
|
||||
|
||||
const [accessRecords, setAccessRecords] = useState<TrusteeAccess[]>([]);
|
||||
const [attributes, setAttributes] = useState<AttributeDefinition[]>([]);
|
||||
const [permissions, setPermissions] = useState<UserPermissions | null>(null);
|
||||
|
|
@ -33,8 +56,10 @@ export function useTrusteeAccess() {
|
|||
|
||||
// Fetch attributes from backend
|
||||
const fetchAttributes = useCallback(async () => {
|
||||
if (!instanceId) return [];
|
||||
|
||||
try {
|
||||
const response = await api.get('/api/attributes/TrusteeAccess');
|
||||
const response = await api.get(`/api/trustee/${instanceId}/attributes/TrusteeAccess`);
|
||||
|
||||
let attrs: AttributeDefinition[] = [];
|
||||
if (response.data?.attributes && Array.isArray(response.data.attributes)) {
|
||||
|
|
@ -58,12 +83,13 @@ export function useTrusteeAccess() {
|
|||
setAttributes([]);
|
||||
return [];
|
||||
}
|
||||
}, []);
|
||||
}, [instanceId]);
|
||||
|
||||
// Fetch permissions from backend
|
||||
const fetchPermissions = useCallback(async () => {
|
||||
try {
|
||||
const perms = await checkPermission('DATA', 'trustee.access');
|
||||
const objectKey = 'data.feature.trustee.TrusteeAccess';
|
||||
const perms = await checkPermission('DATA', objectKey);
|
||||
setPermissions(perms);
|
||||
return perms;
|
||||
} catch (error: any) {
|
||||
|
|
@ -81,8 +107,13 @@ export function useTrusteeAccess() {
|
|||
}, [checkPermission]);
|
||||
|
||||
const fetchAccess = useCallback(async (params?: PaginationParams) => {
|
||||
if (!instanceId) {
|
||||
setAccessRecords([]);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const data = await fetchAccessApi(request, params);
|
||||
const data = await fetchAccessApi(request, instanceId, params);
|
||||
|
||||
if (data && typeof data === 'object' && 'items' in data) {
|
||||
const items = Array.isArray(data.items) ? data.items : [];
|
||||
|
|
@ -99,7 +130,7 @@ export function useTrusteeAccess() {
|
|||
setAccessRecords([]);
|
||||
setPagination(null);
|
||||
}
|
||||
}, [request]);
|
||||
}, [request, instanceId]);
|
||||
|
||||
// Optimistically remove an access record
|
||||
const removeOptimistically = (accessId: string) => {
|
||||
|
|
@ -119,8 +150,9 @@ export function useTrusteeAccess() {
|
|||
|
||||
// Fetch a single access record by ID
|
||||
const fetchAccessById = useCallback(async (accessId: string): Promise<TrusteeAccess | null> => {
|
||||
return await fetchAccessByIdApi(request, accessId);
|
||||
}, [request]);
|
||||
if (!instanceId) return null;
|
||||
return await fetchAccessByIdApi(request, instanceId, accessId);
|
||||
}, [request, instanceId]);
|
||||
|
||||
// Generate edit fields from attributes dynamically
|
||||
const generateEditFieldsFromAttributes = useCallback((): Array<{
|
||||
|
|
@ -161,7 +193,7 @@ export function useTrusteeAccess() {
|
|||
} else if (attr.type === 'select') {
|
||||
fieldType = 'enum';
|
||||
if (Array.isArray(attr.options)) {
|
||||
options = attr.options.map(opt => {
|
||||
options = attr.options.map((opt: any) => {
|
||||
const labelValue = typeof opt.label === 'string'
|
||||
? opt.label
|
||||
: opt.label?.en || opt.label?.[Object.keys(opt.label)[0]] || String(opt.value);
|
||||
|
|
@ -223,16 +255,14 @@ export function useTrusteeAccess() {
|
|||
return fetchedAttributes;
|
||||
}, [attributes, fetchAttributes]);
|
||||
|
||||
// Fetch attributes and permissions on mount
|
||||
// Fetch data when instanceId is available
|
||||
useEffect(() => {
|
||||
fetchAttributes();
|
||||
fetchPermissions();
|
||||
}, [fetchAttributes, fetchPermissions]);
|
||||
|
||||
// Initial fetch
|
||||
useEffect(() => {
|
||||
fetchAccess();
|
||||
}, [fetchAccess]);
|
||||
if (instanceId) {
|
||||
fetchAttributes();
|
||||
fetchPermissions();
|
||||
fetchAccess();
|
||||
}
|
||||
}, [instanceId, fetchAttributes, fetchPermissions, fetchAccess]);
|
||||
|
||||
return {
|
||||
accessRecords,
|
||||
|
|
@ -246,12 +276,15 @@ export function useTrusteeAccess() {
|
|||
pagination,
|
||||
fetchAccessById,
|
||||
generateEditFieldsFromAttributes,
|
||||
ensureAttributesLoaded
|
||||
ensureAttributesLoaded,
|
||||
instanceId
|
||||
};
|
||||
}
|
||||
|
||||
// Access operations hook
|
||||
export function useTrusteeAccessOperations() {
|
||||
const instanceId = useInstanceId();
|
||||
|
||||
const [deletingAccess, setDeletingAccess] = useState<Set<string>>(new Set());
|
||||
const [creatingAccess, setCreatingAccess] = useState(false);
|
||||
const { request, isLoading } = useApiRequest();
|
||||
|
|
@ -260,11 +293,16 @@ export function useTrusteeAccessOperations() {
|
|||
const [updateError, setUpdateError] = useState<string | null>(null);
|
||||
|
||||
const handleAccessDelete = async (accessId: string) => {
|
||||
if (!instanceId) {
|
||||
setDeleteError('No instance context');
|
||||
return false;
|
||||
}
|
||||
|
||||
setDeleteError(null);
|
||||
setDeletingAccess(prev => new Set(prev).add(accessId));
|
||||
|
||||
try {
|
||||
await deleteAccessApi(request, accessId);
|
||||
await deleteAccessApi(request, instanceId, accessId);
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
return true;
|
||||
} catch (error: any) {
|
||||
|
|
@ -280,20 +318,16 @@ export function useTrusteeAccessOperations() {
|
|||
};
|
||||
|
||||
const handleAccessCreate = async (accessData: Partial<TrusteeAccess>) => {
|
||||
if (!instanceId) {
|
||||
setCreateError('No instance context');
|
||||
return { success: false, error: 'No instance context' };
|
||||
}
|
||||
|
||||
setCreateError(null);
|
||||
setCreatingAccess(true);
|
||||
|
||||
try {
|
||||
const currentUserData = getUserDataCache();
|
||||
const mandateId = currentUserData?.mandateId || '';
|
||||
|
||||
const requestBody = {
|
||||
...accessData,
|
||||
mandate: mandateId
|
||||
};
|
||||
|
||||
const newAccess = await createAccessApi(request, requestBody);
|
||||
|
||||
const newAccess = await createAccessApi(request, instanceId, accessData);
|
||||
return { success: true, accessData: newAccess };
|
||||
} catch (error: any) {
|
||||
setCreateError(error.message);
|
||||
|
|
@ -308,19 +342,15 @@ export function useTrusteeAccessOperations() {
|
|||
updateData: Partial<TrusteeAccess>,
|
||||
_originalData?: any
|
||||
) => {
|
||||
if (!instanceId) {
|
||||
setUpdateError('No instance context');
|
||||
return { success: false, error: 'No instance context' };
|
||||
}
|
||||
|
||||
setUpdateError(null);
|
||||
|
||||
try {
|
||||
const currentUserData = getUserDataCache();
|
||||
const mandateId = currentUserData?.mandateId || '';
|
||||
|
||||
const requestBody = {
|
||||
...updateData,
|
||||
mandate: mandateId
|
||||
};
|
||||
|
||||
const updatedAccess = await updateAccessApi(request, accessId, requestBody);
|
||||
|
||||
const updatedAccess = await updateAccessApi(request, instanceId, accessId, updateData);
|
||||
return { success: true, accessData: updatedAccess };
|
||||
} catch (error: any) {
|
||||
const errorMessage = error.response?.data?.message || error.message || 'Failed to update access';
|
||||
|
|
@ -347,6 +377,7 @@ export function useTrusteeAccessOperations() {
|
|||
handleAccessDelete,
|
||||
handleAccessCreate,
|
||||
handleAccessUpdate,
|
||||
isLoading
|
||||
isLoading,
|
||||
instanceId
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useApiRequest } from './useApi';
|
||||
import { getUserDataCache } from '../utils/userCache';
|
||||
import api from '../api';
|
||||
import { usePermissions, type UserPermissions } from './usePermissions';
|
||||
import { useInstanceId } from './useCurrentInstance';
|
||||
import {
|
||||
fetchContracts as fetchContractsApi,
|
||||
fetchContractById as fetchContractByIdApi,
|
||||
|
|
@ -10,15 +10,38 @@ import {
|
|||
updateContract as updateContractApi,
|
||||
deleteContract as deleteContractApi,
|
||||
type TrusteeContract,
|
||||
type AttributeDefinition,
|
||||
type PaginationParams
|
||||
} from '../api/trusteeApi';
|
||||
|
||||
export interface AttributeDefinition {
|
||||
name: string;
|
||||
type: 'text' | 'email' | 'date' | 'checkbox' | 'select' | 'multiselect' | 'number' | 'textarea' | 'timestamp' | 'file';
|
||||
label: string;
|
||||
description?: string;
|
||||
required?: boolean;
|
||||
default?: any;
|
||||
options?: any[] | string;
|
||||
readonly?: boolean;
|
||||
editable?: boolean;
|
||||
visible?: boolean;
|
||||
order?: number;
|
||||
sortable?: boolean;
|
||||
filterable?: boolean;
|
||||
searchable?: boolean;
|
||||
width?: number;
|
||||
minWidth?: number;
|
||||
maxWidth?: number;
|
||||
filterOptions?: string[];
|
||||
dependsOn?: string;
|
||||
}
|
||||
|
||||
// Re-export types
|
||||
export type { TrusteeContract, AttributeDefinition, PaginationParams };
|
||||
export type { TrusteeContract, PaginationParams };
|
||||
|
||||
// Contracts list hook
|
||||
export function useTrusteeContracts() {
|
||||
const instanceId = useInstanceId();
|
||||
|
||||
const [contracts, setContracts] = useState<TrusteeContract[]>([]);
|
||||
const [attributes, setAttributes] = useState<AttributeDefinition[]>([]);
|
||||
const [permissions, setPermissions] = useState<UserPermissions | null>(null);
|
||||
|
|
@ -33,8 +56,10 @@ export function useTrusteeContracts() {
|
|||
|
||||
// Fetch attributes from backend
|
||||
const fetchAttributes = useCallback(async () => {
|
||||
if (!instanceId) return [];
|
||||
|
||||
try {
|
||||
const response = await api.get('/api/attributes/TrusteeContract');
|
||||
const response = await api.get(`/api/trustee/${instanceId}/attributes/TrusteeContract`);
|
||||
|
||||
let attrs: AttributeDefinition[] = [];
|
||||
if (response.data?.attributes && Array.isArray(response.data.attributes)) {
|
||||
|
|
@ -58,12 +83,13 @@ export function useTrusteeContracts() {
|
|||
setAttributes([]);
|
||||
return [];
|
||||
}
|
||||
}, []);
|
||||
}, [instanceId]);
|
||||
|
||||
// Fetch permissions from backend
|
||||
const fetchPermissions = useCallback(async () => {
|
||||
try {
|
||||
const perms = await checkPermission('DATA', 'trustee.contract');
|
||||
const objectKey = 'data.feature.trustee.TrusteeContract';
|
||||
const perms = await checkPermission('DATA', objectKey);
|
||||
setPermissions(perms);
|
||||
return perms;
|
||||
} catch (error: any) {
|
||||
|
|
@ -81,8 +107,13 @@ export function useTrusteeContracts() {
|
|||
}, [checkPermission]);
|
||||
|
||||
const fetchContracts = useCallback(async (params?: PaginationParams) => {
|
||||
if (!instanceId) {
|
||||
setContracts([]);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const data = await fetchContractsApi(request, params);
|
||||
const data = await fetchContractsApi(request, instanceId, params);
|
||||
|
||||
if (data && typeof data === 'object' && 'items' in data) {
|
||||
const items = Array.isArray(data.items) ? data.items : [];
|
||||
|
|
@ -99,7 +130,7 @@ export function useTrusteeContracts() {
|
|||
setContracts([]);
|
||||
setPagination(null);
|
||||
}
|
||||
}, [request]);
|
||||
}, [request, instanceId]);
|
||||
|
||||
// Optimistically remove a contract
|
||||
const removeOptimistically = (contractId: string) => {
|
||||
|
|
@ -119,8 +150,9 @@ export function useTrusteeContracts() {
|
|||
|
||||
// Fetch a single contract by ID
|
||||
const fetchContractById = useCallback(async (contractId: string): Promise<TrusteeContract | null> => {
|
||||
return await fetchContractByIdApi(request, contractId);
|
||||
}, [request]);
|
||||
if (!instanceId) return null;
|
||||
return await fetchContractByIdApi(request, instanceId, contractId);
|
||||
}, [request, instanceId]);
|
||||
|
||||
// Generate edit fields from attributes dynamically
|
||||
const generateEditFieldsFromAttributes = useCallback((): Array<{
|
||||
|
|
@ -161,7 +193,7 @@ export function useTrusteeContracts() {
|
|||
} else if (attr.type === 'select') {
|
||||
fieldType = 'enum';
|
||||
if (Array.isArray(attr.options)) {
|
||||
options = attr.options.map(opt => {
|
||||
options = attr.options.map((opt: any) => {
|
||||
const labelValue = typeof opt.label === 'string'
|
||||
? opt.label
|
||||
: opt.label?.en || opt.label?.[Object.keys(opt.label)[0]] || String(opt.value);
|
||||
|
|
@ -231,16 +263,14 @@ export function useTrusteeContracts() {
|
|||
return fetchedAttributes;
|
||||
}, [attributes, fetchAttributes]);
|
||||
|
||||
// Fetch attributes and permissions on mount
|
||||
// Fetch data when instanceId is available
|
||||
useEffect(() => {
|
||||
fetchAttributes();
|
||||
fetchPermissions();
|
||||
}, [fetchAttributes, fetchPermissions]);
|
||||
|
||||
// Initial fetch
|
||||
useEffect(() => {
|
||||
fetchContracts();
|
||||
}, [fetchContracts]);
|
||||
if (instanceId) {
|
||||
fetchAttributes();
|
||||
fetchPermissions();
|
||||
fetchContracts();
|
||||
}
|
||||
}, [instanceId, fetchAttributes, fetchPermissions, fetchContracts]);
|
||||
|
||||
return {
|
||||
contracts,
|
||||
|
|
@ -254,12 +284,15 @@ export function useTrusteeContracts() {
|
|||
pagination,
|
||||
fetchContractById,
|
||||
generateEditFieldsFromAttributes,
|
||||
ensureAttributesLoaded
|
||||
ensureAttributesLoaded,
|
||||
instanceId
|
||||
};
|
||||
}
|
||||
|
||||
// Contract operations hook
|
||||
export function useTrusteeContractOperations() {
|
||||
const instanceId = useInstanceId();
|
||||
|
||||
const [deletingContracts, setDeletingContracts] = useState<Set<string>>(new Set());
|
||||
const [creatingContract, setCreatingContract] = useState(false);
|
||||
const { request, isLoading } = useApiRequest();
|
||||
|
|
@ -268,11 +301,16 @@ export function useTrusteeContractOperations() {
|
|||
const [updateError, setUpdateError] = useState<string | null>(null);
|
||||
|
||||
const handleContractDelete = async (contractId: string) => {
|
||||
if (!instanceId) {
|
||||
setDeleteError('No instance context');
|
||||
return false;
|
||||
}
|
||||
|
||||
setDeleteError(null);
|
||||
setDeletingContracts(prev => new Set(prev).add(contractId));
|
||||
|
||||
try {
|
||||
await deleteContractApi(request, contractId);
|
||||
await deleteContractApi(request, instanceId, contractId);
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
return true;
|
||||
} catch (error: any) {
|
||||
|
|
@ -288,20 +326,16 @@ export function useTrusteeContractOperations() {
|
|||
};
|
||||
|
||||
const handleContractCreate = async (contractData: Partial<TrusteeContract>) => {
|
||||
if (!instanceId) {
|
||||
setCreateError('No instance context');
|
||||
return { success: false, error: 'No instance context' };
|
||||
}
|
||||
|
||||
setCreateError(null);
|
||||
setCreatingContract(true);
|
||||
|
||||
try {
|
||||
const currentUserData = getUserDataCache();
|
||||
const mandateId = currentUserData?.mandateId || '';
|
||||
|
||||
const requestBody = {
|
||||
...contractData,
|
||||
mandate: mandateId
|
||||
};
|
||||
|
||||
const newContract = await createContractApi(request, requestBody);
|
||||
|
||||
const newContract = await createContractApi(request, instanceId, contractData);
|
||||
return { success: true, contractData: newContract };
|
||||
} catch (error: any) {
|
||||
setCreateError(error.message);
|
||||
|
|
@ -316,21 +350,15 @@ export function useTrusteeContractOperations() {
|
|||
updateData: Partial<TrusteeContract>,
|
||||
_originalData?: any
|
||||
) => {
|
||||
if (!instanceId) {
|
||||
setUpdateError('No instance context');
|
||||
return { success: false, error: 'No instance context' };
|
||||
}
|
||||
|
||||
setUpdateError(null);
|
||||
|
||||
try {
|
||||
const currentUserData = getUserDataCache();
|
||||
const mandateId = currentUserData?.mandateId || '';
|
||||
|
||||
// Note: organisationId should NOT be included in update if immutable
|
||||
// Backend will reject if organisationId is changed
|
||||
const requestBody = {
|
||||
...updateData,
|
||||
mandate: mandateId
|
||||
};
|
||||
|
||||
const updatedContract = await updateContractApi(request, contractId, requestBody);
|
||||
|
||||
const updatedContract = await updateContractApi(request, instanceId, contractId, updateData);
|
||||
return { success: true, contractData: updatedContract };
|
||||
} catch (error: any) {
|
||||
const errorMessage = error.response?.data?.message || error.message || 'Failed to update contract';
|
||||
|
|
@ -357,6 +385,7 @@ export function useTrusteeContractOperations() {
|
|||
handleContractDelete,
|
||||
handleContractCreate,
|
||||
handleContractUpdate,
|
||||
isLoading
|
||||
isLoading,
|
||||
instanceId
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,47 @@
|
|||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useApiRequest } from './useApi';
|
||||
import { getUserDataCache } from '../utils/userCache';
|
||||
import api from '../api';
|
||||
import { usePermissions, type UserPermissions } from './usePermissions';
|
||||
import { useInstanceId } from './useCurrentInstance';
|
||||
import {
|
||||
fetchDocuments as fetchDocumentsApi,
|
||||
fetchDocumentById as fetchDocumentByIdApi,
|
||||
createDocument as createDocumentApi,
|
||||
updateDocument as updateDocumentApi,
|
||||
deleteDocument as deleteDocumentApi,
|
||||
downloadDocumentData as downloadDocumentDataApi,
|
||||
type TrusteeDocument,
|
||||
type AttributeDefinition,
|
||||
type PaginationParams
|
||||
} from '../api/trusteeApi';
|
||||
|
||||
export interface AttributeDefinition {
|
||||
name: string;
|
||||
type: 'text' | 'email' | 'date' | 'checkbox' | 'select' | 'multiselect' | 'number' | 'textarea' | 'timestamp' | 'file';
|
||||
label: string;
|
||||
description?: string;
|
||||
required?: boolean;
|
||||
default?: any;
|
||||
options?: any[] | string;
|
||||
readonly?: boolean;
|
||||
editable?: boolean;
|
||||
visible?: boolean;
|
||||
order?: number;
|
||||
sortable?: boolean;
|
||||
filterable?: boolean;
|
||||
searchable?: boolean;
|
||||
width?: number;
|
||||
minWidth?: number;
|
||||
maxWidth?: number;
|
||||
filterOptions?: string[];
|
||||
dependsOn?: string;
|
||||
}
|
||||
|
||||
// Re-export types
|
||||
export type { TrusteeDocument, AttributeDefinition, PaginationParams };
|
||||
export type { TrusteeDocument, PaginationParams };
|
||||
|
||||
// Documents list hook
|
||||
export function useTrusteeDocuments() {
|
||||
const instanceId = useInstanceId();
|
||||
|
||||
const [documents, setDocuments] = useState<TrusteeDocument[]>([]);
|
||||
const [attributes, setAttributes] = useState<AttributeDefinition[]>([]);
|
||||
const [permissions, setPermissions] = useState<UserPermissions | null>(null);
|
||||
|
|
@ -34,8 +56,10 @@ export function useTrusteeDocuments() {
|
|||
|
||||
// Fetch attributes from backend
|
||||
const fetchAttributes = useCallback(async () => {
|
||||
if (!instanceId) return [];
|
||||
|
||||
try {
|
||||
const response = await api.get('/api/attributes/TrusteeDocument');
|
||||
const response = await api.get(`/api/trustee/${instanceId}/attributes/TrusteeDocument`);
|
||||
|
||||
let attrs: AttributeDefinition[] = [];
|
||||
if (response.data?.attributes && Array.isArray(response.data.attributes)) {
|
||||
|
|
@ -59,12 +83,13 @@ export function useTrusteeDocuments() {
|
|||
setAttributes([]);
|
||||
return [];
|
||||
}
|
||||
}, []);
|
||||
}, [instanceId]);
|
||||
|
||||
// Fetch permissions from backend
|
||||
const fetchPermissions = useCallback(async () => {
|
||||
try {
|
||||
const perms = await checkPermission('DATA', 'trustee.document');
|
||||
const objectKey = 'data.feature.trustee.TrusteeDocument';
|
||||
const perms = await checkPermission('DATA', objectKey);
|
||||
setPermissions(perms);
|
||||
return perms;
|
||||
} catch (error: any) {
|
||||
|
|
@ -82,8 +107,13 @@ export function useTrusteeDocuments() {
|
|||
}, [checkPermission]);
|
||||
|
||||
const fetchDocuments = useCallback(async (params?: PaginationParams) => {
|
||||
if (!instanceId) {
|
||||
setDocuments([]);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const data = await fetchDocumentsApi(request, params);
|
||||
const data = await fetchDocumentsApi(request, instanceId, params);
|
||||
|
||||
if (data && typeof data === 'object' && 'items' in data) {
|
||||
const items = Array.isArray(data.items) ? data.items : [];
|
||||
|
|
@ -100,7 +130,7 @@ export function useTrusteeDocuments() {
|
|||
setDocuments([]);
|
||||
setPagination(null);
|
||||
}
|
||||
}, [request]);
|
||||
}, [request, instanceId]);
|
||||
|
||||
// Optimistically remove a document
|
||||
const removeOptimistically = (documentId: string) => {
|
||||
|
|
@ -120,8 +150,9 @@ export function useTrusteeDocuments() {
|
|||
|
||||
// Fetch a single document by ID
|
||||
const fetchDocumentById = useCallback(async (documentId: string): Promise<TrusteeDocument | null> => {
|
||||
return await fetchDocumentByIdApi(request, documentId);
|
||||
}, [request]);
|
||||
if (!instanceId) return null;
|
||||
return await fetchDocumentByIdApi(request, instanceId, documentId);
|
||||
}, [request, instanceId]);
|
||||
|
||||
// Generate edit fields from attributes dynamically
|
||||
const generateEditFieldsFromAttributes = useCallback((): Array<{
|
||||
|
|
@ -163,7 +194,7 @@ export function useTrusteeDocuments() {
|
|||
} else if (attr.type === 'select') {
|
||||
fieldType = 'enum';
|
||||
if (Array.isArray(attr.options)) {
|
||||
options = attr.options.map(opt => {
|
||||
options = attr.options.map((opt: any) => {
|
||||
const labelValue = typeof opt.label === 'string'
|
||||
? opt.label
|
||||
: opt.label?.en || opt.label?.[Object.keys(opt.label)[0]] || String(opt.value);
|
||||
|
|
@ -222,16 +253,14 @@ export function useTrusteeDocuments() {
|
|||
return fetchedAttributes;
|
||||
}, [attributes, fetchAttributes]);
|
||||
|
||||
// Fetch attributes and permissions on mount
|
||||
// Fetch data when instanceId is available
|
||||
useEffect(() => {
|
||||
fetchAttributes();
|
||||
fetchPermissions();
|
||||
}, [fetchAttributes, fetchPermissions]);
|
||||
|
||||
// Initial fetch
|
||||
useEffect(() => {
|
||||
fetchDocuments();
|
||||
}, [fetchDocuments]);
|
||||
if (instanceId) {
|
||||
fetchAttributes();
|
||||
fetchPermissions();
|
||||
fetchDocuments();
|
||||
}
|
||||
}, [instanceId, fetchAttributes, fetchPermissions, fetchDocuments]);
|
||||
|
||||
return {
|
||||
documents,
|
||||
|
|
@ -245,12 +274,15 @@ export function useTrusteeDocuments() {
|
|||
pagination,
|
||||
fetchDocumentById,
|
||||
generateEditFieldsFromAttributes,
|
||||
ensureAttributesLoaded
|
||||
ensureAttributesLoaded,
|
||||
instanceId
|
||||
};
|
||||
}
|
||||
|
||||
// Document operations hook
|
||||
export function useTrusteeDocumentOperations() {
|
||||
const instanceId = useInstanceId();
|
||||
|
||||
const [deletingDocuments, setDeletingDocuments] = useState<Set<string>>(new Set());
|
||||
const [creatingDocument, setCreatingDocument] = useState(false);
|
||||
const [downloadingDocuments, setDownloadingDocuments] = useState<Set<string>>(new Set());
|
||||
|
|
@ -261,11 +293,16 @@ export function useTrusteeDocumentOperations() {
|
|||
const [downloadError, setDownloadError] = useState<string | null>(null);
|
||||
|
||||
const handleDocumentDelete = async (documentId: string) => {
|
||||
if (!instanceId) {
|
||||
setDeleteError('No instance context');
|
||||
return false;
|
||||
}
|
||||
|
||||
setDeleteError(null);
|
||||
setDeletingDocuments(prev => new Set(prev).add(documentId));
|
||||
|
||||
try {
|
||||
await deleteDocumentApi(request, documentId);
|
||||
await deleteDocumentApi(request, instanceId, documentId);
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
return true;
|
||||
} catch (error: any) {
|
||||
|
|
@ -280,18 +317,17 @@ export function useTrusteeDocumentOperations() {
|
|||
}
|
||||
};
|
||||
|
||||
const handleDocumentCreate = async (documentData: FormData) => {
|
||||
const handleDocumentCreate = async (documentData: Partial<TrusteeDocument>) => {
|
||||
if (!instanceId) {
|
||||
setCreateError('No instance context');
|
||||
return { success: false, error: 'No instance context' };
|
||||
}
|
||||
|
||||
setCreateError(null);
|
||||
setCreatingDocument(true);
|
||||
|
||||
try {
|
||||
const currentUserData = getUserDataCache();
|
||||
const mandateId = currentUserData?.mandateId || '';
|
||||
|
||||
documentData.append('mandate', mandateId);
|
||||
|
||||
const newDocument = await createDocumentApi(request, documentData);
|
||||
|
||||
const newDocument = await createDocumentApi(request, instanceId, documentData);
|
||||
return { success: true, documentData: newDocument };
|
||||
} catch (error: any) {
|
||||
setCreateError(error.message);
|
||||
|
|
@ -306,19 +342,15 @@ export function useTrusteeDocumentOperations() {
|
|||
updateData: Partial<TrusteeDocument>,
|
||||
_originalData?: any
|
||||
) => {
|
||||
if (!instanceId) {
|
||||
setUpdateError('No instance context');
|
||||
return { success: false, error: 'No instance context' };
|
||||
}
|
||||
|
||||
setUpdateError(null);
|
||||
|
||||
try {
|
||||
const currentUserData = getUserDataCache();
|
||||
const mandateId = currentUserData?.mandateId || '';
|
||||
|
||||
const requestBody = {
|
||||
...updateData,
|
||||
mandate: mandateId
|
||||
};
|
||||
|
||||
const updatedDocument = await updateDocumentApi(request, documentId, requestBody);
|
||||
|
||||
const updatedDocument = await updateDocumentApi(request, instanceId, documentId, updateData);
|
||||
return { success: true, documentData: updatedDocument };
|
||||
} catch (error: any) {
|
||||
const errorMessage = error.response?.data?.message || error.message || 'Failed to update document';
|
||||
|
|
@ -337,11 +369,28 @@ export function useTrusteeDocumentOperations() {
|
|||
};
|
||||
|
||||
const handleDocumentDownload = async (documentId: string, documentName: string) => {
|
||||
if (!instanceId) {
|
||||
setDownloadError('No instance context');
|
||||
return false;
|
||||
}
|
||||
|
||||
setDownloadError(null);
|
||||
setDownloadingDocuments(prev => new Set(prev).add(documentId));
|
||||
|
||||
try {
|
||||
const blob = await downloadDocumentDataApi(request, documentId);
|
||||
const doc = await fetchDocumentByIdApi(request, instanceId, documentId);
|
||||
if (!doc || !doc.documentData) {
|
||||
throw new Error('Document data not found');
|
||||
}
|
||||
|
||||
// Convert base64 to blob
|
||||
const byteCharacters = atob(doc.documentData);
|
||||
const byteNumbers = new Array(byteCharacters.length);
|
||||
for (let i = 0; i < byteCharacters.length; i++) {
|
||||
byteNumbers[i] = byteCharacters.charCodeAt(i);
|
||||
}
|
||||
const byteArray = new Uint8Array(byteNumbers);
|
||||
const blob = new Blob([byteArray], { type: doc.documentMimeType || 'application/octet-stream' });
|
||||
|
||||
// Create download link
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
|
|
@ -379,6 +428,7 @@ export function useTrusteeDocumentOperations() {
|
|||
handleDocumentCreate,
|
||||
handleDocumentUpdate,
|
||||
handleDocumentDownload,
|
||||
isLoading
|
||||
isLoading,
|
||||
instanceId
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useApiRequest } from './useApi';
|
||||
import { getUserDataCache } from '../utils/userCache';
|
||||
import api from '../api';
|
||||
import { usePermissions, type UserPermissions } from './usePermissions';
|
||||
import { useInstanceId } from './useCurrentInstance';
|
||||
import {
|
||||
fetchOrganisations as fetchOrganisationsApi,
|
||||
fetchOrganisationById as fetchOrganisationByIdApi,
|
||||
|
|
@ -10,15 +10,38 @@ import {
|
|||
updateOrganisation as updateOrganisationApi,
|
||||
deleteOrganisation as deleteOrganisationApi,
|
||||
type TrusteeOrganisation,
|
||||
type AttributeDefinition,
|
||||
type PaginationParams
|
||||
} from '../api/trusteeApi';
|
||||
|
||||
export interface AttributeDefinition {
|
||||
name: string;
|
||||
type: 'text' | 'email' | 'date' | 'checkbox' | 'select' | 'multiselect' | 'number' | 'textarea' | 'timestamp' | 'file';
|
||||
label: string;
|
||||
description?: string;
|
||||
required?: boolean;
|
||||
default?: any;
|
||||
options?: any[] | string;
|
||||
readonly?: boolean;
|
||||
editable?: boolean;
|
||||
visible?: boolean;
|
||||
order?: number;
|
||||
sortable?: boolean;
|
||||
filterable?: boolean;
|
||||
searchable?: boolean;
|
||||
width?: number;
|
||||
minWidth?: number;
|
||||
maxWidth?: number;
|
||||
filterOptions?: string[];
|
||||
dependsOn?: string;
|
||||
}
|
||||
|
||||
// Re-export types
|
||||
export type { TrusteeOrganisation, AttributeDefinition, PaginationParams };
|
||||
export type { TrusteeOrganisation, PaginationParams };
|
||||
|
||||
// Organisations list hook
|
||||
export function useTrusteeOrganisations() {
|
||||
const instanceId = useInstanceId();
|
||||
|
||||
const [organisations, setOrganisations] = useState<TrusteeOrganisation[]>([]);
|
||||
const [attributes, setAttributes] = useState<AttributeDefinition[]>([]);
|
||||
const [permissions, setPermissions] = useState<UserPermissions | null>(null);
|
||||
|
|
@ -33,8 +56,10 @@ export function useTrusteeOrganisations() {
|
|||
|
||||
// Fetch attributes from backend
|
||||
const fetchAttributes = useCallback(async () => {
|
||||
if (!instanceId) return [];
|
||||
|
||||
try {
|
||||
const response = await api.get('/api/attributes/TrusteeOrganisation');
|
||||
const response = await api.get(`/api/trustee/${instanceId}/attributes/TrusteeOrganisation`);
|
||||
|
||||
let attrs: AttributeDefinition[] = [];
|
||||
if (response.data?.attributes && Array.isArray(response.data.attributes)) {
|
||||
|
|
@ -58,12 +83,13 @@ export function useTrusteeOrganisations() {
|
|||
setAttributes([]);
|
||||
return [];
|
||||
}
|
||||
}, []);
|
||||
}, [instanceId]);
|
||||
|
||||
// Fetch permissions from backend
|
||||
const fetchPermissions = useCallback(async () => {
|
||||
try {
|
||||
const perms = await checkPermission('DATA', 'trustee.organisation');
|
||||
const objectKey = 'data.feature.trustee.TrusteeOrganisation';
|
||||
const perms = await checkPermission('DATA', objectKey);
|
||||
setPermissions(perms);
|
||||
return perms;
|
||||
} catch (error: any) {
|
||||
|
|
@ -81,8 +107,13 @@ export function useTrusteeOrganisations() {
|
|||
}, [checkPermission]);
|
||||
|
||||
const fetchOrganisations = useCallback(async (params?: PaginationParams) => {
|
||||
if (!instanceId) {
|
||||
setOrganisations([]);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const data = await fetchOrganisationsApi(request, params);
|
||||
const data = await fetchOrganisationsApi(request, instanceId, params);
|
||||
|
||||
if (data && typeof data === 'object' && 'items' in data) {
|
||||
const items = Array.isArray(data.items) ? data.items : [];
|
||||
|
|
@ -99,7 +130,7 @@ export function useTrusteeOrganisations() {
|
|||
setOrganisations([]);
|
||||
setPagination(null);
|
||||
}
|
||||
}, [request]);
|
||||
}, [request, instanceId]);
|
||||
|
||||
// Optimistically remove an organisation
|
||||
const removeOptimistically = (organisationId: string) => {
|
||||
|
|
@ -119,8 +150,9 @@ export function useTrusteeOrganisations() {
|
|||
|
||||
// Fetch a single organisation by ID
|
||||
const fetchOrganisationById = useCallback(async (organisationId: string): Promise<TrusteeOrganisation | null> => {
|
||||
return await fetchOrganisationByIdApi(request, organisationId);
|
||||
}, [request]);
|
||||
if (!instanceId) return null;
|
||||
return await fetchOrganisationByIdApi(request, instanceId, organisationId);
|
||||
}, [request, instanceId]);
|
||||
|
||||
// Generate edit fields from attributes dynamically
|
||||
const generateEditFieldsFromAttributes = useCallback((): Array<{
|
||||
|
|
@ -159,7 +191,7 @@ export function useTrusteeOrganisations() {
|
|||
} else if (attr.type === 'select') {
|
||||
fieldType = 'enum';
|
||||
if (Array.isArray(attr.options)) {
|
||||
options = attr.options.map(opt => {
|
||||
options = attr.options.map((opt: any) => {
|
||||
const labelValue = typeof opt.label === 'string'
|
||||
? opt.label
|
||||
: opt.label?.en || opt.label?.[Object.keys(opt.label)[0]] || String(opt.value);
|
||||
|
|
@ -174,7 +206,7 @@ export function useTrusteeOrganisations() {
|
|||
} else if (attr.type === 'multiselect') {
|
||||
fieldType = 'multiselect';
|
||||
if (Array.isArray(attr.options)) {
|
||||
options = attr.options.map(opt => {
|
||||
options = attr.options.map((opt: any) => {
|
||||
const labelValue = typeof opt.label === 'string'
|
||||
? opt.label
|
||||
: opt.label?.en || opt.label?.[Object.keys(opt.label)[0]] || String(opt.value);
|
||||
|
|
@ -239,16 +271,14 @@ export function useTrusteeOrganisations() {
|
|||
return fetchedAttributes;
|
||||
}, [attributes, fetchAttributes]);
|
||||
|
||||
// Fetch attributes and permissions on mount
|
||||
// Fetch data when instanceId is available
|
||||
useEffect(() => {
|
||||
fetchAttributes();
|
||||
fetchPermissions();
|
||||
}, [fetchAttributes, fetchPermissions]);
|
||||
|
||||
// Initial fetch
|
||||
useEffect(() => {
|
||||
fetchOrganisations();
|
||||
}, [fetchOrganisations]);
|
||||
if (instanceId) {
|
||||
fetchAttributes();
|
||||
fetchPermissions();
|
||||
fetchOrganisations();
|
||||
}
|
||||
}, [instanceId, fetchAttributes, fetchPermissions, fetchOrganisations]);
|
||||
|
||||
return {
|
||||
organisations,
|
||||
|
|
@ -262,12 +292,15 @@ export function useTrusteeOrganisations() {
|
|||
pagination,
|
||||
fetchOrganisationById,
|
||||
generateEditFieldsFromAttributes,
|
||||
ensureAttributesLoaded
|
||||
ensureAttributesLoaded,
|
||||
instanceId
|
||||
};
|
||||
}
|
||||
|
||||
// Organisation operations hook
|
||||
export function useTrusteeOrganisationOperations() {
|
||||
const instanceId = useInstanceId();
|
||||
|
||||
const [deletingOrganisations, setDeletingOrganisations] = useState<Set<string>>(new Set());
|
||||
const [creatingOrganisation, setCreatingOrganisation] = useState(false);
|
||||
const { request, isLoading } = useApiRequest();
|
||||
|
|
@ -276,11 +309,16 @@ export function useTrusteeOrganisationOperations() {
|
|||
const [updateError, setUpdateError] = useState<string | null>(null);
|
||||
|
||||
const handleOrganisationDelete = async (organisationId: string) => {
|
||||
if (!instanceId) {
|
||||
setDeleteError('No instance context');
|
||||
return false;
|
||||
}
|
||||
|
||||
setDeleteError(null);
|
||||
setDeletingOrganisations(prev => new Set(prev).add(organisationId));
|
||||
|
||||
try {
|
||||
await deleteOrganisationApi(request, organisationId);
|
||||
await deleteOrganisationApi(request, instanceId, organisationId);
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
return true;
|
||||
} catch (error: any) {
|
||||
|
|
@ -296,20 +334,16 @@ export function useTrusteeOrganisationOperations() {
|
|||
};
|
||||
|
||||
const handleOrganisationCreate = async (organisationData: Partial<TrusteeOrganisation>) => {
|
||||
if (!instanceId) {
|
||||
setCreateError('No instance context');
|
||||
return { success: false, error: 'No instance context' };
|
||||
}
|
||||
|
||||
setCreateError(null);
|
||||
setCreatingOrganisation(true);
|
||||
|
||||
try {
|
||||
const currentUserData = getUserDataCache();
|
||||
const mandateId = currentUserData?.mandateId || '';
|
||||
|
||||
const requestBody = {
|
||||
...organisationData,
|
||||
mandate: mandateId
|
||||
};
|
||||
|
||||
const newOrganisation = await createOrganisationApi(request, requestBody);
|
||||
|
||||
const newOrganisation = await createOrganisationApi(request, instanceId, organisationData);
|
||||
return { success: true, organisationData: newOrganisation };
|
||||
} catch (error: any) {
|
||||
setCreateError(error.message);
|
||||
|
|
@ -324,19 +358,15 @@ export function useTrusteeOrganisationOperations() {
|
|||
updateData: Partial<TrusteeOrganisation>,
|
||||
_originalData?: any
|
||||
) => {
|
||||
if (!instanceId) {
|
||||
setUpdateError('No instance context');
|
||||
return { success: false, error: 'No instance context' };
|
||||
}
|
||||
|
||||
setUpdateError(null);
|
||||
|
||||
try {
|
||||
const currentUserData = getUserDataCache();
|
||||
const mandateId = currentUserData?.mandateId || '';
|
||||
|
||||
const requestBody = {
|
||||
...updateData,
|
||||
mandate: mandateId
|
||||
};
|
||||
|
||||
const updatedOrganisation = await updateOrganisationApi(request, organisationId, requestBody);
|
||||
|
||||
const updatedOrganisation = await updateOrganisationApi(request, instanceId, organisationId, updateData);
|
||||
return { success: true, organisationData: updatedOrganisation };
|
||||
} catch (error: any) {
|
||||
const errorMessage = error.response?.data?.message || error.message || 'Failed to update organisation';
|
||||
|
|
@ -363,6 +393,7 @@ export function useTrusteeOrganisationOperations() {
|
|||
handleOrganisationDelete,
|
||||
handleOrganisationCreate,
|
||||
handleOrganisationUpdate,
|
||||
isLoading
|
||||
isLoading,
|
||||
instanceId
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,46 @@
|
|||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useApiRequest } from './useApi';
|
||||
import { getUserDataCache } from '../utils/userCache';
|
||||
import api from '../api';
|
||||
import { usePermissions, type UserPermissions } from './usePermissions';
|
||||
import { useInstanceId } from './useCurrentInstance';
|
||||
import {
|
||||
fetchPositionDocuments as fetchPositionDocumentsApi,
|
||||
fetchPositionDocumentById as fetchPositionDocumentByIdApi,
|
||||
createPositionDocument as createPositionDocumentApi,
|
||||
deletePositionDocument as deletePositionDocumentApi,
|
||||
type TrusteePositionDocument,
|
||||
type AttributeDefinition,
|
||||
type PaginationParams
|
||||
} from '../api/trusteeApi';
|
||||
|
||||
export interface AttributeDefinition {
|
||||
name: string;
|
||||
type: 'text' | 'email' | 'date' | 'checkbox' | 'select' | 'multiselect' | 'number' | 'textarea' | 'timestamp' | 'file';
|
||||
label: string;
|
||||
description?: string;
|
||||
required?: boolean;
|
||||
default?: any;
|
||||
options?: any[] | string;
|
||||
readonly?: boolean;
|
||||
editable?: boolean;
|
||||
visible?: boolean;
|
||||
order?: number;
|
||||
sortable?: boolean;
|
||||
filterable?: boolean;
|
||||
searchable?: boolean;
|
||||
width?: number;
|
||||
minWidth?: number;
|
||||
maxWidth?: number;
|
||||
filterOptions?: string[];
|
||||
dependsOn?: string;
|
||||
}
|
||||
|
||||
// Re-export types
|
||||
export type { TrusteePositionDocument, AttributeDefinition, PaginationParams };
|
||||
export type { TrusteePositionDocument, PaginationParams };
|
||||
|
||||
// Position-Documents list hook
|
||||
export function useTrusteePositionDocuments() {
|
||||
const instanceId = useInstanceId();
|
||||
|
||||
const [positionDocuments, setPositionDocuments] = useState<TrusteePositionDocument[]>([]);
|
||||
const [attributes, setAttributes] = useState<AttributeDefinition[]>([]);
|
||||
const [permissions, setPermissions] = useState<UserPermissions | null>(null);
|
||||
|
|
@ -32,8 +55,10 @@ export function useTrusteePositionDocuments() {
|
|||
|
||||
// Fetch attributes from backend
|
||||
const fetchAttributes = useCallback(async () => {
|
||||
if (!instanceId) return [];
|
||||
|
||||
try {
|
||||
const response = await api.get('/api/attributes/TrusteePositionDocument');
|
||||
const response = await api.get(`/api/trustee/${instanceId}/attributes/TrusteePositionDocument`);
|
||||
|
||||
let attrs: AttributeDefinition[] = [];
|
||||
if (response.data?.attributes && Array.isArray(response.data.attributes)) {
|
||||
|
|
@ -57,12 +82,13 @@ export function useTrusteePositionDocuments() {
|
|||
setAttributes([]);
|
||||
return [];
|
||||
}
|
||||
}, []);
|
||||
}, [instanceId]);
|
||||
|
||||
// Fetch permissions from backend
|
||||
const fetchPermissions = useCallback(async () => {
|
||||
try {
|
||||
const perms = await checkPermission('DATA', 'trustee.xpositiondocument');
|
||||
const objectKey = 'data.feature.trustee.TrusteePositionDocument';
|
||||
const perms = await checkPermission('DATA', objectKey);
|
||||
setPermissions(perms);
|
||||
return perms;
|
||||
} catch (error: any) {
|
||||
|
|
@ -80,8 +106,13 @@ export function useTrusteePositionDocuments() {
|
|||
}, [checkPermission]);
|
||||
|
||||
const fetchPositionDocuments = useCallback(async (params?: PaginationParams) => {
|
||||
if (!instanceId) {
|
||||
setPositionDocuments([]);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const data = await fetchPositionDocumentsApi(request, params);
|
||||
const data = await fetchPositionDocumentsApi(request, instanceId, params);
|
||||
|
||||
if (data && typeof data === 'object' && 'items' in data) {
|
||||
const items = Array.isArray(data.items) ? data.items : [];
|
||||
|
|
@ -98,7 +129,7 @@ export function useTrusteePositionDocuments() {
|
|||
setPositionDocuments([]);
|
||||
setPagination(null);
|
||||
}
|
||||
}, [request]);
|
||||
}, [request, instanceId]);
|
||||
|
||||
// Optimistically remove a position-document link
|
||||
const removeOptimistically = (positionDocumentId: string) => {
|
||||
|
|
@ -107,8 +138,9 @@ export function useTrusteePositionDocuments() {
|
|||
|
||||
// Fetch a single position-document by ID
|
||||
const fetchPositionDocumentById = useCallback(async (positionDocumentId: string): Promise<TrusteePositionDocument | null> => {
|
||||
return await fetchPositionDocumentByIdApi(request, positionDocumentId);
|
||||
}, [request]);
|
||||
if (!instanceId) return null;
|
||||
return await fetchPositionDocumentByIdApi(request, instanceId, positionDocumentId);
|
||||
}, [request, instanceId]);
|
||||
|
||||
// Generate edit fields from attributes dynamically
|
||||
const generateEditFieldsFromAttributes = useCallback((): Array<{
|
||||
|
|
@ -149,7 +181,7 @@ export function useTrusteePositionDocuments() {
|
|||
} else if (attr.type === 'select') {
|
||||
fieldType = 'enum';
|
||||
if (Array.isArray(attr.options)) {
|
||||
options = attr.options.map(opt => {
|
||||
options = attr.options.map((opt: any) => {
|
||||
const labelValue = typeof opt.label === 'string'
|
||||
? opt.label
|
||||
: opt.label?.en || opt.label?.[Object.keys(opt.label)[0]] || String(opt.value);
|
||||
|
|
@ -212,16 +244,14 @@ export function useTrusteePositionDocuments() {
|
|||
return fetchedAttributes;
|
||||
}, [attributes, fetchAttributes]);
|
||||
|
||||
// Fetch attributes and permissions on mount
|
||||
// Fetch data when instanceId is available
|
||||
useEffect(() => {
|
||||
fetchAttributes();
|
||||
fetchPermissions();
|
||||
}, [fetchAttributes, fetchPermissions]);
|
||||
|
||||
// Initial fetch
|
||||
useEffect(() => {
|
||||
fetchPositionDocuments();
|
||||
}, [fetchPositionDocuments]);
|
||||
if (instanceId) {
|
||||
fetchAttributes();
|
||||
fetchPermissions();
|
||||
fetchPositionDocuments();
|
||||
}
|
||||
}, [instanceId, fetchAttributes, fetchPermissions, fetchPositionDocuments]);
|
||||
|
||||
return {
|
||||
positionDocuments,
|
||||
|
|
@ -234,12 +264,15 @@ export function useTrusteePositionDocuments() {
|
|||
pagination,
|
||||
fetchPositionDocumentById,
|
||||
generateEditFieldsFromAttributes,
|
||||
ensureAttributesLoaded
|
||||
ensureAttributesLoaded,
|
||||
instanceId
|
||||
};
|
||||
}
|
||||
|
||||
// Position-Document operations hook
|
||||
export function useTrusteePositionDocumentOperations() {
|
||||
const instanceId = useInstanceId();
|
||||
|
||||
const [deletingPositionDocuments, setDeletingPositionDocuments] = useState<Set<string>>(new Set());
|
||||
const [creatingPositionDocument, setCreatingPositionDocument] = useState(false);
|
||||
const { request, isLoading } = useApiRequest();
|
||||
|
|
@ -247,11 +280,16 @@ export function useTrusteePositionDocumentOperations() {
|
|||
const [createError, setCreateError] = useState<string | null>(null);
|
||||
|
||||
const handlePositionDocumentDelete = async (positionDocumentId: string) => {
|
||||
if (!instanceId) {
|
||||
setDeleteError('No instance context');
|
||||
return false;
|
||||
}
|
||||
|
||||
setDeleteError(null);
|
||||
setDeletingPositionDocuments(prev => new Set(prev).add(positionDocumentId));
|
||||
|
||||
try {
|
||||
await deletePositionDocumentApi(request, positionDocumentId);
|
||||
await deletePositionDocumentApi(request, instanceId, positionDocumentId);
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
return true;
|
||||
} catch (error: any) {
|
||||
|
|
@ -267,20 +305,16 @@ export function useTrusteePositionDocumentOperations() {
|
|||
};
|
||||
|
||||
const handlePositionDocumentCreate = async (positionDocumentData: Partial<TrusteePositionDocument>) => {
|
||||
if (!instanceId) {
|
||||
setCreateError('No instance context');
|
||||
return { success: false, error: 'No instance context' };
|
||||
}
|
||||
|
||||
setCreateError(null);
|
||||
setCreatingPositionDocument(true);
|
||||
|
||||
try {
|
||||
const currentUserData = getUserDataCache();
|
||||
const mandateId = currentUserData?.mandateId || '';
|
||||
|
||||
const requestBody = {
|
||||
...positionDocumentData,
|
||||
mandate: mandateId
|
||||
};
|
||||
|
||||
const newPositionDocument = await createPositionDocumentApi(request, requestBody);
|
||||
|
||||
const newPositionDocument = await createPositionDocumentApi(request, instanceId, positionDocumentData);
|
||||
return { success: true, positionDocumentData: newPositionDocument };
|
||||
} catch (error: any) {
|
||||
setCreateError(error.message);
|
||||
|
|
@ -297,6 +331,7 @@ export function useTrusteePositionDocumentOperations() {
|
|||
createError,
|
||||
handlePositionDocumentDelete,
|
||||
handlePositionDocumentCreate,
|
||||
isLoading
|
||||
isLoading,
|
||||
instanceId
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useApiRequest } from './useApi';
|
||||
import { getUserDataCache } from '../utils/userCache';
|
||||
import api from '../api';
|
||||
import { usePermissions, type UserPermissions } from './usePermissions';
|
||||
import { useInstanceId } from './useCurrentInstance';
|
||||
import {
|
||||
fetchPositions as fetchPositionsApi,
|
||||
fetchPositionById as fetchPositionByIdApi,
|
||||
|
|
@ -10,15 +10,38 @@ import {
|
|||
updatePosition as updatePositionApi,
|
||||
deletePosition as deletePositionApi,
|
||||
type TrusteePosition,
|
||||
type AttributeDefinition,
|
||||
type PaginationParams
|
||||
} from '../api/trusteeApi';
|
||||
|
||||
export interface AttributeDefinition {
|
||||
name: string;
|
||||
type: 'text' | 'email' | 'date' | 'checkbox' | 'select' | 'multiselect' | 'number' | 'textarea' | 'timestamp' | 'file';
|
||||
label: string;
|
||||
description?: string;
|
||||
required?: boolean;
|
||||
default?: any;
|
||||
options?: any[] | string;
|
||||
readonly?: boolean;
|
||||
editable?: boolean;
|
||||
visible?: boolean;
|
||||
order?: number;
|
||||
sortable?: boolean;
|
||||
filterable?: boolean;
|
||||
searchable?: boolean;
|
||||
width?: number;
|
||||
minWidth?: number;
|
||||
maxWidth?: number;
|
||||
filterOptions?: string[];
|
||||
dependsOn?: string;
|
||||
}
|
||||
|
||||
// Re-export types
|
||||
export type { TrusteePosition, AttributeDefinition, PaginationParams };
|
||||
export type { TrusteePosition, PaginationParams };
|
||||
|
||||
// Positions list hook
|
||||
export function useTrusteePositions() {
|
||||
const instanceId = useInstanceId();
|
||||
|
||||
const [positions, setPositions] = useState<TrusteePosition[]>([]);
|
||||
const [attributes, setAttributes] = useState<AttributeDefinition[]>([]);
|
||||
const [permissions, setPermissions] = useState<UserPermissions | null>(null);
|
||||
|
|
@ -33,8 +56,10 @@ export function useTrusteePositions() {
|
|||
|
||||
// Fetch attributes from backend
|
||||
const fetchAttributes = useCallback(async () => {
|
||||
if (!instanceId) return [];
|
||||
|
||||
try {
|
||||
const response = await api.get('/api/attributes/TrusteePosition');
|
||||
const response = await api.get(`/api/trustee/${instanceId}/attributes/TrusteePosition`);
|
||||
|
||||
let attrs: AttributeDefinition[] = [];
|
||||
if (response.data?.attributes && Array.isArray(response.data.attributes)) {
|
||||
|
|
@ -58,12 +83,13 @@ export function useTrusteePositions() {
|
|||
setAttributes([]);
|
||||
return [];
|
||||
}
|
||||
}, []);
|
||||
}, [instanceId]);
|
||||
|
||||
// Fetch permissions from backend
|
||||
const fetchPermissions = useCallback(async () => {
|
||||
try {
|
||||
const perms = await checkPermission('DATA', 'trustee.position');
|
||||
const objectKey = 'data.feature.trustee.TrusteePosition';
|
||||
const perms = await checkPermission('DATA', objectKey);
|
||||
setPermissions(perms);
|
||||
return perms;
|
||||
} catch (error: any) {
|
||||
|
|
@ -81,8 +107,13 @@ export function useTrusteePositions() {
|
|||
}, [checkPermission]);
|
||||
|
||||
const fetchPositions = useCallback(async (params?: PaginationParams) => {
|
||||
if (!instanceId) {
|
||||
setPositions([]);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const data = await fetchPositionsApi(request, params);
|
||||
const data = await fetchPositionsApi(request, instanceId, params);
|
||||
|
||||
if (data && typeof data === 'object' && 'items' in data) {
|
||||
const items = Array.isArray(data.items) ? data.items : [];
|
||||
|
|
@ -99,7 +130,7 @@ export function useTrusteePositions() {
|
|||
setPositions([]);
|
||||
setPagination(null);
|
||||
}
|
||||
}, [request]);
|
||||
}, [request, instanceId]);
|
||||
|
||||
// Optimistically remove a position
|
||||
const removeOptimistically = (positionId: string) => {
|
||||
|
|
@ -119,8 +150,9 @@ export function useTrusteePositions() {
|
|||
|
||||
// Fetch a single position by ID
|
||||
const fetchPositionById = useCallback(async (positionId: string): Promise<TrusteePosition | null> => {
|
||||
return await fetchPositionByIdApi(request, positionId);
|
||||
}, [request]);
|
||||
if (!instanceId) return null;
|
||||
return await fetchPositionByIdApi(request, instanceId, positionId);
|
||||
}, [request, instanceId]);
|
||||
|
||||
// Generate edit fields from attributes dynamically with MwSt calculation logic
|
||||
const generateEditFieldsFromAttributes = useCallback((): Array<{
|
||||
|
|
@ -175,7 +207,7 @@ export function useTrusteePositions() {
|
|||
} else if (attr.type === 'select') {
|
||||
fieldType = 'enum';
|
||||
if (Array.isArray(attr.options)) {
|
||||
options = attr.options.map(opt => {
|
||||
options = attr.options.map((opt: any) => {
|
||||
const labelValue = typeof opt.label === 'string'
|
||||
? opt.label
|
||||
: opt.label?.en || opt.label?.[Object.keys(opt.label)[0]] || String(opt.value);
|
||||
|
|
@ -288,16 +320,14 @@ export function useTrusteePositions() {
|
|||
return fetchedAttributes;
|
||||
}, [attributes, fetchAttributes]);
|
||||
|
||||
// Fetch attributes and permissions on mount
|
||||
// Fetch data when instanceId is available
|
||||
useEffect(() => {
|
||||
fetchAttributes();
|
||||
fetchPermissions();
|
||||
}, [fetchAttributes, fetchPermissions]);
|
||||
|
||||
// Initial fetch
|
||||
useEffect(() => {
|
||||
fetchPositions();
|
||||
}, [fetchPositions]);
|
||||
if (instanceId) {
|
||||
fetchAttributes();
|
||||
fetchPermissions();
|
||||
fetchPositions();
|
||||
}
|
||||
}, [instanceId, fetchAttributes, fetchPermissions, fetchPositions]);
|
||||
|
||||
return {
|
||||
positions,
|
||||
|
|
@ -311,12 +341,15 @@ export function useTrusteePositions() {
|
|||
pagination,
|
||||
fetchPositionById,
|
||||
generateEditFieldsFromAttributes,
|
||||
ensureAttributesLoaded
|
||||
ensureAttributesLoaded,
|
||||
instanceId
|
||||
};
|
||||
}
|
||||
|
||||
// Position operations hook
|
||||
export function useTrusteePositionOperations() {
|
||||
const instanceId = useInstanceId();
|
||||
|
||||
const [deletingPositions, setDeletingPositions] = useState<Set<string>>(new Set());
|
||||
const [creatingPosition, setCreatingPosition] = useState(false);
|
||||
const { request, isLoading } = useApiRequest();
|
||||
|
|
@ -325,11 +358,16 @@ export function useTrusteePositionOperations() {
|
|||
const [updateError, setUpdateError] = useState<string | null>(null);
|
||||
|
||||
const handlePositionDelete = async (positionId: string) => {
|
||||
if (!instanceId) {
|
||||
setDeleteError('No instance context');
|
||||
return false;
|
||||
}
|
||||
|
||||
setDeleteError(null);
|
||||
setDeletingPositions(prev => new Set(prev).add(positionId));
|
||||
|
||||
try {
|
||||
await deletePositionApi(request, positionId);
|
||||
await deletePositionApi(request, instanceId, positionId);
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
return true;
|
||||
} catch (error: any) {
|
||||
|
|
@ -345,20 +383,16 @@ export function useTrusteePositionOperations() {
|
|||
};
|
||||
|
||||
const handlePositionCreate = async (positionData: Partial<TrusteePosition>) => {
|
||||
if (!instanceId) {
|
||||
setCreateError('No instance context');
|
||||
return { success: false, error: 'No instance context' };
|
||||
}
|
||||
|
||||
setCreateError(null);
|
||||
setCreatingPosition(true);
|
||||
|
||||
try {
|
||||
const currentUserData = getUserDataCache();
|
||||
const mandateId = currentUserData?.mandateId || '';
|
||||
|
||||
const requestBody = {
|
||||
...positionData,
|
||||
mandate: mandateId
|
||||
};
|
||||
|
||||
const newPosition = await createPositionApi(request, requestBody);
|
||||
|
||||
const newPosition = await createPositionApi(request, instanceId, positionData);
|
||||
return { success: true, positionData: newPosition };
|
||||
} catch (error: any) {
|
||||
setCreateError(error.message);
|
||||
|
|
@ -373,19 +407,15 @@ export function useTrusteePositionOperations() {
|
|||
updateData: Partial<TrusteePosition>,
|
||||
_originalData?: any
|
||||
) => {
|
||||
if (!instanceId) {
|
||||
setUpdateError('No instance context');
|
||||
return { success: false, error: 'No instance context' };
|
||||
}
|
||||
|
||||
setUpdateError(null);
|
||||
|
||||
try {
|
||||
const currentUserData = getUserDataCache();
|
||||
const mandateId = currentUserData?.mandateId || '';
|
||||
|
||||
const requestBody = {
|
||||
...updateData,
|
||||
mandate: mandateId
|
||||
};
|
||||
|
||||
const updatedPosition = await updatePositionApi(request, positionId, requestBody);
|
||||
|
||||
const updatedPosition = await updatePositionApi(request, instanceId, positionId, updateData);
|
||||
return { success: true, positionData: updatedPosition };
|
||||
} catch (error: any) {
|
||||
const errorMessage = error.response?.data?.message || error.message || 'Failed to update position';
|
||||
|
|
@ -412,6 +442,7 @@ export function useTrusteePositionOperations() {
|
|||
handlePositionDelete,
|
||||
handlePositionCreate,
|
||||
handlePositionUpdate,
|
||||
isLoading
|
||||
isLoading,
|
||||
instanceId
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useApiRequest } from './useApi';
|
||||
import { getUserDataCache } from '../utils/userCache';
|
||||
import api from '../api';
|
||||
import { usePermissions, type UserPermissions } from './usePermissions';
|
||||
import { useInstanceId } from './useCurrentInstance';
|
||||
import {
|
||||
fetchRoles as fetchRolesApi,
|
||||
fetchRoleById as fetchRoleByIdApi,
|
||||
|
|
@ -10,15 +10,38 @@ import {
|
|||
updateRole as updateRoleApi,
|
||||
deleteRole as deleteRoleApi,
|
||||
type TrusteeRole,
|
||||
type AttributeDefinition,
|
||||
type PaginationParams
|
||||
} from '../api/trusteeApi';
|
||||
|
||||
export interface AttributeDefinition {
|
||||
name: string;
|
||||
type: 'text' | 'email' | 'date' | 'checkbox' | 'select' | 'multiselect' | 'number' | 'textarea' | 'timestamp' | 'file';
|
||||
label: string;
|
||||
description?: string;
|
||||
required?: boolean;
|
||||
default?: any;
|
||||
options?: any[] | string;
|
||||
readonly?: boolean;
|
||||
editable?: boolean;
|
||||
visible?: boolean;
|
||||
order?: number;
|
||||
sortable?: boolean;
|
||||
filterable?: boolean;
|
||||
searchable?: boolean;
|
||||
width?: number;
|
||||
minWidth?: number;
|
||||
maxWidth?: number;
|
||||
filterOptions?: string[];
|
||||
dependsOn?: string;
|
||||
}
|
||||
|
||||
// Re-export types
|
||||
export type { TrusteeRole, AttributeDefinition, PaginationParams };
|
||||
export type { TrusteeRole, PaginationParams };
|
||||
|
||||
// Roles list hook
|
||||
export function useTrusteeRoles() {
|
||||
const instanceId = useInstanceId();
|
||||
|
||||
const [roles, setRoles] = useState<TrusteeRole[]>([]);
|
||||
const [attributes, setAttributes] = useState<AttributeDefinition[]>([]);
|
||||
const [permissions, setPermissions] = useState<UserPermissions | null>(null);
|
||||
|
|
@ -33,8 +56,10 @@ export function useTrusteeRoles() {
|
|||
|
||||
// Fetch attributes from backend
|
||||
const fetchAttributes = useCallback(async () => {
|
||||
if (!instanceId) return [];
|
||||
|
||||
try {
|
||||
const response = await api.get('/api/attributes/TrusteeRole');
|
||||
const response = await api.get(`/api/trustee/${instanceId}/attributes/TrusteeRole`);
|
||||
|
||||
let attrs: AttributeDefinition[] = [];
|
||||
if (response.data?.attributes && Array.isArray(response.data.attributes)) {
|
||||
|
|
@ -58,12 +83,13 @@ export function useTrusteeRoles() {
|
|||
setAttributes([]);
|
||||
return [];
|
||||
}
|
||||
}, []);
|
||||
}, [instanceId]);
|
||||
|
||||
// Fetch permissions from backend
|
||||
const fetchPermissions = useCallback(async () => {
|
||||
try {
|
||||
const perms = await checkPermission('DATA', 'trustee.role');
|
||||
const objectKey = 'data.feature.trustee.TrusteeRole';
|
||||
const perms = await checkPermission('DATA', objectKey);
|
||||
setPermissions(perms);
|
||||
return perms;
|
||||
} catch (error: any) {
|
||||
|
|
@ -81,8 +107,13 @@ export function useTrusteeRoles() {
|
|||
}, [checkPermission]);
|
||||
|
||||
const fetchRoles = useCallback(async (params?: PaginationParams) => {
|
||||
if (!instanceId) {
|
||||
setRoles([]);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const data = await fetchRolesApi(request, params);
|
||||
const data = await fetchRolesApi(request, instanceId, params);
|
||||
|
||||
if (data && typeof data === 'object' && 'items' in data) {
|
||||
const items = Array.isArray(data.items) ? data.items : [];
|
||||
|
|
@ -99,7 +130,7 @@ export function useTrusteeRoles() {
|
|||
setRoles([]);
|
||||
setPagination(null);
|
||||
}
|
||||
}, [request]);
|
||||
}, [request, instanceId]);
|
||||
|
||||
// Optimistically remove a role
|
||||
const removeOptimistically = (roleId: string) => {
|
||||
|
|
@ -119,30 +150,11 @@ export function useTrusteeRoles() {
|
|||
|
||||
// Fetch a single role by ID
|
||||
const fetchRoleById = useCallback(async (roleId: string): Promise<TrusteeRole | null> => {
|
||||
return await fetchRoleByIdApi(request, roleId);
|
||||
}, [request]);
|
||||
if (!instanceId) return null;
|
||||
return await fetchRoleByIdApi(request, instanceId, roleId);
|
||||
}, [request, instanceId]);
|
||||
|
||||
// Generate edit fields from attributes dynamically
|
||||
// Ensure attributes are loaded
|
||||
const ensureAttributesLoaded = useCallback(async () => {
|
||||
if (attributes && attributes.length > 0) {
|
||||
return attributes;
|
||||
}
|
||||
const fetchedAttributes = await fetchAttributes();
|
||||
return fetchedAttributes;
|
||||
}, [attributes, fetchAttributes]);
|
||||
|
||||
// Fetch attributes and permissions on mount
|
||||
useEffect(() => {
|
||||
fetchAttributes();
|
||||
fetchPermissions();
|
||||
}, [fetchAttributes, fetchPermissions]);
|
||||
|
||||
// Initial fetch
|
||||
useEffect(() => {
|
||||
fetchRoles();
|
||||
}, [fetchRoles]);
|
||||
|
||||
const generateEditFieldsFromAttributes = useCallback((): Array<{
|
||||
key: string;
|
||||
label: string;
|
||||
|
|
@ -189,7 +201,7 @@ export function useTrusteeRoles() {
|
|||
} else if (attr.type === 'select') {
|
||||
fieldType = 'enum';
|
||||
if (Array.isArray(attr.options)) {
|
||||
options = attr.options.map(opt => {
|
||||
options = attr.options.map((opt: any) => {
|
||||
const labelValue = typeof opt.label === 'string'
|
||||
? opt.label
|
||||
: opt.label?.en || opt.label?.[Object.keys(opt.label)[0]] || String(opt.value);
|
||||
|
|
@ -248,6 +260,24 @@ export function useTrusteeRoles() {
|
|||
return editableFields;
|
||||
}, [attributes]);
|
||||
|
||||
// Ensure attributes are loaded
|
||||
const ensureAttributesLoaded = useCallback(async () => {
|
||||
if (attributes && attributes.length > 0) {
|
||||
return attributes;
|
||||
}
|
||||
const fetchedAttributes = await fetchAttributes();
|
||||
return fetchedAttributes;
|
||||
}, [attributes, fetchAttributes]);
|
||||
|
||||
// Fetch data when instanceId is available
|
||||
useEffect(() => {
|
||||
if (instanceId) {
|
||||
fetchAttributes();
|
||||
fetchPermissions();
|
||||
fetchRoles();
|
||||
}
|
||||
}, [instanceId, fetchAttributes, fetchPermissions, fetchRoles]);
|
||||
|
||||
return {
|
||||
roles,
|
||||
loading,
|
||||
|
|
@ -260,12 +290,15 @@ export function useTrusteeRoles() {
|
|||
pagination,
|
||||
fetchRoleById,
|
||||
generateEditFieldsFromAttributes,
|
||||
ensureAttributesLoaded
|
||||
ensureAttributesLoaded,
|
||||
instanceId
|
||||
};
|
||||
}
|
||||
|
||||
// Role operations hook
|
||||
export function useTrusteeRoleOperations() {
|
||||
const instanceId = useInstanceId();
|
||||
|
||||
const [deletingRoles, setDeletingRoles] = useState<Set<string>>(new Set());
|
||||
const [creatingRole, setCreatingRole] = useState(false);
|
||||
const { request, isLoading } = useApiRequest();
|
||||
|
|
@ -274,11 +307,16 @@ export function useTrusteeRoleOperations() {
|
|||
const [updateError, setUpdateError] = useState<string | null>(null);
|
||||
|
||||
const handleRoleDelete = async (roleId: string) => {
|
||||
if (!instanceId) {
|
||||
setDeleteError('No instance context');
|
||||
return false;
|
||||
}
|
||||
|
||||
setDeleteError(null);
|
||||
setDeletingRoles(prev => new Set(prev).add(roleId));
|
||||
|
||||
try {
|
||||
await deleteRoleApi(request, roleId);
|
||||
await deleteRoleApi(request, instanceId, roleId);
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
return true;
|
||||
} catch (error: any) {
|
||||
|
|
@ -296,20 +334,16 @@ export function useTrusteeRoleOperations() {
|
|||
};
|
||||
|
||||
const handleRoleCreate = async (roleData: Partial<TrusteeRole>) => {
|
||||
if (!instanceId) {
|
||||
setCreateError('No instance context');
|
||||
return { success: false, error: 'No instance context' };
|
||||
}
|
||||
|
||||
setCreateError(null);
|
||||
setCreatingRole(true);
|
||||
|
||||
try {
|
||||
const currentUserData = getUserDataCache();
|
||||
const mandateId = currentUserData?.mandateId || '';
|
||||
|
||||
const requestBody = {
|
||||
...roleData,
|
||||
mandate: mandateId
|
||||
};
|
||||
|
||||
const newRole = await createRoleApi(request, requestBody);
|
||||
|
||||
const newRole = await createRoleApi(request, instanceId, roleData);
|
||||
return { success: true, roleData: newRole };
|
||||
} catch (error: any) {
|
||||
setCreateError(error.message);
|
||||
|
|
@ -324,19 +358,15 @@ export function useTrusteeRoleOperations() {
|
|||
updateData: Partial<TrusteeRole>,
|
||||
_originalData?: any
|
||||
) => {
|
||||
if (!instanceId) {
|
||||
setUpdateError('No instance context');
|
||||
return { success: false, error: 'No instance context' };
|
||||
}
|
||||
|
||||
setUpdateError(null);
|
||||
|
||||
try {
|
||||
const currentUserData = getUserDataCache();
|
||||
const mandateId = currentUserData?.mandateId || '';
|
||||
|
||||
const requestBody = {
|
||||
...updateData,
|
||||
mandate: mandateId
|
||||
};
|
||||
|
||||
const updatedRole = await updateRoleApi(request, roleId, requestBody);
|
||||
|
||||
const updatedRole = await updateRoleApi(request, instanceId, roleId, updateData);
|
||||
return { success: true, roleData: updatedRole };
|
||||
} catch (error: any) {
|
||||
const errorMessage = error.response?.data?.message || error.message || 'Failed to update role';
|
||||
|
|
@ -363,6 +393,7 @@ export function useTrusteeRoleOperations() {
|
|||
handleRoleDelete,
|
||||
handleRoleCreate,
|
||||
handleRoleUpdate,
|
||||
isLoading
|
||||
isLoading,
|
||||
instanceId
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export const TeamsbotSettingsView: React.FC = () => {
|
|||
const { instance } = useCurrentInstance();
|
||||
const instanceId = instance?.id || '';
|
||||
|
||||
const [config, setConfig] = useState<TeamsbotConfig | null>(null);
|
||||
const [_config, setConfig] = useState<TeamsbotConfig | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
|
|
|||
Loading…
Reference in a new issue