Files
hanzo.ai/components/sales/Partners.tsx
zeekay 6c65e3e941 @hanzo/app 0.2.0: the app SDK, renamed from @hanzo/rooms
Every import, the catalog pin and the docs name @hanzo/app and
github.com/hanzoai/app. lib/rooms.ts is lib/app.ts and
components/rooms.tsx is components/app.tsx.
2026-10-22 19:07:20 -07:00

105 lines
4.6 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
/**
* Working with Hanzo on /enterprise, from what exists and nothing else: the
* affiliate programme (/affiliate, which states its own rates), the White-label
* plan and the agency's plans as the plan list sells them (GET
* /v1/billing/plans, read when the page opens), and the clouds and silicon
* Hanzo deploys on (lib/constants/partner-logos `infrastructureLogos`).
*
* NO PARTNER IS NAMED, because none is on record: the marks under the cards are
* vendors Hanzo runs on, and the line beside them says exactly that, never
* "partners" or "trusted by" (the claim partner-logos.ts was split to keep
* apart).
*/
import type { LucideIcon } from 'lucide-react'
import { Handshake, Megaphone, Palette } from 'lucide-react'
import { Text, View, XStack, YStack } from '@hanzo/ui'
import { More } from '@hanzo/ui/marketing'
import { money } from '@hanzo/app/lib/pay'
import { usePlans } from '@/lib/api/use'
import type { Plan } from '@/lib/api/read'
import { infrastructureLogos } from '@/lib/constants/partner-logos'
import { AGENCY } from '@/components/home/nav-data'
import { Mark, SALES, Tile } from './kit'
type Way = { icon: LucideIcon; title: string; body: string; price?: string; href: string; go: string }
/** The cheapest monthly price among rows, as the cards write money. */
const from = (rows: Plan[]): string | undefined => {
const prices = rows.map((p) => p.priceMonthly ?? 0).filter((v) => v > 0)
return prices.length ? money(Math.min(...prices)) : undefined
}
export default function Partners() {
const reading = usePlans()
const rows = reading.state === 'ready' ? reading.data : []
const label = rows.find((p) => p.category === 'white-label')
const agency = rows.filter((p) => p.category === 'agency')
const ways: Way[] = [
{
icon: Megaphone,
title: 'Refer customers',
body: 'Bring organizations to Hanzo and earn a share of Hanzo’s margin on what they spend, every period they spend. The customer’s price does not change.',
href: '/affiliate',
go: 'The affiliate programme',
},
{
icon: Palette,
title: label?.name ? `${label.name}: resell under your brand` : 'Resell under your brand',
body: label?.description ?? 'Your own AI agency, under your brand, on your domain.',
price: label?.priceMonthly ? `${money(label.priceMonthly)} a month` : undefined,
href: SALES,
go: 'Ask about White-label',
},
{
icon: Handshake,
title: 'Have Hanzo build it',
body: agency.length ? `${agency.map((p) => p.name).join(', ')}: Hanzo’s agency ships the work with you, from one workstream to an embedded team.` : 'Hanzo’s agency ships the work with you, from one workstream to an embedded team.',
price: from(agency) ? `From ${from(agency)} a month` : undefined,
href: AGENCY,
go: 'Hanzo Agency',
},
]
return (
<YStack gap={32}>
<View display="grid" gap={16} gridTemplateColumns="minmax(0, 1fr)" $md={{ gridTemplateColumns: 'repeat(3, minmax(0, 1fr))' }} data-slot="partners">
{ways.map(({ icon: Icon, title, body, price, href, go }) => (
<Tile key={go}>
<Mark>
<Icon width={20} height={20} aria-hidden />
</Mark>
<Text render="h3" fontSize="$5" lineHeight="1.75rem" fontWeight="600" color="$ink">
{title}
</Text>
<Text render="p" fontSize="$3" lineHeight="1.5rem" color="var(--muted-foreground)">
{body}
</Text>
{price ? (
<Text render="p" fontSize="$3" fontWeight="600" color="$ink" $platform-web={{ fontVariantNumeric: 'tabular-nums' }}>
{price}
</Text>
) : null}
<XStack mt="auto" pt={8}>
<More href={href}>{`${go} →`}</More>
</XStack>
</Tile>
))}
</View>
<YStack gap={16} items="center">
<Text render="p" fontSize="$2" color="var(--muted-foreground)" text="center" maxW={560}>
Hanzo runs in your cloud and on these. They are the clouds and the silicon Hanzo deploys on, not partners or customers.
</Text>
<XStack flexWrap="wrap" justify="center" items="center" columnGap={40} rowGap={20} data-slot="runs-on">
{infrastructureLogos.map((l) => (
<View key={l.name} height={l.height ?? 24} filter="brightness(0) invert(1)" $theme-light={{ filter: 'brightness(0)' }} opacity={0.7}>
<View render={<img src={l.src} alt={l.name} loading="lazy" />} display="block" height={l.height ?? 24} width="auto" />
</View>
))}
</XStack>
</YStack>
</YStack>
)
}