mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 12:18:11 +00:00
feat: add existing files to customer documet tab on portal
This commit is contained in:
@@ -1,24 +1,3 @@
|
|||||||
import { useCallback, useState } from "react";
|
// Re-export of the shared hook, now living in @edr/ui-common. Kept so existing
|
||||||
import { FileViewerModal, type ViewableFile } from "@edr/ui-common";
|
// `@/hooks/useFileViewer` imports keep working.
|
||||||
|
export { useFileViewer } from "@edr/ui-common";
|
||||||
/**
|
|
||||||
* Drives a single shared {@link FileViewerModal} for a page. Call `view(file)`
|
|
||||||
* from any file row to open the document inline (pdf / image / video / office /
|
|
||||||
* text); render `viewer` once near the page root.
|
|
||||||
*
|
|
||||||
* const { view, viewer } = useFileViewer();
|
|
||||||
* <Button onClick={() => view({ name, url, mimeType })}>View</Button>
|
|
||||||
* {viewer}
|
|
||||||
*/
|
|
||||||
export function useFileViewer() {
|
|
||||||
const [file, setFile] = useState<ViewableFile | null>(null);
|
|
||||||
|
|
||||||
const view = useCallback((f: ViewableFile) => setFile(f), []);
|
|
||||||
const close = useCallback(() => setFile(null), []);
|
|
||||||
|
|
||||||
const viewer = (
|
|
||||||
<FileViewerModal open={file !== null} file={file} onClose={close} />
|
|
||||||
);
|
|
||||||
|
|
||||||
return { view, close, viewer };
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,10 +4,12 @@ import { getMinFiles } from "@/types/fileUploadSettings";
|
|||||||
import type { ProfileResponse } from "@/types/profile";
|
import type { ProfileResponse } from "@/types/profile";
|
||||||
import { SmartFileInput } from "@edr/ui-common";
|
import { SmartFileInput } from "@edr/ui-common";
|
||||||
import {
|
import {
|
||||||
|
Anchor,
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
Center,
|
Center,
|
||||||
Group,
|
Group,
|
||||||
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
Title,
|
Title,
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
@@ -17,10 +19,19 @@ import {
|
|||||||
CheckCircle2,
|
CheckCircle2,
|
||||||
FileCheck,
|
FileCheck,
|
||||||
Loader2,
|
Loader2,
|
||||||
|
Paperclip,
|
||||||
UploadCloud,
|
UploadCloud,
|
||||||
XCircle,
|
XCircle,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
|
|
||||||
|
const ROLE_LABELS: Record<string, string> = {
|
||||||
|
importer: "Importer",
|
||||||
|
exporter: "Exporter",
|
||||||
|
freight_forwarder: "Freight Forwarder",
|
||||||
|
dj_freight_forwarder: "DJ Freight Forwarder",
|
||||||
|
transporter: "Transporter",
|
||||||
|
};
|
||||||
|
|
||||||
interface TabDocumentsProps {
|
interface TabDocumentsProps {
|
||||||
profile: ProfileResponse;
|
profile: ProfileResponse;
|
||||||
@@ -28,21 +39,59 @@ interface TabDocumentsProps {
|
|||||||
onContinue?: () => void;
|
onContinue?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function TabDocuments({ profile, mode = "edit", onContinue }: TabDocumentsProps) {
|
function documentSettingCode(nationality: string | null | undefined): string {
|
||||||
|
return nationality === "foreign"
|
||||||
|
? "company_onboarding_documents_foreign"
|
||||||
|
: "company_onboarding_documents_ethiopian";
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function TabDocuments({
|
||||||
|
profile,
|
||||||
|
mode = "edit",
|
||||||
|
onContinue,
|
||||||
|
}: TabDocumentsProps) {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const [documentFiles, setDocumentFiles] = useState<Record<string, File | File[] | null>>({});
|
const [documentFiles, setDocumentFiles] = useState<
|
||||||
|
Record<string, File | File[] | null>
|
||||||
|
>({});
|
||||||
|
|
||||||
const docSettingQuery = useQuery(
|
const docSettingQuery = useQuery(
|
||||||
api.fileUploadSettings.getByCode.queryOptions({
|
api.fileUploadSettings.getByCode.queryOptions({
|
||||||
input: { code: "customer_file_documents" },
|
input: { code: documentSettingCode(profile.nationality) },
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const docsQuery = useQuery(
|
||||||
|
api.companies.documents.queryOptions({
|
||||||
|
input: { companyId: profile.companyId },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const uploadedKeys = useMemo(
|
||||||
|
() => (docsQuery.data ?? []).map((d) => d.code),
|
||||||
|
[docsQuery.data],
|
||||||
|
);
|
||||||
|
|
||||||
|
const existingFilesByKey = useMemo(() => {
|
||||||
|
const map: Record<string, { name: string; url: string; size?: number }[]> =
|
||||||
|
{};
|
||||||
|
for (const doc of docsQuery.data ?? []) {
|
||||||
|
(map[doc.code] ??= []).push({
|
||||||
|
name: doc.name,
|
||||||
|
url: doc.url,
|
||||||
|
size: doc.size,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}, [docsQuery.data]);
|
||||||
|
|
||||||
const docUploadMutation = useMutation({
|
const docUploadMutation = useMutation({
|
||||||
mutationFn: (files: Record<string, File | File[] | null>) =>
|
mutationFn: (files: Record<string, File | File[] | null>) =>
|
||||||
companiesService.uploadDocuments(profile.companyId, files),
|
companiesService.uploadDocuments(profile.companyId, files),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
queryClient.invalidateQueries({ queryKey: api.companies.getProfile.queryKey() });
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: api.companies.getProfile.queryKey(),
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -73,6 +122,7 @@ export default function TabDocuments({ profile, mode = "edit", onContinue }: Tab
|
|||||||
for (const field of docSettingQuery.data?.fields ?? []) {
|
for (const field of docSettingQuery.data?.fields ?? []) {
|
||||||
const min = getMinFiles(field);
|
const min = getMinFiles(field);
|
||||||
if (min <= 0) continue;
|
if (min <= 0) continue;
|
||||||
|
if (uploadedKeys.includes(field.fileKey)) continue;
|
||||||
const v = documentFiles[field.fileKey];
|
const v = documentFiles[field.fileKey];
|
||||||
const count = Array.isArray(v) ? v.length : v ? 1 : 0;
|
const count = Array.isArray(v) ? v.length : v ? 1 : 0;
|
||||||
if (count < min) {
|
if (count < min) {
|
||||||
@@ -82,94 +132,141 @@ export default function TabDocuments({ profile, mode = "edit", onContinue }: Tab
|
|||||||
return errs;
|
return errs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const licenseProfiles = profile.companyProfiles.filter(
|
||||||
|
(p) => p.licenseFiles && p.licenseFiles.length > 0,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card padding="lg">
|
<>
|
||||||
<Group gap="sm" mb="xs">
|
<Card padding="lg">
|
||||||
<FileCheck size={20} />
|
<Group gap="sm" mb="xs">
|
||||||
<Title order={3}>Documents</Title>
|
<FileCheck size={20} />
|
||||||
</Group>
|
<Title order={3}>Documents</Title>
|
||||||
<Text c="edr-muted" size="sm" mb="lg">
|
</Group>
|
||||||
Upload and manage required business documents
|
<Text c="edr-muted" size="sm" mb="lg">
|
||||||
</Text>
|
Upload and manage required business documents
|
||||||
|
|
||||||
{docSettingQuery.isLoading ? (
|
|
||||||
<Center py="xl">
|
|
||||||
<Loader2 size={24} className="animate-spin" />
|
|
||||||
</Center>
|
|
||||||
) : !docSettingQuery.data ? (
|
|
||||||
<Text c="edr-muted" size="sm" ta="center" py="md">
|
|
||||||
No document requirements configured for your account.
|
|
||||||
</Text>
|
</Text>
|
||||||
) : (
|
|
||||||
<SmartFileInput
|
|
||||||
file={docSettingQuery.data}
|
|
||||||
value={documentFiles}
|
|
||||||
onChange={handleFilesChange}
|
|
||||||
errors={fieldErrors}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{docSettingQuery.data && (
|
{docSettingQuery.isLoading ? (
|
||||||
<Group
|
<Center py="xl">
|
||||||
justify="space-between"
|
<Loader2 size={24} className="animate-spin" />
|
||||||
mt="lg"
|
</Center>
|
||||||
pt="md"
|
) : !docSettingQuery.data ? (
|
||||||
style={{ borderTop: "1px solid var(--mantine-color-edr-border-0)" }}
|
<Text c="edr-muted" size="sm" ta="center" py="md">
|
||||||
>
|
No document requirements configured for your account.
|
||||||
<Group gap="xs">
|
</Text>
|
||||||
{docUploadMutation.isSuccess && (
|
) : (
|
||||||
<Group gap={6} c="green">
|
<SmartFileInput
|
||||||
<CheckCircle2 size={16} />
|
file={docSettingQuery.data}
|
||||||
<Text size="sm" fw={500}>
|
value={documentFiles}
|
||||||
{mode === "onboarding" ? "Saved successfully" : "Documents uploaded successfully"}
|
onChange={handleFilesChange}
|
||||||
</Text>
|
errors={fieldErrors}
|
||||||
</Group>
|
uploadedKeys={uploadedKeys}
|
||||||
)}
|
existingFiles={existingFilesByKey}
|
||||||
{docUploadMutation.isError && (
|
/>
|
||||||
<Group gap={6} c="red">
|
)}
|
||||||
<XCircle size={16} />
|
|
||||||
<Text size="sm" fw={500}>Upload failed</Text>
|
{docSettingQuery.data && (
|
||||||
</Group>
|
<Group
|
||||||
|
justify="space-between"
|
||||||
|
mt="lg"
|
||||||
|
pt="md"
|
||||||
|
style={{ borderTop: "1px solid var(--mantine-color-edr-border-0)" }}
|
||||||
|
>
|
||||||
|
<Group gap="xs">
|
||||||
|
{docUploadMutation.isSuccess && (
|
||||||
|
<Group gap={6} c="green">
|
||||||
|
<CheckCircle2 size={16} />
|
||||||
|
<Text size="sm" fw={500}>
|
||||||
|
{mode === "onboarding"
|
||||||
|
? "Saved successfully"
|
||||||
|
: "Documents uploaded successfully"}
|
||||||
|
</Text>
|
||||||
|
</Group>
|
||||||
|
)}
|
||||||
|
{docUploadMutation.isError && (
|
||||||
|
<Group gap={6} c="red">
|
||||||
|
<XCircle size={16} />
|
||||||
|
<Text size="sm" fw={500}>
|
||||||
|
Upload failed
|
||||||
|
</Text>
|
||||||
|
</Group>
|
||||||
|
)}
|
||||||
|
</Group>
|
||||||
|
{mode === "onboarding" ? (
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
leftSection={<ArrowRight size={16} />}
|
||||||
|
loading={docUploadMutation.isPending}
|
||||||
|
onClick={() => {
|
||||||
|
const validationErrors = validateRequired();
|
||||||
|
if (Object.keys(validationErrors).length > 0) {
|
||||||
|
setFieldErrors(validationErrors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (hasFiles) {
|
||||||
|
docUploadMutation.mutate(documentFiles, {
|
||||||
|
onSuccess: () => onContinue?.(),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
onContinue?.();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Continue
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
leftSection={<UploadCloud size={16} />}
|
||||||
|
loading={docUploadMutation.isPending}
|
||||||
|
disabled={!hasFiles}
|
||||||
|
onClick={() => {
|
||||||
|
if (!hasFiles) return;
|
||||||
|
docUploadMutation.mutate(documentFiles);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Upload Documents
|
||||||
|
</Button>
|
||||||
)}
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
{mode === "onboarding" ? (
|
)}
|
||||||
<Button
|
</Card>
|
||||||
type="button"
|
|
||||||
leftSection={<ArrowRight size={16} />}
|
{licenseProfiles.length > 0 && (
|
||||||
loading={docUploadMutation.isPending}
|
<Card padding="lg" mt="lg">
|
||||||
onClick={() => {
|
<Group gap="sm" mb="xs">
|
||||||
const validationErrors = validateRequired();
|
<Paperclip size={20} />
|
||||||
if (Object.keys(validationErrors).length > 0) {
|
<Title order={3}>Business licenses</Title>
|
||||||
setFieldErrors(validationErrors);
|
</Group>
|
||||||
return;
|
<Text c="edr-muted" size="sm" mb="lg">
|
||||||
}
|
License documents uploaded per operational profile
|
||||||
if (hasFiles) {
|
</Text>
|
||||||
docUploadMutation.mutate(documentFiles, {
|
|
||||||
onSuccess: () => onContinue?.(),
|
<Stack gap="md">
|
||||||
});
|
{licenseProfiles.map((p) => (
|
||||||
} else {
|
<Stack key={p.id} gap={4}>
|
||||||
onContinue?.();
|
<Text size="sm" fw={600} c="edr-text">
|
||||||
}
|
{ROLE_LABELS[p.type] ?? p.type} · {p.reference}
|
||||||
}}
|
</Text>
|
||||||
>
|
{p.licenseFiles.map((f) => (
|
||||||
Continue
|
<Group key={f.url} gap={6} wrap="nowrap">
|
||||||
</Button>
|
<Paperclip size={13} className="text-edr-muted" />
|
||||||
) : (
|
<Anchor
|
||||||
<Button
|
href={f.url}
|
||||||
type="button"
|
target="_blank"
|
||||||
leftSection={<UploadCloud size={16} />}
|
rel="noopener noreferrer"
|
||||||
loading={docUploadMutation.isPending}
|
size="xs"
|
||||||
disabled={!hasFiles}
|
>
|
||||||
onClick={() => {
|
{f.name}
|
||||||
if (!hasFiles) return;
|
</Anchor>
|
||||||
docUploadMutation.mutate(documentFiles);
|
</Group>
|
||||||
}}
|
))}
|
||||||
>
|
</Stack>
|
||||||
Upload Documents
|
))}
|
||||||
</Button>
|
</Stack>
|
||||||
)}
|
</Card>
|
||||||
</Group>
|
|
||||||
)}
|
)}
|
||||||
</Card>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ import {
|
|||||||
UpdateDropdownSettingDto,
|
UpdateDropdownSettingDto,
|
||||||
} from "@/types/dropdownSettings";
|
} from "@/types/dropdownSettings";
|
||||||
import type {
|
import type {
|
||||||
|
CompanyDocument,
|
||||||
CompanyInfoResponse,
|
CompanyInfoResponse,
|
||||||
CompanyNationality,
|
CompanyNationality,
|
||||||
CompanyProfileResponse,
|
CompanyProfileResponse,
|
||||||
@@ -158,7 +159,11 @@ export const api = {
|
|||||||
createCompanyProfile: endpoint<
|
createCompanyProfile: endpoint<
|
||||||
{ type: ProfileTypeValue; businessLicense?: string },
|
{ type: ProfileTypeValue; businessLicense?: string },
|
||||||
CompanyProfileResponse
|
CompanyProfileResponse
|
||||||
>("companies", "createCompanyProfile", companiesService.createCompanyProfile),
|
>(
|
||||||
|
"companies",
|
||||||
|
"createCompanyProfile",
|
||||||
|
companiesService.createCompanyProfile,
|
||||||
|
),
|
||||||
|
|
||||||
startOnboarding: endpoint<
|
startOnboarding: endpoint<
|
||||||
{
|
{
|
||||||
@@ -192,6 +197,12 @@ export const api = {
|
|||||||
"onboardingRequirements",
|
"onboardingRequirements",
|
||||||
companiesService.getOnboardingRequirements,
|
companiesService.getOnboardingRequirements,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
documents: endpoint<{ companyId: string }, CompanyDocument[]>(
|
||||||
|
"companies",
|
||||||
|
"documents",
|
||||||
|
({ companyId }) => companiesService.getDocuments(companyId),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
|
|
||||||
bookings: {
|
bookings: {
|
||||||
@@ -228,7 +239,8 @@ export const api = {
|
|||||||
downloadHandoverDocument: endpoint<{ inventoryId: string }, Blob>(
|
downloadHandoverDocument: endpoint<{ inventoryId: string }, Blob>(
|
||||||
"bookings",
|
"bookings",
|
||||||
"downloadHandoverDocument",
|
"downloadHandoverDocument",
|
||||||
({ inventoryId }) => bookingsService.downloadHandoverDocument(inventoryId),
|
({ inventoryId }) =>
|
||||||
|
bookingsService.downloadHandoverDocument(inventoryId),
|
||||||
),
|
),
|
||||||
|
|
||||||
create: endpoint<
|
create: endpoint<
|
||||||
@@ -312,11 +324,8 @@ export const api = {
|
|||||||
proceedToOperation: endpoint<
|
proceedToOperation: endpoint<
|
||||||
{ id: string; scheduledDate: string },
|
{ id: string; scheduledDate: string },
|
||||||
Freight.IBooking
|
Freight.IBooking
|
||||||
>(
|
>("bookings", "proceedToOperation", ({ id, scheduledDate }) =>
|
||||||
"bookings",
|
bookingsService.proceedToOperation(id, scheduledDate),
|
||||||
"proceedToOperation",
|
|
||||||
({ id, scheduledDate }) =>
|
|
||||||
bookingsService.proceedToOperation(id, scheduledDate),
|
|
||||||
),
|
),
|
||||||
|
|
||||||
checkPayment: endpoint<{ orderId: string }, { status: string }>(
|
checkPayment: endpoint<{ orderId: string }, { status: string }>(
|
||||||
@@ -354,10 +363,11 @@ export const api = {
|
|||||||
bookingsService.getAvailableDays({ originYardId, destinationYardId }),
|
bookingsService.getAvailableDays({ originYardId, destinationYardId }),
|
||||||
),
|
),
|
||||||
|
|
||||||
getAvailableDaysForCargo: endpoint<Freight.AvailableDaysForCargoQuery, string[]>(
|
getAvailableDaysForCargo: endpoint<
|
||||||
"train-scheduling",
|
Freight.AvailableDaysForCargoQuery,
|
||||||
"availableDaysForCargo",
|
string[]
|
||||||
(input) => bookingsService.getAvailableDaysForCargo(input),
|
>("train-scheduling", "availableDaysForCargo", (input) =>
|
||||||
|
bookingsService.getAvailableDaysForCargo(input),
|
||||||
),
|
),
|
||||||
|
|
||||||
getMyBookingWindows: endpoint<void, MyBookingWindow[]>(
|
getMyBookingWindows: endpoint<void, MyBookingWindow[]>(
|
||||||
|
|||||||
@@ -82,6 +82,18 @@ export interface CompanyInfoResponse {
|
|||||||
company: CompanyResponse;
|
company: CompanyResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A single company-level document uploaded against a `file_upload_settings` field. */
|
||||||
|
export interface CompanyDocument {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
/** The `fileKey` of the setting field it was uploaded against. */
|
||||||
|
code: string;
|
||||||
|
mimeType: string;
|
||||||
|
size: number;
|
||||||
|
uploadedAt: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
/** A single onboarding document field, as resolved and described by the backend. */
|
/** A single onboarding document field, as resolved and described by the backend. */
|
||||||
export interface OnboardingDocumentField {
|
export interface OnboardingDocumentField {
|
||||||
fileKey: string;
|
fileKey: string;
|
||||||
@@ -124,7 +136,12 @@ export interface OnboardingRequirements {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface CompanyProfileInput {
|
export interface CompanyProfileInput {
|
||||||
type: "importer" | "exporter" | "freight_forwarder" | "dj_freight_forwarder" | "transporter";
|
type:
|
||||||
|
| "importer"
|
||||||
|
| "exporter"
|
||||||
|
| "freight_forwarder"
|
||||||
|
| "dj_freight_forwarder"
|
||||||
|
| "transporter";
|
||||||
businessLicense?: string;
|
businessLicense?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +197,9 @@ export const companiesService = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
create: async (payload: CreateCompanyPayload): Promise<CompanyInfoResponse> => {
|
create: async (
|
||||||
|
payload: CreateCompanyPayload,
|
||||||
|
): Promise<CompanyInfoResponse> => {
|
||||||
const response = await client.post<ApiResponse<CompanyInfoResponse>>(
|
const response = await client.post<ApiResponse<CompanyInfoResponse>>(
|
||||||
URL_CONSTANTS.COMPANIES_API.CREATE,
|
URL_CONSTANTS.COMPANIES_API.CREATE,
|
||||||
payload,
|
payload,
|
||||||
@@ -195,7 +214,9 @@ export const companiesService = {
|
|||||||
return unwrap(response.data);
|
return unwrap(response.data);
|
||||||
},
|
},
|
||||||
|
|
||||||
updateProfile: async (payload: UpdateProfilePayload): Promise<ProfileResponse> => {
|
updateProfile: async (
|
||||||
|
payload: UpdateProfilePayload,
|
||||||
|
): Promise<ProfileResponse> => {
|
||||||
const response = await client.patch<ApiResponse<ProfileResponse>>(
|
const response = await client.patch<ApiResponse<ProfileResponse>>(
|
||||||
URL_CONSTANTS.COMPANIES_API.PROFILE,
|
URL_CONSTANTS.COMPANIES_API.PROFILE,
|
||||||
payload,
|
payload,
|
||||||
@@ -293,7 +314,18 @@ export const companiesService = {
|
|||||||
formData.append(fieldName, fileOrFiles);
|
formData.append(fieldName, fileOrFiles);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await client.post(URL_CONSTANTS.COMPANIES_API.DOCUMENTS(companyId), formData);
|
await client.post(
|
||||||
|
URL_CONSTANTS.COMPANIES_API.DOCUMENTS(companyId),
|
||||||
|
formData,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
/** List documents already uploaded for a company (settings-driven, by fileKey). */
|
||||||
|
getDocuments: async (companyId: string): Promise<CompanyDocument[]> => {
|
||||||
|
const response = await client.get<ApiResponse<CompanyDocument[]>>(
|
||||||
|
URL_CONSTANTS.COMPANIES_API.DOCUMENTS(companyId),
|
||||||
|
);
|
||||||
|
return unwrap(response.data);
|
||||||
},
|
},
|
||||||
|
|
||||||
/** Upload business-license document(s) for a company profile (multi-file). */
|
/** Upload business-license document(s) for a company profile (multi-file). */
|
||||||
|
|||||||
Reference in New Issue
Block a user