feat(website): show partner location instead of served regions in marketplace (#22224)
## Context On the partners marketplace, the eyebrow shown below each partner's name (on both the list card and the profile header) displayed the served regions (e.g. `APAC`, `EUROPE`). The partner's actual location was buried in the "Where & how" facts list. The location is more useful at a glance, so this swaps the two. ## Changes **List card (`PartnerCard`)** - The eyebrow below the name now shows the partner's city and country instead of the first served region. **Profile page** - `PartnerProfileHeader`: the eyebrow near the title now shows the real location (city, country). - `PartnerFactsList`: the served regions move into the "Where & how" section as a `Regions` row, taking the place of the now-redundant "Based in" row. The `Regions` chip rows on the card are unchanged. https://claude.ai/code/session_01FQRRfvPpmNsjAAnZeDc5sy --- _Generated by [Claude Code](https://claude.ai/code/session_01FQRRfvPpmNsjAAnZeDc5sy)_ <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22224?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
This commit is contained in:
@@ -29,6 +29,7 @@ import { PartnerMoneyRow } from './PartnerMoneyRow';
|
||||
import { PARTNER_SCOPE_LABELS } from './partner-scope-labels';
|
||||
import { SERVED_GEO_LABELS } from './served-geo-labels';
|
||||
import { SPOKEN_LANGUAGE_LABELS } from './spoken-language-labels';
|
||||
import { titleCaseFallback } from './title-case-fallback';
|
||||
|
||||
type PartnerCardStyle = CSSProperties & {
|
||||
'--partner-card-index': number;
|
||||
@@ -146,7 +147,7 @@ const LinkedinIconLink = styled(ExternalLink)`
|
||||
}
|
||||
`;
|
||||
|
||||
const CountryEyebrow = styled.span`
|
||||
const LocationEyebrow = styled.span`
|
||||
color: ${semanticColor.inkMuted};
|
||||
font-family: ${fontFamily('mono')};
|
||||
font-size: ${fontSize(3)};
|
||||
@@ -210,10 +211,12 @@ export function PartnerCard({ partner, index }: PartnerCardProps) {
|
||||
// Unprefixed; LocalizedLink (the name link) and the Button add the locale.
|
||||
const profileHref = `/partners/profile/${partner.slug}`;
|
||||
|
||||
const firstGeo = partner.region[0];
|
||||
const countryLine = firstGeo
|
||||
? i18n._(SERVED_GEO_LABELS[firstGeo]).toUpperCase()
|
||||
: '';
|
||||
const locationLine = [
|
||||
partner.city,
|
||||
partner.country ? titleCaseFallback(partner.country) : '',
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(', ');
|
||||
|
||||
const linkedinSafe = isSafeHttpUrl(partner.linkedinUrl);
|
||||
|
||||
@@ -239,7 +242,7 @@ export function PartnerCard({ partner, index }: PartnerCardProps) {
|
||||
</LinkedinIconLink>
|
||||
)}
|
||||
</NameRow>
|
||||
<CountryEyebrow>{countryLine}</CountryEyebrow>
|
||||
<LocationEyebrow>{locationLine}</LocationEyebrow>
|
||||
</HeaderText>
|
||||
</CardHeader>
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import { color, fontFamily, fontSize, semanticColor, spacing } from '@/tokens';
|
||||
|
||||
import { type MarketplacePartner } from './marketplace-partner';
|
||||
import { PARTNER_SCOPE_LABELS } from './partner-scope-labels';
|
||||
import { SERVED_GEO_LABELS } from './served-geo-labels';
|
||||
import { SPOKEN_LANGUAGE_LABELS } from './spoken-language-labels';
|
||||
import { titleCaseFallback } from './title-case-fallback';
|
||||
|
||||
@@ -57,23 +58,18 @@ function resolveLabels<TValue extends string>(
|
||||
}
|
||||
|
||||
export function PartnerFactsList({
|
||||
city,
|
||||
country,
|
||||
region,
|
||||
languagesSpoken,
|
||||
partnerScope,
|
||||
}: {
|
||||
city: MarketplacePartner['city'];
|
||||
country: MarketplacePartner['country'];
|
||||
region: MarketplacePartner['region'];
|
||||
languagesSpoken: MarketplacePartner['languagesSpoken'];
|
||||
partnerScope: MarketplacePartner['partnerScope'];
|
||||
}) {
|
||||
const { i18n } = useLingui();
|
||||
const translate = (descriptor: MessageDescriptor) => i18n._(descriptor);
|
||||
|
||||
// Country is a CRM SELECT enum (e.g. "UNITED_STATES"); title-case it.
|
||||
const locationText = [city, country ? titleCaseFallback(country) : '']
|
||||
.filter(Boolean)
|
||||
.join(', ');
|
||||
const regionText = resolveLabels(region, SERVED_GEO_LABELS, translate);
|
||||
const languageText = resolveLabels(
|
||||
languagesSpoken,
|
||||
SPOKEN_LANGUAGE_LABELS,
|
||||
@@ -87,10 +83,10 @@ export function PartnerFactsList({
|
||||
|
||||
return (
|
||||
<FactsDl>
|
||||
{locationText && (
|
||||
{regionText && (
|
||||
<FactRow>
|
||||
<FactLabel>{i18n._(msg`Based in`)}</FactLabel>
|
||||
<FactValue>{locationText}</FactValue>
|
||||
<FactLabel>{i18n._(msg`Regions`)}</FactLabel>
|
||||
<FactValue>{regionText}</FactValue>
|
||||
</FactRow>
|
||||
)}
|
||||
{languageText && (
|
||||
|
||||
@@ -173,8 +173,7 @@ export function PartnerProfile({ partner }: { partner: MarketplacePartner }) {
|
||||
<Block>
|
||||
<ProfileEyebrow>{i18n._(msg`Where & how`)}</ProfileEyebrow>
|
||||
<PartnerFactsList
|
||||
city={partner.city}
|
||||
country={partner.country}
|
||||
region={partner.region}
|
||||
languagesSpoken={partner.languagesSpoken}
|
||||
partnerScope={partner.partnerScope}
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
'use client';
|
||||
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { styled } from '@linaria/react';
|
||||
|
||||
import {
|
||||
@@ -15,7 +12,7 @@ import {
|
||||
|
||||
import { type MarketplacePartner } from './marketplace-partner';
|
||||
import { ProfileEyebrow } from './ProfileEyebrow';
|
||||
import { SERVED_GEO_LABELS } from './served-geo-labels';
|
||||
import { titleCaseFallback } from './title-case-fallback';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
display: flex;
|
||||
@@ -56,13 +53,12 @@ export function PartnerProfileHeader({
|
||||
}: {
|
||||
partner: MarketplacePartner;
|
||||
}) {
|
||||
const { i18n } = useLingui();
|
||||
|
||||
// Served regions are the partner's market coverage, not their address.
|
||||
const eyebrow = partner.region
|
||||
.map((geo) => i18n._(SERVED_GEO_LABELS[geo]))
|
||||
const eyebrow = [
|
||||
partner.city,
|
||||
partner.country ? titleCaseFallback(partner.country) : '',
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' · ');
|
||||
.join(', ');
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
|
||||
Reference in New Issue
Block a user