Add countries and category to vendors
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
169
apps/console/src/components/form/CountriesField.tsx
Normal file
169
apps/console/src/components/form/CountriesField.tsx
Normal file
@@ -0,0 +1,169 @@
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import { useRef, useState } from "react";
|
||||
import { Badge, Input, IconCrossLargeX } from "@probo/ui";
|
||||
import { type Control, Controller, type FieldPath, type FieldValues } from "react-hook-form";
|
||||
import { getCountryName, getCountryOptions, countries, type CountryCode } from "@probo/helpers";
|
||||
import clsx from "clsx";
|
||||
|
||||
type Props<T extends FieldValues = FieldValues> = {
|
||||
control: Control<T>;
|
||||
name: FieldPath<T>;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
export function CountriesField<T extends FieldValues = FieldValues>({ control, name, disabled }: Props<T>) {
|
||||
return (
|
||||
<Controller
|
||||
control={control}
|
||||
name={name}
|
||||
render={({ field }) => (
|
||||
<CountriesFieldInput
|
||||
value={field.value}
|
||||
onValueChange={field.onChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
type CountriesFieldInputProps = {
|
||||
value: string[];
|
||||
onValueChange: (value: string[]) => void;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
function CountriesFieldInput(props: CountriesFieldInputProps) {
|
||||
const { __ } = useTranslate();
|
||||
const animateBadge = useRef(false);
|
||||
|
||||
const addCountry = (code: string) => {
|
||||
animateBadge.current = true;
|
||||
props.onValueChange([...props.value, code]);
|
||||
};
|
||||
|
||||
const removeCountry = (code: string) => {
|
||||
animateBadge.current = true;
|
||||
props.onValueChange(props.value.filter((v) => v !== code));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={clsx(props.value.length > 0 ? "space-y-4" : "")}>
|
||||
{props.value.length > 0 && (
|
||||
<div className="space-y-2">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{props.value.map((countryCode) => (
|
||||
<Badge asChild size="md" key={countryCode}>
|
||||
<button
|
||||
onClick={() => removeCountry(countryCode)}
|
||||
type="button"
|
||||
disabled={props.disabled}
|
||||
className={clsx(
|
||||
"hover:bg-subtle-hover cursor-pointer",
|
||||
props.disabled && "opacity-50 cursor-not-allowed",
|
||||
animateBadge.current &&
|
||||
"starting:opacity-0 starting:w-0 w-max transition-all duration-500 starting:bg-accent"
|
||||
)}
|
||||
>
|
||||
{getCountryName(__, countryCode as CountryCode)}
|
||||
<div className="w-0 overflow-hidden group-hover:w-4 duration-200">
|
||||
<IconCrossLargeX size={12} />
|
||||
</div>
|
||||
</button>
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!props.disabled && (
|
||||
<CountryInput
|
||||
availableCountries={countries.filter(
|
||||
(c: CountryCode) => !props.value.includes(c)
|
||||
)}
|
||||
onAdd={addCountry}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
type CountryInputProps = {
|
||||
availableCountries: readonly CountryCode[];
|
||||
onAdd: (code: string) => void;
|
||||
};
|
||||
|
||||
function CountryInput({ availableCountries, onAdd }: CountryInputProps) {
|
||||
const { __ } = useTranslate();
|
||||
const [search, setSearch] = useState("");
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const countryOptions = getCountryOptions(__);
|
||||
|
||||
const filteredCountries = countryOptions
|
||||
.filter((option: { value: string; label: string }) => availableCountries.includes(option.value as CountryCode))
|
||||
.filter((option: { value: string; label: string }) =>
|
||||
option.label.toLowerCase().includes(search.toLowerCase())
|
||||
);
|
||||
|
||||
const handleCountryClick = (value: string) => {
|
||||
onAdd(value);
|
||||
setSearch("");
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="relative flex-1">
|
||||
<Input
|
||||
type="text"
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
onFocus={() => setIsOpen(true)}
|
||||
placeholder={__("Search and add countries...")}
|
||||
className="w-full pr-8"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
className="absolute right-2 top-1/2 -translate-y-1/2 text-txt-secondary hover:text-txt-primary transition-colors"
|
||||
>
|
||||
<svg
|
||||
className="w-4 h-4"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M19 9l-7 7-7-7"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isOpen && filteredCountries.length > 0 && (
|
||||
<div className="absolute z-50 w-full mt-1 p-2 shadow-mid bg-level-1 overflow-y-auto overflow-x-hidden rounded-2xl border-border-low max-h-60">
|
||||
{filteredCountries.map((option: { value: string; label: string }) => (
|
||||
<button
|
||||
key={option.value}
|
||||
type="button"
|
||||
onClick={() => handleCountryClick(option.value)}
|
||||
className="w-full px-3 py-2 text-left text-sm text-txt-primary hover:bg-highlight-hover focus:bg-highlight-pressed focus:outline-none rounded-lg"
|
||||
>
|
||||
{option.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isOpen && (
|
||||
<div
|
||||
className="fixed inset-0 z-40"
|
||||
onClick={() => setIsOpen(false)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<ea3e7fd6a3b7dd5f78622e9f21cdb1d3>>
|
||||
* @generated SignedSource<<28b582a607c240a6304ea42cb2451776>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -9,12 +9,16 @@
|
||||
// @ts-nocheck
|
||||
|
||||
import { ReaderFragment } from 'relay-runtime';
|
||||
export type CountryCode = "AD" | "AE" | "AF" | "AG" | "AI" | "AL" | "AM" | "AO" | "AQ" | "AR" | "AS" | "AT" | "AU" | "AW" | "AX" | "AZ" | "BA" | "BB" | "BD" | "BE" | "BF" | "BG" | "BH" | "BI" | "BJ" | "BL" | "BM" | "BN" | "BO" | "BQ" | "BR" | "BS" | "BT" | "BV" | "BW" | "BY" | "BZ" | "CA" | "CC" | "CD" | "CF" | "CG" | "CH" | "CI" | "CK" | "CL" | "CM" | "CN" | "CO" | "CR" | "CU" | "CV" | "CW" | "CX" | "CY" | "CZ" | "DE" | "DJ" | "DK" | "DM" | "DO" | "DZ" | "EC" | "EE" | "EG" | "EH" | "ER" | "ES" | "ET" | "FI" | "FJ" | "FK" | "FM" | "FO" | "FR" | "GA" | "GB" | "GD" | "GE" | "GF" | "GG" | "GH" | "GI" | "GL" | "GM" | "GN" | "GP" | "GQ" | "GR" | "GT" | "GU" | "GW" | "GY" | "HK" | "HM" | "HN" | "HR" | "HT" | "HU" | "ID" | "IE" | "IL" | "IM" | "IN" | "IO" | "IQ" | "IR" | "IS" | "IT" | "JE" | "JM" | "JO" | "JP" | "KE" | "KG" | "KH" | "KI" | "KM" | "KN" | "KP" | "KR" | "KW" | "KY" | "KZ" | "LA" | "LB" | "LC" | "LI" | "LK" | "LR" | "LS" | "LT" | "LU" | "LV" | "LY" | "MA" | "MC" | "MD" | "ME" | "MF" | "MG" | "MH" | "MK" | "ML" | "MM" | "MN" | "MO" | "MP" | "MQ" | "MR" | "MS" | "MT" | "MU" | "MV" | "MW" | "MX" | "MY" | "MZ" | "NA" | "NC" | "NE" | "NF" | "NG" | "NI" | "NL" | "NO" | "NP" | "NR" | "NU" | "NZ" | "OM" | "PA" | "PE" | "PF" | "PG" | "PH" | "PK" | "PL" | "PM" | "PN" | "PR" | "PS" | "PT" | "PW" | "PY" | "QA" | "RE" | "RO" | "RS" | "RU" | "RW" | "SA" | "SB" | "SC" | "SD" | "SE" | "SG" | "SH" | "SI" | "SJ" | "SK" | "SL" | "SM" | "SN" | "SO" | "SR" | "SS" | "ST" | "SV" | "SX" | "SY" | "SZ" | "TC" | "TD" | "TF" | "TG" | "TH" | "TJ" | "TK" | "TL" | "TM" | "TN" | "TO" | "TR" | "TT" | "TV" | "TW" | "TZ" | "UA" | "UG" | "UM" | "US" | "UY" | "UZ" | "VA" | "VC" | "VE" | "VG" | "VI" | "VN" | "VU" | "WF" | "WS" | "YE" | "YT" | "ZA" | "ZM" | "ZW";
|
||||
export type VendorCategory = "ANALYTICS" | "CLOUD_MONITORING" | "CLOUD_PROVIDER" | "COLLABORATION" | "CUSTOMER_SUPPORT" | "DATA_STORAGE_AND_PROCESSING" | "DOCUMENT_MANAGEMENT" | "EMPLOYEE_MANAGEMENT" | "ENGINEERING" | "FINANCE" | "IDENTITY_PROVIDER" | "IT" | "MARKETING" | "OFFICE_OPERATIONS" | "OTHER" | "PASSWORD_MANAGEMENT" | "PRODUCT_AND_DESIGN" | "PROFESSIONAL_SERVICES" | "RECRUITING" | "SALES" | "SECURITY" | "VERSION_CONTROL";
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type useVendorFormFragment$data = {
|
||||
readonly businessOwner: {
|
||||
readonly id: string;
|
||||
} | null | undefined;
|
||||
readonly category: VendorCategory;
|
||||
readonly certifications: ReadonlyArray<string>;
|
||||
readonly countries: ReadonlyArray<CountryCode>;
|
||||
readonly dataProcessingAgreementUrl: string | null | undefined;
|
||||
readonly description: string | null | undefined;
|
||||
readonly headquarterAddress: string | null | undefined;
|
||||
@@ -70,6 +74,13 @@ return {
|
||||
"name": "description",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "category",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
@@ -133,6 +144,13 @@ return {
|
||||
"name": "certifications",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "countries",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
@@ -173,6 +191,6 @@ return {
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "87f1029f8c634a5f7efdb6d7abe17709";
|
||||
(node as any).hash = "89148658660d29dbe0ab6761300c6771";
|
||||
|
||||
export default node;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<faa26838a242a98d5df14f51ff257950>>
|
||||
* @generated SignedSource<<3f3a2de3bcfe5c2e7abbea0ba0fb4848>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -10,12 +10,14 @@
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type CountryCode = "AD" | "AE" | "AF" | "AG" | "AI" | "AL" | "AM" | "AO" | "AQ" | "AR" | "AS" | "AT" | "AU" | "AW" | "AX" | "AZ" | "BA" | "BB" | "BD" | "BE" | "BF" | "BG" | "BH" | "BI" | "BJ" | "BL" | "BM" | "BN" | "BO" | "BQ" | "BR" | "BS" | "BT" | "BV" | "BW" | "BY" | "BZ" | "CA" | "CC" | "CD" | "CF" | "CG" | "CH" | "CI" | "CK" | "CL" | "CM" | "CN" | "CO" | "CR" | "CU" | "CV" | "CW" | "CX" | "CY" | "CZ" | "DE" | "DJ" | "DK" | "DM" | "DO" | "DZ" | "EC" | "EE" | "EG" | "EH" | "ER" | "ES" | "ET" | "FI" | "FJ" | "FK" | "FM" | "FO" | "FR" | "GA" | "GB" | "GD" | "GE" | "GF" | "GG" | "GH" | "GI" | "GL" | "GM" | "GN" | "GP" | "GQ" | "GR" | "GT" | "GU" | "GW" | "GY" | "HK" | "HM" | "HN" | "HR" | "HT" | "HU" | "ID" | "IE" | "IL" | "IM" | "IN" | "IO" | "IQ" | "IR" | "IS" | "IT" | "JE" | "JM" | "JO" | "JP" | "KE" | "KG" | "KH" | "KI" | "KM" | "KN" | "KP" | "KR" | "KW" | "KY" | "KZ" | "LA" | "LB" | "LC" | "LI" | "LK" | "LR" | "LS" | "LT" | "LU" | "LV" | "LY" | "MA" | "MC" | "MD" | "ME" | "MF" | "MG" | "MH" | "MK" | "ML" | "MM" | "MN" | "MO" | "MP" | "MQ" | "MR" | "MS" | "MT" | "MU" | "MV" | "MW" | "MX" | "MY" | "MZ" | "NA" | "NC" | "NE" | "NF" | "NG" | "NI" | "NL" | "NO" | "NP" | "NR" | "NU" | "NZ" | "OM" | "PA" | "PE" | "PF" | "PG" | "PH" | "PK" | "PL" | "PM" | "PN" | "PR" | "PS" | "PT" | "PW" | "PY" | "QA" | "RE" | "RO" | "RS" | "RU" | "RW" | "SA" | "SB" | "SC" | "SD" | "SE" | "SG" | "SH" | "SI" | "SJ" | "SK" | "SL" | "SM" | "SN" | "SO" | "SR" | "SS" | "ST" | "SV" | "SX" | "SY" | "SZ" | "TC" | "TD" | "TF" | "TG" | "TH" | "TJ" | "TK" | "TL" | "TM" | "TN" | "TO" | "TR" | "TT" | "TV" | "TW" | "TZ" | "UA" | "UG" | "UM" | "US" | "UY" | "UZ" | "VA" | "VC" | "VE" | "VG" | "VI" | "VN" | "VU" | "WF" | "WS" | "YE" | "YT" | "ZA" | "ZM" | "ZW";
|
||||
export type VendorCategory = "ANALYTICS" | "CLOUD_MONITORING" | "CLOUD_PROVIDER" | "COLLABORATION" | "CUSTOMER_SUPPORT" | "DATA_STORAGE_AND_PROCESSING" | "DOCUMENT_MANAGEMENT" | "EMPLOYEE_MANAGEMENT" | "ENGINEERING" | "FINANCE" | "IDENTITY_PROVIDER" | "IT" | "MARKETING" | "OFFICE_OPERATIONS" | "OTHER" | "PASSWORD_MANAGEMENT" | "PRODUCT_AND_DESIGN" | "PROFESSIONAL_SERVICES" | "RECRUITING" | "SALES" | "SECURITY" | "VERSION_CONTROL";
|
||||
export type UpdateVendorInput = {
|
||||
businessAssociateAgreementUrl?: string | null | undefined;
|
||||
businessOwnerId?: string | null | undefined;
|
||||
category?: VendorCategory | null | undefined;
|
||||
certifications?: ReadonlyArray<string> | null | undefined;
|
||||
countries?: ReadonlyArray<CountryCode> | null | undefined;
|
||||
dataProcessingAgreementUrl?: string | null | undefined;
|
||||
description?: string | null | undefined;
|
||||
headquarterAddress?: string | null | undefined;
|
||||
@@ -148,6 +150,13 @@ return {
|
||||
"name": "description",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "category",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
@@ -211,6 +220,13 @@ return {
|
||||
"name": "certifications",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "countries",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
@@ -254,12 +270,12 @@ return {
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "324b4589b4692806f555489703521bcd",
|
||||
"cacheID": "35a5e6d13ef172a9a8640740a5606b46",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "useVendorFormMutation",
|
||||
"operationKind": "mutation",
|
||||
"text": "mutation useVendorFormMutation(\n $input: UpdateVendorInput!\n) {\n updateVendor(input: $input) {\n vendor {\n ...useVendorFormFragment\n id\n }\n }\n}\n\nfragment useVendorFormFragment on Vendor {\n id\n name\n description\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n websiteUrl\n legalName\n headquarterAddress\n certifications\n securityPageUrl\n trustPageUrl\n businessOwner {\n id\n }\n securityOwner {\n id\n }\n}\n"
|
||||
"text": "mutation useVendorFormMutation(\n $input: UpdateVendorInput!\n) {\n updateVendor(input: $input) {\n vendor {\n ...useVendorFormFragment\n id\n }\n }\n}\n\nfragment useVendorFormFragment on Vendor {\n id\n name\n description\n category\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n websiteUrl\n legalName\n headquarterAddress\n certifications\n countries\n securityPageUrl\n trustPageUrl\n businessOwner {\n id\n }\n securityOwner {\n id\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useEffect, useMemo } from "react";
|
||||
const schema = z.object({
|
||||
name: z.string(),
|
||||
description: z.string(),
|
||||
category: z.string().nullish(),
|
||||
statusPageUrl: z.string(),
|
||||
termsOfServiceUrl: z.string(),
|
||||
privacyPolicyUrl: z.string(),
|
||||
@@ -19,6 +20,7 @@ const schema = z.object({
|
||||
legalName: z.string(),
|
||||
headquarterAddress: z.string(),
|
||||
certifications: z.array(z.string()),
|
||||
countries: z.array(z.string()),
|
||||
securityPageUrl: z.string(),
|
||||
trustPageUrl: z.string(),
|
||||
businessOwnerId: z.string().nullish(),
|
||||
@@ -30,6 +32,7 @@ const vendorFormFragment = graphql`
|
||||
id
|
||||
name
|
||||
description
|
||||
category
|
||||
statusPageUrl
|
||||
termsOfServiceUrl
|
||||
privacyPolicyUrl
|
||||
@@ -39,6 +42,7 @@ const vendorFormFragment = graphql`
|
||||
legalName
|
||||
headquarterAddress
|
||||
certifications
|
||||
countries
|
||||
securityPageUrl
|
||||
trustPageUrl
|
||||
businessOwner {
|
||||
@@ -73,6 +77,7 @@ export function useVendorForm(vendorKey: useVendorFormFragment$key) {
|
||||
() => ({
|
||||
name: vendor.name,
|
||||
description: vendor.description ?? "",
|
||||
category: vendor.category ?? null,
|
||||
statusPageUrl: vendor.statusPageUrl ?? "",
|
||||
termsOfServiceUrl: vendor.termsOfServiceUrl ?? "",
|
||||
privacyPolicyUrl: vendor.privacyPolicyUrl ?? "",
|
||||
@@ -82,6 +87,7 @@ export function useVendorForm(vendorKey: useVendorFormFragment$key) {
|
||||
legalName: vendor.legalName ?? "",
|
||||
headquarterAddress: vendor.headquarterAddress ?? "",
|
||||
certifications: [...(vendor.certifications ?? [])],
|
||||
countries: [...(vendor.countries ?? [])],
|
||||
securityPageUrl: vendor.securityPageUrl ?? "",
|
||||
trustPageUrl: vendor.trustPageUrl ?? "",
|
||||
businessOwnerId: vendor.businessOwner?.id,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<be30aebdf9a7304cd154284fa9f6b207>>
|
||||
* @generated SignedSource<<309fa8f1d9e203536f9b7d00b3622456>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -10,12 +10,14 @@
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type CountryCode = "AD" | "AE" | "AF" | "AG" | "AI" | "AL" | "AM" | "AO" | "AQ" | "AR" | "AS" | "AT" | "AU" | "AW" | "AX" | "AZ" | "BA" | "BB" | "BD" | "BE" | "BF" | "BG" | "BH" | "BI" | "BJ" | "BL" | "BM" | "BN" | "BO" | "BQ" | "BR" | "BS" | "BT" | "BV" | "BW" | "BY" | "BZ" | "CA" | "CC" | "CD" | "CF" | "CG" | "CH" | "CI" | "CK" | "CL" | "CM" | "CN" | "CO" | "CR" | "CU" | "CV" | "CW" | "CX" | "CY" | "CZ" | "DE" | "DJ" | "DK" | "DM" | "DO" | "DZ" | "EC" | "EE" | "EG" | "EH" | "ER" | "ES" | "ET" | "FI" | "FJ" | "FK" | "FM" | "FO" | "FR" | "GA" | "GB" | "GD" | "GE" | "GF" | "GG" | "GH" | "GI" | "GL" | "GM" | "GN" | "GP" | "GQ" | "GR" | "GT" | "GU" | "GW" | "GY" | "HK" | "HM" | "HN" | "HR" | "HT" | "HU" | "ID" | "IE" | "IL" | "IM" | "IN" | "IO" | "IQ" | "IR" | "IS" | "IT" | "JE" | "JM" | "JO" | "JP" | "KE" | "KG" | "KH" | "KI" | "KM" | "KN" | "KP" | "KR" | "KW" | "KY" | "KZ" | "LA" | "LB" | "LC" | "LI" | "LK" | "LR" | "LS" | "LT" | "LU" | "LV" | "LY" | "MA" | "MC" | "MD" | "ME" | "MF" | "MG" | "MH" | "MK" | "ML" | "MM" | "MN" | "MO" | "MP" | "MQ" | "MR" | "MS" | "MT" | "MU" | "MV" | "MW" | "MX" | "MY" | "MZ" | "NA" | "NC" | "NE" | "NF" | "NG" | "NI" | "NL" | "NO" | "NP" | "NR" | "NU" | "NZ" | "OM" | "PA" | "PE" | "PF" | "PG" | "PH" | "PK" | "PL" | "PM" | "PN" | "PR" | "PS" | "PT" | "PW" | "PY" | "QA" | "RE" | "RO" | "RS" | "RU" | "RW" | "SA" | "SB" | "SC" | "SD" | "SE" | "SG" | "SH" | "SI" | "SJ" | "SK" | "SL" | "SM" | "SN" | "SO" | "SR" | "SS" | "ST" | "SV" | "SX" | "SY" | "SZ" | "TC" | "TD" | "TF" | "TG" | "TH" | "TJ" | "TK" | "TL" | "TM" | "TN" | "TO" | "TR" | "TT" | "TV" | "TW" | "TZ" | "UA" | "UG" | "UM" | "US" | "UY" | "UZ" | "VA" | "VC" | "VE" | "VG" | "VI" | "VN" | "VU" | "WF" | "WS" | "YE" | "YT" | "ZA" | "ZM" | "ZW";
|
||||
export type VendorCategory = "ANALYTICS" | "CLOUD_MONITORING" | "CLOUD_PROVIDER" | "COLLABORATION" | "CUSTOMER_SUPPORT" | "DATA_STORAGE_AND_PROCESSING" | "DOCUMENT_MANAGEMENT" | "EMPLOYEE_MANAGEMENT" | "ENGINEERING" | "FINANCE" | "IDENTITY_PROVIDER" | "IT" | "MARKETING" | "OFFICE_OPERATIONS" | "OTHER" | "PASSWORD_MANAGEMENT" | "PRODUCT_AND_DESIGN" | "PROFESSIONAL_SERVICES" | "RECRUITING" | "SALES" | "SECURITY" | "VERSION_CONTROL";
|
||||
export type UpdateVendorInput = {
|
||||
businessAssociateAgreementUrl?: string | null | undefined;
|
||||
businessOwnerId?: string | null | undefined;
|
||||
category?: VendorCategory | null | undefined;
|
||||
certifications?: ReadonlyArray<string> | null | undefined;
|
||||
countries?: ReadonlyArray<CountryCode> | null | undefined;
|
||||
dataProcessingAgreementUrl?: string | null | undefined;
|
||||
description?: string | null | undefined;
|
||||
headquarterAddress?: string | null | undefined;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<8ef289e99926f279eb0e2d5ea955cb32>>
|
||||
* @generated SignedSource<<58e32433a39672dcebad5b51c5d18bd4>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -9,12 +9,14 @@
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
export type CountryCode = "AD" | "AE" | "AF" | "AG" | "AI" | "AL" | "AM" | "AO" | "AQ" | "AR" | "AS" | "AT" | "AU" | "AW" | "AX" | "AZ" | "BA" | "BB" | "BD" | "BE" | "BF" | "BG" | "BH" | "BI" | "BJ" | "BL" | "BM" | "BN" | "BO" | "BQ" | "BR" | "BS" | "BT" | "BV" | "BW" | "BY" | "BZ" | "CA" | "CC" | "CD" | "CF" | "CG" | "CH" | "CI" | "CK" | "CL" | "CM" | "CN" | "CO" | "CR" | "CU" | "CV" | "CW" | "CX" | "CY" | "CZ" | "DE" | "DJ" | "DK" | "DM" | "DO" | "DZ" | "EC" | "EE" | "EG" | "EH" | "ER" | "ES" | "ET" | "FI" | "FJ" | "FK" | "FM" | "FO" | "FR" | "GA" | "GB" | "GD" | "GE" | "GF" | "GG" | "GH" | "GI" | "GL" | "GM" | "GN" | "GP" | "GQ" | "GR" | "GT" | "GU" | "GW" | "GY" | "HK" | "HM" | "HN" | "HR" | "HT" | "HU" | "ID" | "IE" | "IL" | "IM" | "IN" | "IO" | "IQ" | "IR" | "IS" | "IT" | "JE" | "JM" | "JO" | "JP" | "KE" | "KG" | "KH" | "KI" | "KM" | "KN" | "KP" | "KR" | "KW" | "KY" | "KZ" | "LA" | "LB" | "LC" | "LI" | "LK" | "LR" | "LS" | "LT" | "LU" | "LV" | "LY" | "MA" | "MC" | "MD" | "ME" | "MF" | "MG" | "MH" | "MK" | "ML" | "MM" | "MN" | "MO" | "MP" | "MQ" | "MR" | "MS" | "MT" | "MU" | "MV" | "MW" | "MX" | "MY" | "MZ" | "NA" | "NC" | "NE" | "NF" | "NG" | "NI" | "NL" | "NO" | "NP" | "NR" | "NU" | "NZ" | "OM" | "PA" | "PE" | "PF" | "PG" | "PH" | "PK" | "PL" | "PM" | "PN" | "PR" | "PS" | "PT" | "PW" | "PY" | "QA" | "RE" | "RO" | "RS" | "RU" | "RW" | "SA" | "SB" | "SC" | "SD" | "SE" | "SG" | "SH" | "SI" | "SJ" | "SK" | "SL" | "SM" | "SN" | "SO" | "SR" | "SS" | "ST" | "SV" | "SX" | "SY" | "SZ" | "TC" | "TD" | "TF" | "TG" | "TH" | "TJ" | "TK" | "TL" | "TM" | "TN" | "TO" | "TR" | "TT" | "TV" | "TW" | "TZ" | "UA" | "UG" | "UM" | "US" | "UY" | "UZ" | "VA" | "VC" | "VE" | "VG" | "VI" | "VN" | "VU" | "WF" | "WS" | "YE" | "YT" | "ZA" | "ZM" | "ZW";
|
||||
export type VendorCategory = "ANALYTICS" | "CLOUD_MONITORING" | "CLOUD_PROVIDER" | "COLLABORATION" | "CUSTOMER_SUPPORT" | "DATA_STORAGE_AND_PROCESSING" | "DOCUMENT_MANAGEMENT" | "EMPLOYEE_MANAGEMENT" | "ENGINEERING" | "FINANCE" | "IDENTITY_PROVIDER" | "IT" | "MARKETING" | "OFFICE_OPERATIONS" | "OTHER" | "PASSWORD_MANAGEMENT" | "PRODUCT_AND_DESIGN" | "PROFESSIONAL_SERVICES" | "RECRUITING" | "SALES" | "SECURITY" | "VERSION_CONTROL";
|
||||
export type CreateVendorInput = {
|
||||
businessAssociateAgreementUrl?: string | null | undefined;
|
||||
businessOwnerId?: string | null | undefined;
|
||||
category?: VendorCategory | null | undefined;
|
||||
certifications?: ReadonlyArray<string> | null | undefined;
|
||||
countries?: ReadonlyArray<CountryCode> | null | undefined;
|
||||
dataProcessingAgreementUrl?: string | null | undefined;
|
||||
description?: string | null | undefined;
|
||||
headquarterAddress?: string | null | undefined;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<c3a7e9de9c7f072bbca3ad552e5860cd>>
|
||||
* @generated SignedSource<<15c7796ac43c03708488ba03ef9d76a6>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -361,6 +361,13 @@ return {
|
||||
(v5/*: any*/),
|
||||
(v6/*: any*/),
|
||||
(v10/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "category",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
@@ -417,6 +424,13 @@ return {
|
||||
"name": "certifications",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "countries",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
@@ -807,12 +821,12 @@ return {
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "f0b506b57e84959deb0b1e3fa0481897",
|
||||
"cacheID": "90924936acacd1851e8e81b1d94d6655",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "VendorGraphNodeQuery",
|
||||
"operationKind": "query",
|
||||
"text": "query VendorGraphNodeQuery(\n $vendorId: ID!\n $organizationId: ID!\n) {\n node(id: $vendorId) {\n __typename\n ... on Vendor {\n id\n snapshotId\n name\n websiteUrl\n ...useVendorFormFragment\n ...VendorComplianceTabFragment\n ...VendorContactsTabFragment\n ...VendorServicesTabFragment\n ...VendorRiskAssessmentTabFragment\n ...VendorOverviewTabBusinessAssociateAgreementFragment\n ...VendorOverviewTabDataPrivacyAgreementFragment\n }\n id\n }\n viewer {\n user {\n people(organizationId: $organizationId) {\n id\n }\n id\n }\n id\n }\n}\n\nfragment VendorComplianceTabFragment on Vendor {\n complianceReports(first: 50) {\n edges {\n node {\n id\n ...VendorComplianceTabFragment_report\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorComplianceTabFragment_report on VendorComplianceReport {\n id\n reportDate\n validUntil\n reportName\n fileUrl\n fileSize\n}\n\nfragment VendorContactsTabFragment on Vendor {\n contacts(first: 50) {\n edges {\n node {\n id\n ...VendorContactsTabFragment_contact\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorContactsTabFragment_contact on VendorContact {\n id\n fullName\n email\n phone\n role\n createdAt\n updatedAt\n}\n\nfragment VendorOverviewTabBusinessAssociateAgreementFragment on Vendor {\n businessAssociateAgreement {\n id\n fileName\n fileUrl\n validFrom\n validUntil\n createdAt\n }\n}\n\nfragment VendorOverviewTabDataPrivacyAgreementFragment on Vendor {\n dataPrivacyAgreement {\n id\n fileName\n fileUrl\n validFrom\n validUntil\n createdAt\n }\n}\n\nfragment VendorRiskAssessmentTabFragment on Vendor {\n id\n riskAssessments(first: 50) {\n edges {\n node {\n id\n ...VendorRiskAssessmentTabFragment_assessment\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment VendorRiskAssessmentTabFragment_assessment on VendorRiskAssessment {\n id\n assessedAt\n assessedBy {\n id\n fullName\n }\n expiresAt\n dataSensitivity\n businessImpact\n notes\n}\n\nfragment VendorServicesTabFragment on Vendor {\n services(first: 50) {\n edges {\n node {\n id\n ...VendorServicesTabFragment_service\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorServicesTabFragment_service on VendorService {\n id\n name\n description\n createdAt\n updatedAt\n}\n\nfragment useVendorFormFragment on Vendor {\n id\n name\n description\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n websiteUrl\n legalName\n headquarterAddress\n certifications\n securityPageUrl\n trustPageUrl\n businessOwner {\n id\n }\n securityOwner {\n id\n }\n}\n"
|
||||
"text": "query VendorGraphNodeQuery(\n $vendorId: ID!\n $organizationId: ID!\n) {\n node(id: $vendorId) {\n __typename\n ... on Vendor {\n id\n snapshotId\n name\n websiteUrl\n ...useVendorFormFragment\n ...VendorComplianceTabFragment\n ...VendorContactsTabFragment\n ...VendorServicesTabFragment\n ...VendorRiskAssessmentTabFragment\n ...VendorOverviewTabBusinessAssociateAgreementFragment\n ...VendorOverviewTabDataPrivacyAgreementFragment\n }\n id\n }\n viewer {\n user {\n people(organizationId: $organizationId) {\n id\n }\n id\n }\n id\n }\n}\n\nfragment VendorComplianceTabFragment on Vendor {\n complianceReports(first: 50) {\n edges {\n node {\n id\n ...VendorComplianceTabFragment_report\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorComplianceTabFragment_report on VendorComplianceReport {\n id\n reportDate\n validUntil\n reportName\n fileUrl\n fileSize\n}\n\nfragment VendorContactsTabFragment on Vendor {\n contacts(first: 50) {\n edges {\n node {\n id\n ...VendorContactsTabFragment_contact\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorContactsTabFragment_contact on VendorContact {\n id\n fullName\n email\n phone\n role\n createdAt\n updatedAt\n}\n\nfragment VendorOverviewTabBusinessAssociateAgreementFragment on Vendor {\n businessAssociateAgreement {\n id\n fileName\n fileUrl\n validFrom\n validUntil\n createdAt\n }\n}\n\nfragment VendorOverviewTabDataPrivacyAgreementFragment on Vendor {\n dataPrivacyAgreement {\n id\n fileName\n fileUrl\n validFrom\n validUntil\n createdAt\n }\n}\n\nfragment VendorRiskAssessmentTabFragment on Vendor {\n id\n riskAssessments(first: 50) {\n edges {\n node {\n id\n ...VendorRiskAssessmentTabFragment_assessment\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment VendorRiskAssessmentTabFragment_assessment on VendorRiskAssessment {\n id\n assessedAt\n assessedBy {\n id\n fullName\n }\n expiresAt\n dataSensitivity\n businessImpact\n notes\n}\n\nfragment VendorServicesTabFragment on Vendor {\n services(first: 50) {\n edges {\n node {\n id\n ...VendorServicesTabFragment_service\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorServicesTabFragment_service on VendorService {\n id\n name\n description\n createdAt\n updatedAt\n}\n\nfragment useVendorFormFragment on Vendor {\n id\n name\n description\n category\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n websiteUrl\n legalName\n headquarterAddress\n certifications\n countries\n securityPageUrl\n trustPageUrl\n businessOwner {\n id\n }\n securityOwner {\n id\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -51,6 +51,7 @@ export function CreateVendorDialog({
|
||||
serviceLevelAgreementUrl: vendor.serviceLevelAgreementUrl,
|
||||
dataProcessingAgreementUrl: vendor.dataProcessingAgreementUrl,
|
||||
certifications: vendor.certifications,
|
||||
countries: vendor.countries,
|
||||
securityPageUrl: vendor.securityPageUrl,
|
||||
trustPageUrl: vendor.trustPageUrl,
|
||||
statusPageUrl: vendor.statusPageUrl,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<a0f6e47aa4001c2a99c02b7eabe5c99a>>
|
||||
* @generated SignedSource<<6db92ed13cdca3a852d1b7b9c113840e>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -218,6 +218,13 @@ return {
|
||||
"name": "description",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "category",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
@@ -274,6 +281,13 @@ return {
|
||||
"name": "certifications",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "countries",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
@@ -528,12 +542,12 @@ return {
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "dbe0c3ef0f5d4d36436224603629d30a",
|
||||
"cacheID": "025f271f1dca46c6f052f0d59a4315cc",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "ImportAssessmentDialogMutation",
|
||||
"operationKind": "mutation",
|
||||
"text": "mutation ImportAssessmentDialogMutation(\n $input: AssessVendorInput!\n) {\n assessVendor(input: $input) {\n vendor {\n id\n name\n websiteUrl\n ...useVendorFormFragment\n ...VendorComplianceTabFragment\n ...VendorRiskAssessmentTabFragment\n }\n }\n}\n\nfragment VendorComplianceTabFragment on Vendor {\n complianceReports(first: 50) {\n edges {\n node {\n id\n ...VendorComplianceTabFragment_report\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorComplianceTabFragment_report on VendorComplianceReport {\n id\n reportDate\n validUntil\n reportName\n fileUrl\n fileSize\n}\n\nfragment VendorRiskAssessmentTabFragment on Vendor {\n id\n riskAssessments(first: 50) {\n edges {\n node {\n id\n ...VendorRiskAssessmentTabFragment_assessment\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment VendorRiskAssessmentTabFragment_assessment on VendorRiskAssessment {\n id\n assessedAt\n assessedBy {\n id\n fullName\n }\n expiresAt\n dataSensitivity\n businessImpact\n notes\n}\n\nfragment useVendorFormFragment on Vendor {\n id\n name\n description\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n websiteUrl\n legalName\n headquarterAddress\n certifications\n securityPageUrl\n trustPageUrl\n businessOwner {\n id\n }\n securityOwner {\n id\n }\n}\n"
|
||||
"text": "mutation ImportAssessmentDialogMutation(\n $input: AssessVendorInput!\n) {\n assessVendor(input: $input) {\n vendor {\n id\n name\n websiteUrl\n ...useVendorFormFragment\n ...VendorComplianceTabFragment\n ...VendorRiskAssessmentTabFragment\n }\n }\n}\n\nfragment VendorComplianceTabFragment on Vendor {\n complianceReports(first: 50) {\n edges {\n node {\n id\n ...VendorComplianceTabFragment_report\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorComplianceTabFragment_report on VendorComplianceReport {\n id\n reportDate\n validUntil\n reportName\n fileUrl\n fileSize\n}\n\nfragment VendorRiskAssessmentTabFragment on Vendor {\n id\n riskAssessments(first: 50) {\n edges {\n node {\n id\n ...VendorRiskAssessmentTabFragment_assessment\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment VendorRiskAssessmentTabFragment_assessment on VendorRiskAssessment {\n id\n assessedAt\n assessedBy {\n id\n fullName\n }\n expiresAt\n dataSensitivity\n businessImpact\n notes\n}\n\nfragment useVendorFormFragment on Vendor {\n id\n name\n description\n category\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n websiteUrl\n legalName\n headquarterAddress\n certifications\n countries\n securityPageUrl\n trustPageUrl\n businessOwner {\n id\n }\n securityOwner {\n id\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import { useVendorForm } from "/hooks/forms/useVendorForm";
|
||||
import { useOutletContext, useParams } from "react-router";
|
||||
import { Button, Card, Field, Input, IconPlusLarge, IconTrashCan, IconPencil } from "@probo/ui";
|
||||
import { Button, Card, Field, Input, IconPlusLarge, IconTrashCan, IconPencil, Option } from "@probo/ui";
|
||||
import { PeopleSelectField } from "/components/form/PeopleSelectField";
|
||||
import { ControlledField } from "/components/form/ControlledField";
|
||||
import { CountriesField } from "/components/form/CountriesField";
|
||||
import { useOrganizationId } from "/hooks/useOrganizationId";
|
||||
import { useMemo } from "react";
|
||||
import { usePageTitle } from "@probo/hooks";
|
||||
@@ -17,6 +19,7 @@ import { EditDataPrivacyAgreementDialog } from "../dialogs/EditDataPrivacyAgreem
|
||||
import type { useVendorFormFragment$key } from "/hooks/forms/__generated__/useVendorFormFragment.graphql";
|
||||
import type { VendorOverviewTabBusinessAssociateAgreementFragment$key } from "./__generated__/VendorOverviewTabBusinessAssociateAgreementFragment.graphql";
|
||||
import type { VendorOverviewTabDataPrivacyAgreementFragment$key } from "./__generated__/VendorOverviewTabDataPrivacyAgreementFragment.graphql";
|
||||
import type { VendorCategory } from "@probo/vendors";
|
||||
|
||||
const vendorBusinessAssociateAgreementFragment = graphql`
|
||||
fragment VendorOverviewTabBusinessAssociateAgreementFragment on Vendor {
|
||||
@@ -54,6 +57,31 @@ export default function VendorOverviewTab() {
|
||||
}>();
|
||||
|
||||
const { __ } = useTranslate();
|
||||
|
||||
const vendorCategories: { value: VendorCategory; label: string }[] = [
|
||||
{ value: "ANALYTICS", label: __("Analytics") },
|
||||
{ value: "CLOUD_MONITORING", label: __("Cloud Monitoring") },
|
||||
{ value: "CLOUD_PROVIDER", label: __("Cloud Provider") },
|
||||
{ value: "COLLABORATION", label: __("Collaboration") },
|
||||
{ value: "CUSTOMER_SUPPORT", label: __("Customer Support") },
|
||||
{ value: "DATA_STORAGE_AND_PROCESSING", label: __("Data Storage and Processing") },
|
||||
{ value: "DOCUMENT_MANAGEMENT", label: __("Document Management") },
|
||||
{ value: "EMPLOYEE_MANAGEMENT", label: __("Employee Management") },
|
||||
{ value: "ENGINEERING", label: __("Engineering") },
|
||||
{ value: "FINANCE", label: __("Finance") },
|
||||
{ value: "IDENTITY_PROVIDER", label: __("Identity Provider") },
|
||||
{ value: "IT", label: __("IT") },
|
||||
{ value: "MARKETING", label: __("Marketing") },
|
||||
{ value: "OFFICE_OPERATIONS", label: __("Office Operations") },
|
||||
{ value: "OTHER", label: __("Other") },
|
||||
{ value: "PASSWORD_MANAGEMENT", label: __("Password Management") },
|
||||
{ value: "PRODUCT_AND_DESIGN", label: __("Product and Design") },
|
||||
{ value: "PROFESSIONAL_SERVICES", label: __("Professional Services") },
|
||||
{ value: "RECRUITING", label: __("Recruiting") },
|
||||
{ value: "SALES", label: __("Sales") },
|
||||
{ value: "SECURITY", label: __("Security") },
|
||||
{ value: "VERSION_CONTROL", label: __("Version Control") },
|
||||
];
|
||||
const organizationId = useOrganizationId();
|
||||
const { snapshotId } = useParams<{ snapshotId?: string }>();
|
||||
const isSnapshotMode = Boolean(snapshotId);
|
||||
@@ -119,6 +147,21 @@ export default function VendorOverviewTab() {
|
||||
error={errors.description?.message}
|
||||
disabled={isSubmitting || isSnapshotMode}
|
||||
/>
|
||||
<ControlledField
|
||||
control={control}
|
||||
name="category"
|
||||
type="select"
|
||||
label={__("Category")}
|
||||
placeholder={__("Select a category")}
|
||||
error={errors.category?.message}
|
||||
disabled={isSubmitting || isSnapshotMode}
|
||||
>
|
||||
{vendorCategories.map((category) => (
|
||||
<Option key={category.value} value={category.value}>
|
||||
{category.label}
|
||||
</Option>
|
||||
))}
|
||||
</ControlledField>
|
||||
<Field
|
||||
{...register("legalName")}
|
||||
label={__("Legal name")}
|
||||
@@ -143,6 +186,17 @@ export default function VendorOverviewTab() {
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<h2 className="text-base font-medium">{__("Countries")}</h2>
|
||||
<Card padded>
|
||||
<CountriesField
|
||||
control={control}
|
||||
name="countries"
|
||||
disabled={isSubmitting || isSnapshotMode}
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* Ownership */}
|
||||
<div className="space-y-4">
|
||||
<h2 className="text-base font-medium">{__("Ownership details")}</h2>
|
||||
|
||||
Reference in New Issue
Block a user