This commit is contained in:
@@ -5,6 +5,7 @@ import DocumentItem from "@/components/forms/companies/documents/DocumentItem";
|
|||||||
import { ShowcaseSection } from "@/components/Layouts/showcase-section";
|
import { ShowcaseSection } from "@/components/Layouts/showcase-section";
|
||||||
import Status from "@/components/ui/Status";
|
import Status from "@/components/ui/Status";
|
||||||
import { useCompanyDetails } from "@/hooks/queries";
|
import { useCompanyDetails } from "@/hooks/queries";
|
||||||
|
import type { ICompanyLink } from "@/lib/api";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { BreadcrumbItem } from "@/types/shared";
|
import { BreadcrumbItem } from "@/types/shared";
|
||||||
import { formatPhoneNumber, unixToDate } from "@/utils/shared";
|
import { formatPhoneNumber, unixToDate } from "@/utils/shared";
|
||||||
@@ -76,6 +77,9 @@ const CompanyDetailsPage = ({ params }: IProps) => {
|
|||||||
const documentFileIds: string[] = Array.isArray(company.document_file_ids)
|
const documentFileIds: string[] = Array.isArray(company.document_file_ids)
|
||||||
? company.document_file_ids
|
? company.document_file_ids
|
||||||
: [];
|
: [];
|
||||||
|
const companyLinks: ICompanyLink[] = Array.isArray(company.links)
|
||||||
|
? company.links
|
||||||
|
: [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -145,12 +149,18 @@ const CompanyDetailsPage = ({ params }: IProps) => {
|
|||||||
{`${company.currency || "—"} ${getSymbolFromCurrency(company.currency ?? "USD")}`}
|
{`${company.currency || "—"} ${getSymbolFromCurrency(company.currency ?? "USD")}`}
|
||||||
</span>
|
</span>
|
||||||
</ShowcaseSection>
|
</ShowcaseSection>
|
||||||
<ShowcaseSection title="Annual revenue" {...SHOWCASE_CENTERED_BODY}>
|
<ShowcaseSection
|
||||||
|
title="Annual revenue"
|
||||||
|
{...SHOWCASE_CENTERED_BODY}
|
||||||
|
>
|
||||||
<span className="font-medium text-dark dark:text-white">
|
<span className="font-medium text-dark dark:text-white">
|
||||||
{company.annual_revenue || "—"}
|
{company.annual_revenue || "—"}
|
||||||
</span>
|
</span>
|
||||||
</ShowcaseSection>
|
</ShowcaseSection>
|
||||||
<ShowcaseSection title="Employee count" {...SHOWCASE_CENTERED_BODY}>
|
<ShowcaseSection
|
||||||
|
title="Employee count"
|
||||||
|
{...SHOWCASE_CENTERED_BODY}
|
||||||
|
>
|
||||||
<span className="font-medium text-dark dark:text-white">
|
<span className="font-medium text-dark dark:text-white">
|
||||||
{company.employee_count || "—"}
|
{company.employee_count || "—"}
|
||||||
</span>
|
</span>
|
||||||
@@ -230,6 +240,35 @@ const CompanyDetailsPage = ({ params }: IProps) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{companyLinks.length > 0 && (
|
||||||
|
<div>
|
||||||
|
<SectionHeading>Links</SectionHeading>
|
||||||
|
<div className="grid gap-3 sm:grid-cols-2">
|
||||||
|
{companyLinks.map((companyLink, index) => (
|
||||||
|
<Link
|
||||||
|
key={`${companyLink.url}-${index}`}
|
||||||
|
href={companyLink.url}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="shadow-theme-xs flex min-w-0 items-center justify-between gap-3 rounded-xl border border-stroke/70 bg-white/80 px-4 py-3 text-primary transition hover:border-primary/50 hover:bg-primary/5 dark:border-dark-3 dark:bg-dark-2/70 dark:hover:border-primary/50"
|
||||||
|
>
|
||||||
|
<span className="min-w-0">
|
||||||
|
<span className="block truncate font-medium text-dark dark:text-white">
|
||||||
|
{companyLink.title || companyLink.url}
|
||||||
|
</span>
|
||||||
|
{companyLink.title ? (
|
||||||
|
<span className="block truncate text-xs text-dark-5 dark:text-dark-6">
|
||||||
|
{companyLink.url}
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
</span>
|
||||||
|
<ExternalLinkIcon />
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</ShowcaseSection>
|
</ShowcaseSection>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ const CreateCompany = ({ defaultValues, editMode, id }: IProps) => {
|
|||||||
{editMode ? "Edit company" : "New company"}
|
{editMode ? "Edit company" : "New company"}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-sm text-dark-5 dark:text-dark-6">
|
<p className="text-sm text-dark-5 dark:text-dark-6">
|
||||||
Profile, business details, address, tags, and supporting documents.
|
Profile, business details, address, tags, documents, and links.
|
||||||
</p>
|
</p>
|
||||||
</header>
|
</header>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import type { ILabelValue } from "@/types/shared";
|
|||||||
import type { UseFormSetValue, UseFormWatch } from "react-hook-form";
|
import type { UseFormSetValue, UseFormWatch } from "react-hook-form";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
import CompanyDocuments from "./documents/CompanyDocuments";
|
import CompanyDocuments from "./documents/CompanyDocuments";
|
||||||
|
import CompanyLinks from "./links/CompanyLinks";
|
||||||
|
|
||||||
const companyInformationSectionId = uuidv4();
|
const companyInformationSectionId = uuidv4();
|
||||||
const businessInformationSectionId = uuidv4();
|
const businessInformationSectionId = uuidv4();
|
||||||
@@ -18,6 +19,7 @@ const settingsSectionId = uuidv4();
|
|||||||
const addressSectionId = uuidv4();
|
const addressSectionId = uuidv4();
|
||||||
const tagsSectionId = uuidv4();
|
const tagsSectionId = uuidv4();
|
||||||
const documentsSectionId = uuidv4();
|
const documentsSectionId = uuidv4();
|
||||||
|
const linksSectionId = uuidv4();
|
||||||
|
|
||||||
interface CompanyFormSectionsOptions {
|
interface CompanyFormSectionsOptions {
|
||||||
editMode?: boolean;
|
editMode?: boolean;
|
||||||
@@ -169,9 +171,8 @@ const getTimezoneOffsetMinutes = (timezone: string, date = new Date()) => {
|
|||||||
timeZoneName: "shortOffset",
|
timeZoneName: "shortOffset",
|
||||||
});
|
});
|
||||||
const offset =
|
const offset =
|
||||||
formatter
|
formatter.formatToParts(date).find((part) => part.type === "timeZoneName")
|
||||||
.formatToParts(date)
|
?.value ?? "";
|
||||||
.find((part) => part.type === "timeZoneName")?.value ?? "";
|
|
||||||
const label = offset.replace(/^GMT/, "") || "+0";
|
const label = offset.replace(/^GMT/, "") || "+0";
|
||||||
const match = label.match(/^([+-])(\d{1,2})(?::(\d{2}))?$/);
|
const match = label.match(/^([+-])(\d{1,2})(?::(\d{2}))?$/);
|
||||||
|
|
||||||
@@ -667,4 +668,19 @@ export const createCompanyFormSections = ({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: linksSectionId,
|
||||||
|
title: "Links",
|
||||||
|
rootClassName: "lg:col-span-2",
|
||||||
|
className: "md:grid-cols-1",
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
kind: "custom",
|
||||||
|
name: "links",
|
||||||
|
render: ({ control, errors, register }) => (
|
||||||
|
<CompanyLinks control={control} errors={errors} register={register} />
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import InputGroup from "@/components/FormElements/InputGroup";
|
||||||
|
import type { ICreateCompanyCredentials } from "@/lib/api";
|
||||||
|
import type { Control, FieldErrors, UseFormRegister } from "react-hook-form";
|
||||||
|
import { get, useFieldArray } from "react-hook-form";
|
||||||
|
|
||||||
|
const MAX_COMPANY_LINKS = 20;
|
||||||
|
|
||||||
|
interface CompanyLinksProps {
|
||||||
|
control: Control<ICreateCompanyCredentials>;
|
||||||
|
register: UseFormRegister<ICreateCompanyCredentials>;
|
||||||
|
errors: FieldErrors<ICreateCompanyCredentials>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const validateHttpsUrl = (value?: string) => {
|
||||||
|
const trimmedValue = value?.trim() ?? "";
|
||||||
|
if (!trimmedValue) return "URL is required";
|
||||||
|
|
||||||
|
try {
|
||||||
|
const url = new URL(trimmedValue);
|
||||||
|
return url.protocol === "https:" || "Enter a valid HTTPS URL";
|
||||||
|
} catch {
|
||||||
|
return "Enter a valid HTTPS URL";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const CompanyLinks = ({ control, register, errors }: CompanyLinksProps) => {
|
||||||
|
const { fields, append, remove } = useFieldArray({
|
||||||
|
control,
|
||||||
|
name: "links",
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-4">
|
||||||
|
{fields.length === 0 ? (
|
||||||
|
<p className="text-sm text-dark-5 dark:text-dark-6">
|
||||||
|
No external links added yet.
|
||||||
|
</p>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{fields.map((field, index) => {
|
||||||
|
const urlName = `links.${index}.url` as const;
|
||||||
|
const titleName = `links.${index}.title` as const;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={field.id}
|
||||||
|
className="grid gap-4 rounded-xl border border-stroke/70 bg-gray-1/50 p-4 dark:border-dark-3 dark:bg-dark-2/50 sm:grid-cols-2"
|
||||||
|
>
|
||||||
|
<InputGroup<ICreateCompanyCredentials>
|
||||||
|
{...register(titleName, {
|
||||||
|
setValueAs: (value: string) => value.trim(),
|
||||||
|
maxLength: {
|
||||||
|
value: 200,
|
||||||
|
message: "Title must be 200 characters or fewer",
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
name={titleName}
|
||||||
|
label="Title (optional)"
|
||||||
|
type="text"
|
||||||
|
placeholder="LinkedIn"
|
||||||
|
errors={errors}
|
||||||
|
/>
|
||||||
|
<InputGroup<ICreateCompanyCredentials>
|
||||||
|
{...register(urlName, {
|
||||||
|
validate: validateHttpsUrl,
|
||||||
|
setValueAs: (value: string) => value.trim(),
|
||||||
|
})}
|
||||||
|
name={urlName}
|
||||||
|
label="URL"
|
||||||
|
type="url"
|
||||||
|
placeholder="https://example.com/profile"
|
||||||
|
required
|
||||||
|
errors={errors}
|
||||||
|
/>
|
||||||
|
<div className="flex items-center justify-between sm:col-span-2">
|
||||||
|
<span className="text-xs text-error">
|
||||||
|
{get(errors, `links.${index}.root`)?.message ?? ""}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => remove(index)}
|
||||||
|
className="rounded-lg border border-error/30 px-3 py-1.5 text-sm font-medium text-error transition hover:bg-error/10"
|
||||||
|
>
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
<div className="flex items-center justify-between gap-4">
|
||||||
|
<p className="text-xs text-dark-5 dark:text-dark-6">
|
||||||
|
{fields.length}/{MAX_COMPANY_LINKS} links
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
disabled={fields.length >= MAX_COMPANY_LINKS}
|
||||||
|
onClick={() => append({ url: "", title: "" })}
|
||||||
|
className="rounded-xl bg-primary px-4 py-2 text-sm font-semibold text-white transition hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
|
>
|
||||||
|
+ Add link
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CompanyLinks;
|
||||||
@@ -30,6 +30,7 @@ const useCreateCompanyPresenter = ({ defaultValues, editMode, id }: IProps) => {
|
|||||||
mode: "onChange",
|
mode: "onChange",
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
...defaultValues,
|
...defaultValues,
|
||||||
|
links: defaultValues?.links ?? [],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -72,6 +73,10 @@ const useCreateCompanyPresenter = ({ defaultValues, editMode, id }: IProps) => {
|
|||||||
employee_count: optionalNumber(data.employee_count),
|
employee_count: optionalNumber(data.employee_count),
|
||||||
annual_revenue: optionalNumber(data.annual_revenue),
|
annual_revenue: optionalNumber(data.annual_revenue),
|
||||||
document_file_ids: documentFileIds ?? [],
|
document_file_ids: documentFileIds ?? [],
|
||||||
|
links: (data.links ?? []).map((link) => ({
|
||||||
|
url: link.url.trim(),
|
||||||
|
...(link.title?.trim() ? { title: link.title.trim() } : {}),
|
||||||
|
})),
|
||||||
tags: {
|
tags: {
|
||||||
keywords: data?.tags?.keywords?.length ? data?.tags?.keywords : [],
|
keywords: data?.tags?.keywords?.length ? data?.tags?.keywords : [],
|
||||||
categories: data?.tags?.categories?.length ? data?.tags?.categories : [],
|
categories: data?.tags?.categories?.length ? data?.tags?.categories : [],
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import {
|
|||||||
API_ENDPOINTS,
|
API_ENDPOINTS,
|
||||||
companiesService,
|
companiesService,
|
||||||
companyCategoriesService,
|
companyCategoriesService,
|
||||||
|
type ICompanyLink,
|
||||||
type TCompanyCategoryApiResponse,
|
type TCompanyCategoryApiResponse,
|
||||||
} from "@/lib/api";
|
} from "@/lib/api";
|
||||||
import {
|
import {
|
||||||
@@ -100,6 +101,26 @@ export const useUploadCompanyDocuments = (id: string) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useAddCompanyLinks = (id: string) => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const mutationKey = useMemo(
|
||||||
|
() => [API_ENDPOINTS.COMPANIES.LINKS(id), "add-links"],
|
||||||
|
[id],
|
||||||
|
);
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationKey,
|
||||||
|
mutationFn: (links: ICompanyLink[]) =>
|
||||||
|
companiesService.addLinks({ id, links }),
|
||||||
|
onSuccess: (response) => {
|
||||||
|
toast.success(response.message ?? "Company links added successfully");
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: [API_ENDPOINTS.COMPANIES.READ_ALL, id, "details"],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const useDeleteCompanyQuery = (successCallback?: () => void) => {
|
export const useDeleteCompanyQuery = (successCallback?: () => void) => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const mutationKey = useMemo(
|
const mutationKey = useMemo(
|
||||||
@@ -224,7 +245,8 @@ export const useDeleteCompanyCategoryQuery = (successCallback?: () => void) => {
|
|||||||
};
|
};
|
||||||
export const useToggleCompanyCategoryPublished = () => {
|
export const useToggleCompanyCategoryPublished = () => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const updateOptimisticCategories = useCallback((categoryId: string) => {
|
const updateOptimisticCategories = useCallback(
|
||||||
|
(categoryId: string) => {
|
||||||
queryClient.setQueriesData<TCompanyCategoryApiResponse>(
|
queryClient.setQueriesData<TCompanyCategoryApiResponse>(
|
||||||
{
|
{
|
||||||
queryKey: [API_ENDPOINTS.COMPANIES.CATEGORIES.READ_ALL],
|
queryKey: [API_ENDPOINTS.COMPANIES.CATEGORIES.READ_ALL],
|
||||||
@@ -247,7 +269,9 @@ export const useToggleCompanyCategoryPublished = () => {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}, [queryClient]);
|
},
|
||||||
|
[queryClient],
|
||||||
|
);
|
||||||
const mutationKey = useMemo(
|
const mutationKey = useMemo(
|
||||||
() => [
|
() => [
|
||||||
API_ENDPOINTS.COMPANIES.CATEGORIES.TOGGLE_PUBLISHED("published"),
|
API_ENDPOINTS.COMPANIES.CATEGORIES.TOGGLE_PUBLISHED("published"),
|
||||||
@@ -263,8 +287,7 @@ export const useToggleCompanyCategoryPublished = () => {
|
|||||||
data?: { message?: string };
|
data?: { message?: string };
|
||||||
message?: string;
|
message?: string;
|
||||||
};
|
};
|
||||||
const toastMessage =
|
const toastMessage = responseBody.data?.message ?? responseBody.message;
|
||||||
responseBody.data?.message ?? responseBody.message;
|
|
||||||
if (toastMessage) {
|
if (toastMessage) {
|
||||||
toast.success(toastMessage);
|
toast.success(toastMessage);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ export const API_ENDPOINTS = {
|
|||||||
DELETE: (id: string) => `companies/${id}`,
|
DELETE: (id: string) => `companies/${id}`,
|
||||||
DETAILS: (id: string) => `companies/${id}`,
|
DETAILS: (id: string) => `companies/${id}`,
|
||||||
DOCUMENTS: (id: string) => `companies/${id}/documents`,
|
DOCUMENTS: (id: string) => `companies/${id}/documents`,
|
||||||
|
LINKS: (id: string) => `companies/${id}/links`,
|
||||||
CATEGORIES: {
|
CATEGORIES: {
|
||||||
READ_ALL: "company-categories",
|
READ_ALL: "company-categories",
|
||||||
CREATE: "company-categories",
|
CREATE: "company-categories",
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import {
|
|||||||
TCompaniesResponse,
|
TCompaniesResponse,
|
||||||
TCompanyCategoryApiResponse,
|
TCompanyCategoryApiResponse,
|
||||||
TCreateCompanyCategoryCredentials,
|
TCreateCompanyCategoryCredentials,
|
||||||
|
IAddCompanyLinksResponse,
|
||||||
|
ICompanyLink,
|
||||||
UploadDocumentsData,
|
UploadDocumentsData,
|
||||||
} from "../types";
|
} from "../types";
|
||||||
|
|
||||||
@@ -87,10 +89,25 @@ export const companiesService = {
|
|||||||
|
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("ERROR caught in Companies Services Upload Documents:", error);
|
console.error(
|
||||||
|
"ERROR caught in Companies Services Upload Documents:",
|
||||||
|
error,
|
||||||
|
);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
addLinks: async ({
|
||||||
|
id,
|
||||||
|
links,
|
||||||
|
}: {
|
||||||
|
id: string;
|
||||||
|
links: ICompanyLink[];
|
||||||
|
}): Promise<ApiResponse<IAddCompanyLinksResponse>> => {
|
||||||
|
const response = await api.post(API_ENDPOINTS.COMPANIES.LINKS(id), {
|
||||||
|
links,
|
||||||
|
});
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
deleteCompany: async (id: string) => {
|
deleteCompany: async (id: string) => {
|
||||||
try {
|
try {
|
||||||
return (await api.delete(API_ENDPOINTS.COMPANIES.DELETE(id))).data;
|
return (await api.delete(API_ENDPOINTS.COMPANIES.DELETE(id))).data;
|
||||||
|
|||||||
@@ -28,6 +28,11 @@ export interface ITags {
|
|||||||
cpv_codes: string[];
|
cpv_codes: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ICompanyLink {
|
||||||
|
url: string;
|
||||||
|
title?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ICreateCompanyCredentials {
|
export interface ICreateCompanyCredentials {
|
||||||
name: string;
|
name: string;
|
||||||
email: string;
|
email: string;
|
||||||
@@ -48,6 +53,7 @@ export interface ICreateCompanyCredentials {
|
|||||||
contact_person: IContactPerson;
|
contact_person: IContactPerson;
|
||||||
tags: ITags;
|
tags: ITags;
|
||||||
document_file_ids?: string[];
|
document_file_ids?: string[];
|
||||||
|
links?: ICompanyLink[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const companySchema = z.object({
|
export const companySchema = z.object({
|
||||||
@@ -92,6 +98,14 @@ export const companySchema = z.object({
|
|||||||
cpv_codes: z.array(z.string()).optional(),
|
cpv_codes: z.array(z.string()).optional(),
|
||||||
}),
|
}),
|
||||||
document_file_ids: z.array(z.string()).optional(),
|
document_file_ids: z.array(z.string()).optional(),
|
||||||
|
links: z
|
||||||
|
.array(
|
||||||
|
z.object({
|
||||||
|
url: z.string().url(),
|
||||||
|
title: z.string().nullable().optional(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const companiesResponseSchema = z.object({
|
export const companiesResponseSchema = z.object({
|
||||||
|
|||||||
@@ -38,6 +38,16 @@ export interface ITags {
|
|||||||
cpv_codes: string[];
|
cpv_codes: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ICompanyLink {
|
||||||
|
url: string;
|
||||||
|
title?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IAddCompanyLinksResponse {
|
||||||
|
links: ICompanyLink[];
|
||||||
|
added: ICompanyLink[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface ICreateCompanyCredentials {
|
export interface ICreateCompanyCredentials {
|
||||||
name: string;
|
name: string;
|
||||||
email: string;
|
email: string;
|
||||||
@@ -58,6 +68,7 @@ export interface ICreateCompanyCredentials {
|
|||||||
contact_person?: IContactPerson;
|
contact_person?: IContactPerson;
|
||||||
tags: ITags;
|
tags: ITags;
|
||||||
document_file_ids?: string[];
|
document_file_ids?: string[];
|
||||||
|
links?: ICompanyLink[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const companySchema = z.object({
|
export const companySchema = z.object({
|
||||||
@@ -110,6 +121,15 @@ export const companySchema = z.object({
|
|||||||
cpv_codes: nullableStringArraySchema,
|
cpv_codes: nullableStringArraySchema,
|
||||||
}),
|
}),
|
||||||
document_file_ids: z.array(z.string()).or(z.null()).optional(),
|
document_file_ids: z.array(z.string()).or(z.null()).optional(),
|
||||||
|
links: z
|
||||||
|
.array(
|
||||||
|
z.object({
|
||||||
|
url: z.string().url(),
|
||||||
|
title: z.string().nullable().optional(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.or(z.null())
|
||||||
|
.optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const companiesResponseSchema = z.object({
|
export const companiesResponseSchema = z.object({
|
||||||
|
|||||||
Reference in New Issue
Block a user