Files
dyolink/frontend/src/lib/api/organization.ts

188 lines
5.7 KiB
TypeScript

import { apiClient } from './client';
import type {
LabCaseComment,
LabCaseDetail,
ListLabCasesParams,
PaginatedLabCases,
} from '@/types/cases';
export interface CounterpartSearchResultDto {
id: string;
name: string;
email: string;
phone: string | null;
owner: { email: string; name: string };
}
export interface CounterpartItemDto {
id: string;
requestedByOrganizationId: string | null;
counterpartOrganizationId: string | null;
organizationName: string;
ownerEmail: string;
phone: string | null;
status: 'PENDING' | 'ACTIVE' | 'REJECTED' | 'EXPIRED';
createdAt: string;
acceptedAt: string | null;
/**
* Set by GET /organizations/connections when this PENDING row came from inviteOrganization()
* (joined server-side). Lets the main table show copy-invite without opening history.
*/
pendingInvitationId?: string | null;
invitationStatus?: OrganizationInvitationHistoryItemDto['status'] | null;
}
export interface OrganizationInvitationHistoryItemDto {
id: string;
organizationName: string;
ownerEmail: string;
status: 'PENDING' | 'ACTIVE' | 'REJECTED' | 'EXPIRED';
createdAt: string;
acceptedAt: string | null;
}
export const organizationApi = {
search: async (q: string): Promise<{ success: boolean; data: CounterpartSearchResultDto[] }> => {
const response = await apiClient.get(`/organizations/search?q=${encodeURIComponent(q)}`);
return response.data;
},
list: async (): Promise<{ success: boolean; data: { items: CounterpartItemDto[] } }> => {
const response = await apiClient.get('/organizations/connections');
return response.data;
},
pendingIncomingCount: async (): Promise<{ success: boolean; data: { count: number } }> => {
const response = await apiClient.get('/organizations/connections/pending-count');
return response.data;
},
listInvitations: async (): Promise<{
success: boolean;
data: { items: OrganizationInvitationHistoryItemDto[] };
}> => {
const response = await apiClient.get('/organizations/invitations');
return response.data;
},
createConnectionRequest: async (
targetOrganizationId: string,
): Promise<{ success: boolean; data: { id: string; status: 'PENDING' | 'ACTIVE' | 'REJECTED' } }> => {
const response = await apiClient.post('/organizations/connections', { targetOrganizationId });
return response.data;
},
respondToConnectionRequest: async (
connectionId: string,
action: 'ACCEPT' | 'REJECT',
): Promise<{ success: boolean; data: { id: string; status: 'PENDING' | 'ACTIVE' | 'REJECTED' } }> => {
const response = await apiClient.patch(`/organizations/connections/${connectionId}/respond`, {
action,
});
return response.data;
},
deleteConnection: async (
connectionId: string,
): Promise<{ success: boolean; data: { id: string }; message: string }> => {
const response = await apiClient.delete(`/organizations/connections/${connectionId}`);
return response.data;
},
invite: async (body: {
organizationName: string;
ownerEmail: string;
phone?: string;
}): Promise<{ success: boolean; data: { invitationId: string; invitationUrl: string; status: 'PENDING' } }> => {
const response = await apiClient.post('/organizations/invite', body);
return response.data;
},
getInvitationLink: async (
invitationId: string,
): Promise<{ success: boolean; data: { invitationId: string; invitationUrl: string } }> => {
const response = await apiClient.post(`/organizations/invitations/${invitationId}/link`);
return response.data;
},
previewInvite: async (
token: string,
): Promise<{
success: boolean;
data: {
ownerEmail: string;
organizationName: string;
organizationType: 'CLINIC' | 'LAB';
organizationEmail?: string;
inviterOrganizationName: string;
expiresAt: string;
status: 'PENDING' | 'ACCEPTED';
};
}> => {
const response = await apiClient.get(
`/organizations/invitations/preview?token=${encodeURIComponent(token)}`,
);
return response.data;
},
acceptInvite: async (body: {
token: string;
organizationName: string;
organizationEmail: string;
organizationType: 'CLINIC' | 'LAB';
ownerName: string;
password: string;
}): Promise<{ success: boolean; message: string; data: { organizationId: string } }> => {
const response = await apiClient.post('/organizations/invitations/accept', body);
return response.data;
},
listConnectionCases: async (
connectionId: string,
params: ListLabCasesParams = {},
): Promise<{
success: boolean;
data: PaginatedLabCases & { counterpart: { id: string; name: string } };
}> => {
const response = await apiClient.get(`/organizations/connections/${connectionId}/cases`, {
params,
});
return response.data;
},
getConnectionCase: async (
connectionId: string,
caseId: string,
): Promise<{
success: boolean;
data: LabCaseDetail & { counterpart: { id: string; name: string } };
}> => {
const response = await apiClient.get(
`/organizations/connections/${connectionId}/cases/${caseId}`,
);
return response.data;
},
listConnectionCaseComments: async (
connectionId: string,
caseId: string,
): Promise<{ success: boolean; data: LabCaseComment[] }> => {
const response = await apiClient.get(
`/organizations/connections/${connectionId}/cases/${caseId}/comments`,
);
return response.data;
},
addConnectionCaseComment: async (
connectionId: string,
caseId: string,
body: string,
): Promise<{ success: boolean; data: LabCaseComment }> => {
const response = await apiClient.post(
`/organizations/connections/${connectionId}/cases/${caseId}/comments`,
{ body },
);
return response.data;
},
};