Refactored UI endpoint usage
This commit is contained in:
@@ -27,6 +27,7 @@ import {
|
||||
Award,
|
||||
CreateAwardRequest,
|
||||
Contract,
|
||||
ContractStatus,
|
||||
CreateContractRequest,
|
||||
UpdateContractRequest,
|
||||
ExecuteContractRequest,
|
||||
@@ -429,6 +430,18 @@ export const createAward = async (payload: CreateAwardRequest): Promise<Award> =
|
||||
return res.data;
|
||||
};
|
||||
|
||||
export const fetchHashId = async (id64: number | string): Promise<string> => {
|
||||
try {
|
||||
const res = await apiClient.get<string>(`/v1/api/tools/hashid/${id64}`);
|
||||
if (res.data && typeof res.data === 'string') {
|
||||
return res.data;
|
||||
}
|
||||
} catch {
|
||||
// Fall back to client-side deterministic Hashids
|
||||
}
|
||||
return toolsService.encodeIdSync(id64);
|
||||
};
|
||||
|
||||
export const getContracts = async (page = 1, pageSize = 100): Promise<Contract[]> => {
|
||||
const res = await apiClient.get<Contract[]>('/v1/api/grants/contracts', {
|
||||
params: { page, pageSize },
|
||||
@@ -444,15 +457,94 @@ export const getContract = async (contractId: string | number): Promise<Contract
|
||||
|
||||
export const createContract = async (payload: CreateContractRequest): Promise<Contract> => {
|
||||
const userSub = getCurrentUserSub();
|
||||
const hashedAwardId = await toolsService.resolveAwardId(payload.awardId);
|
||||
const res = await apiClient.post('/v1/api/grants/contracts', {
|
||||
...payload,
|
||||
awardId: hashedAwardId,
|
||||
createdBy: userSub || undefined,
|
||||
});
|
||||
return res.data;
|
||||
|
||||
// Extract ID from headers (e.g. Location or Content-Location) if present
|
||||
const locationHeader = res.headers?.['location'] || res.headers?.['Location'];
|
||||
let headerId: string | undefined;
|
||||
if (locationHeader && typeof locationHeader === 'string') {
|
||||
const parts = locationHeader.split('/');
|
||||
headerId = parts[parts.length - 1];
|
||||
}
|
||||
|
||||
// Case 1: Backend returns string contractId/hash directly
|
||||
if (typeof res.data === 'string' && res.data.trim().length > 0) {
|
||||
const rawStr = res.data.trim();
|
||||
return {
|
||||
id: rawStr,
|
||||
contractId: rawStr,
|
||||
awardId: hashedAwardId,
|
||||
totalValue: payload.totalValue,
|
||||
effectiveAt: payload.effectiveAt,
|
||||
expiresAt: payload.expiresAt,
|
||||
status: ContractStatus.Draft,
|
||||
} as unknown as Contract;
|
||||
}
|
||||
|
||||
// Case 2: Backend returns object
|
||||
if (res.data && typeof res.data === 'object') {
|
||||
const candidateId =
|
||||
res.data.id ??
|
||||
res.data.contractId ??
|
||||
res.data.Id ??
|
||||
res.data.ContractId ??
|
||||
headerId;
|
||||
if (candidateId) {
|
||||
return {
|
||||
...res.data,
|
||||
id: candidateId,
|
||||
contractId: candidateId,
|
||||
awardId: res.data.awardId || hashedAwardId,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Case 3: ID extracted from Location header
|
||||
if (headerId) {
|
||||
return {
|
||||
id: headerId,
|
||||
contractId: headerId,
|
||||
awardId: hashedAwardId,
|
||||
totalValue: payload.totalValue,
|
||||
effectiveAt: payload.effectiveAt,
|
||||
expiresAt: payload.expiresAt,
|
||||
status: ContractStatus.Draft,
|
||||
} as unknown as Contract;
|
||||
}
|
||||
|
||||
// Case 4: If backend returns empty 200 OK without body, locate newly created contract by awardId
|
||||
try {
|
||||
const existing = await getContracts(1, 10);
|
||||
const matched = existing.find(
|
||||
(c) =>
|
||||
String(c.awardId) === String(hashedAwardId) ||
|
||||
String(c.awardId) === String(payload.awardId)
|
||||
);
|
||||
if (matched) return matched;
|
||||
} catch {}
|
||||
|
||||
return (res.data || {
|
||||
id: hashedAwardId,
|
||||
contractId: hashedAwardId,
|
||||
awardId: hashedAwardId,
|
||||
totalValue: payload.totalValue,
|
||||
effectiveAt: payload.effectiveAt,
|
||||
expiresAt: payload.expiresAt,
|
||||
status: ContractStatus.Draft,
|
||||
}) as unknown as Contract;
|
||||
};
|
||||
|
||||
export const updateContract = async (payload: UpdateContractRequest): Promise<void> => {
|
||||
await apiClient.put('/v1/api/grants/contracts', payload);
|
||||
const hashedContractId = await toolsService.resolveContractId(payload.contractId);
|
||||
await apiClient.put('/v1/api/grants/contracts', {
|
||||
...payload,
|
||||
contractId: hashedContractId,
|
||||
});
|
||||
};
|
||||
|
||||
export const uploadContractFile = async (
|
||||
@@ -471,14 +563,19 @@ export const uploadContractFile = async (
|
||||
|
||||
export const getContractSecureLink = async (contractId: string | number): Promise<string> => {
|
||||
const hashedContractId = await toolsService.resolveContractId(contractId);
|
||||
const res = await apiClient.get<string>(`/v1/api/grants/contracts/${hashedContractId}/securelink`);
|
||||
return res.data;
|
||||
const res = await apiClient.get<string | { url?: string; link?: string }>(
|
||||
`/v1/api/grants/contracts/${hashedContractId}/securelink`
|
||||
);
|
||||
if (typeof res.data === 'string') return res.data;
|
||||
return (res.data as any)?.url || (res.data as any)?.link || String(res.data);
|
||||
};
|
||||
|
||||
export const executeContract = async (payload: ExecuteContractRequest): Promise<void> => {
|
||||
const userSub = getCurrentUserSub();
|
||||
const hashedContractId = await toolsService.resolveContractId(payload.contractId);
|
||||
await apiClient.post('/v1/api/grants/contracts/execute', {
|
||||
...payload,
|
||||
contractId: hashedContractId,
|
||||
executedBy: userSub || undefined,
|
||||
});
|
||||
};
|
||||
@@ -759,7 +856,7 @@ export const updateUserStatus = async (userId: string, status: ActivityStatus |
|
||||
await apiClient.get(`/v1/api/users/${userId}/status/${status}`);
|
||||
};
|
||||
|
||||
export {
|
||||
import {
|
||||
syncUserAccount,
|
||||
ensureUserSynced,
|
||||
isUserSyncedInBrowser,
|
||||
@@ -771,6 +868,18 @@ export {
|
||||
getActivationPendingReason,
|
||||
} from './userSyncService';
|
||||
|
||||
export {
|
||||
syncUserAccount,
|
||||
ensureUserSynced,
|
||||
isUserSyncedInBrowser,
|
||||
saveUserSyncInBrowser,
|
||||
clearUserSyncInBrowser,
|
||||
getUserSyncRecord,
|
||||
isActivationPending,
|
||||
setActivationPending,
|
||||
getActivationPendingReason,
|
||||
};
|
||||
|
||||
/**
|
||||
* Synchronizes the authenticated user with the backend to enable the user in the system.
|
||||
* By default, sync is saved in the browser to prevent hotspotting the sync endpoint.
|
||||
@@ -786,13 +895,15 @@ export const syncUser = async (
|
||||
},
|
||||
force = false
|
||||
): Promise<boolean> => {
|
||||
const { ensureUserSynced } = await import('./userSyncService');
|
||||
return ensureUserSynced(userData?.sub || userData?.id, undefined, userData, force);
|
||||
};
|
||||
|
||||
export const syncIntegration = async (force = true): Promise<void> => {
|
||||
const { ensureUserSynced } = await import('./userSyncService');
|
||||
await ensureUserSynced(undefined, undefined, undefined, force);
|
||||
try {
|
||||
await apiClient.post('/v1/api/integration/sync', {});
|
||||
} catch {
|
||||
await ensureUserSynced(undefined, undefined, undefined, force);
|
||||
}
|
||||
};
|
||||
|
||||
// ==========================================
|
||||
@@ -821,26 +932,3 @@ export const getApplicantInvites = async (applicantUserId: string): Promise<Invi
|
||||
const res = await apiClient.get<Invite[]>(`/v1/api/communications/invites/${applicantUserId}`);
|
||||
return res.data || [];
|
||||
};
|
||||
|
||||
// Legacy compatibility helpers
|
||||
export const inviteUser = async (payload: InviteUserRequest): Promise<User> => {
|
||||
const userSub = getCurrentUserSub();
|
||||
const res = await apiClient.post('/v1/api/governance/users/invite', {
|
||||
...payload,
|
||||
invitedBy: userSub || undefined,
|
||||
});
|
||||
return res.data;
|
||||
};
|
||||
|
||||
export const revokeUser = async (userId: string): Promise<void> => {
|
||||
await apiClient.delete(`/v1/api/governance/users/${userId}`);
|
||||
};
|
||||
|
||||
export const getAuditLogs = async (): Promise<AuditLog[]> => {
|
||||
try {
|
||||
const res = await apiClient.get<AuditLog[]>('/v1/api/governance/audit');
|
||||
return res.data || [];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user