Rework the UI of vendor row on compliance page

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-02-04 18:29:32 +04:00
parent fc5108a0ce
commit ad122f8b2e
10 changed files with 105 additions and 102 deletions

View File

@@ -1,6 +1,6 @@
import { faviconUrl, getCountryName } from "@probo/helpers";
import { useTranslate } from "@probo/i18n";
import { IconPin, IconShield } from "@probo/ui";
import { IconPin } from "@probo/ui";
import { useFragment } from "react-relay";
import { graphql } from "relay-runtime";
@@ -8,11 +8,9 @@ import type { VendorRowFragment$key } from "./__generated__/VendorRowFragment.gr
const vendorRowFragment = graphql`
fragment VendorRowFragment on Vendor {
id
name
category
description
websiteUrl
privacyPolicyUrl
countries
}
`;
@@ -22,48 +20,37 @@ export function VendorRow(props: { vendor: VendorRowFragment$key; hasAnyCountrie
const logo = faviconUrl(vendor.websiteUrl);
const { __ } = useTranslate();
const gridCols = props.hasAnyCountries ? "grid-cols-[1fr_1fr_1fr]" : "grid-cols-[1fr_1fr]";
return (
<div className="flex text-sm leading-tight gap-3 md:items-center">
<div className="flex text-sm leading-tight gap-6 items-center">
{logo
? (
<img
src={logo}
className="size-8 md:size-6 flex-none rounded-lg"
className="size-8 flex-none rounded-lg"
alt=""
/>
)
: (
<div className="size-8 md:size-6 flex-none rounded-lg" />
<div className="size-8 flex-none rounded-lg" />
)}
<div className="flex flex-col gap-2 flex-1">
<span className="text-sm">{vendor.name}</span>
<div className="text-xs text-txt-secondary w-full">{vendor.description}</div>
{props.hasAnyCountries
&& (
<div className="text-xs flex gap-1 items-start text-txt-quaternary">
{vendor.countries.length > 0 && (
<>
<IconPin size={16} className="flex-none" />
<span>
{vendor.countries
.map(country => getCountryName(__, country))
.join(", ")}
</span>
</>
)}
</div>
)}
<div className={`flex flex-col md:grid ${gridCols} flex-1 gap-0.5`}>
<div>{vendor.name}</div>
{vendor.privacyPolicyUrl
? (
<a
href={vendor.privacyPolicyUrl}
target="_blank"
className={`flex gap-1 text-txt-info items-center hover:underline ${!props.hasAnyCountries ? "md:justify-end" : ""}`}
rel="noreferrer"
>
<IconShield size={16} className="flex-none" />
<span>{__("Privacy")}</span>
</a>
)
: (
<div></div>
)}
{vendor.countries.length > 0 && (
<div className={`flex gap-1 text-txt-secondary items-center ${props.hasAnyCountries ? "md:justify-end" : ""}`}>
<IconPin size={16} className="flex-none" />
<span>
{vendor.countries
.map(country => getCountryName(__, country))
.join(", ")}
</span>
</div>
)}
</div>
</div>
);

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<d9bec9231c4fff6da2f9fa23d68675e1>>
* @generated SignedSource<<93ab4de166540c22f47f2cf5fe51c009>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -10,14 +10,11 @@
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" | "EU" | "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 VendorRowFragment$data = {
readonly category: VendorCategory;
readonly countries: ReadonlyArray<CountryCode>;
readonly id: string;
readonly description: string | null | undefined;
readonly name: string;
readonly privacyPolicyUrl: string | null | undefined;
readonly websiteUrl: string | null | undefined;
readonly " $fragmentType": "VendorRowFragment";
};
@@ -32,13 +29,6 @@ const node: ReaderFragment = {
"metadata": null,
"name": "VendorRowFragment",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -50,7 +40,7 @@ const node: ReaderFragment = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "category",
"name": "description",
"storageKey": null
},
{
@@ -60,13 +50,6 @@ const node: ReaderFragment = {
"name": "websiteUrl",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "privacyPolicyUrl",
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -79,6 +62,6 @@ const node: ReaderFragment = {
"abstractKey": null
};
(node as any).hash = "eba669a2b65ef7b9990799516b7d9932";
(node as any).hash = "deaa52007cf14fbc93ca5a82f6dbba42";
export default node;