Files

48 lines
2.4 KiB
TypeScript

import type { ComponentType } from 'react'
import { Building2, CreditCard, Gauge, IdCard, KeyRound, Users } from 'lucide-react'
/**
* Every settings page, once: the column draws these rows, ⌘K searches them, and
* the phone's strip names the open one from them, so a page cannot be reachable
* one way and missing another.
*
* `team` marks a page a personal organization does not have. An org of one holds
* one person and takes no invitations (HIP-0527 I5), so its Members row is
* replaced by the Organization page's "Convert to team".
*/
export interface Place {
href: string
label: string
Icon: ComponentType<{ size?: number; 'aria-hidden'?: boolean }>
/** Words a person might search for that the label does not say. */
words: string
/** Part of an organization's settings rather than the person's own. */
org: boolean
team?: boolean
}
export const SETTINGS = '/settings'
export const ORGANIZATION = '/settings/organization'
/** API keys live in one place, the platform's keys page; this app keeps no copy. */
export const KEYS = 'https://platform.hanzo.ai/api-keys'
export const PLACES: Place[] = [
{ href: SETTINGS, label: 'General', Icon: IdCard, words: 'profile name picture photo theme appearance dark light account', org: false },
{ href: ORGANIZATION, label: 'Organization', Icon: Building2, words: 'name address country id delete convert team', org: true },
{ href: `${ORGANIZATION}/members`, label: 'Members', Icon: Users, words: 'people invite invitations roles remove teammates', org: true, team: true },
{ href: `${ORGANIZATION}/billing`, label: 'Billing', Icon: CreditCard, words: 'plan card payment invoices credits balance add funds', org: true },
{ href: `${ORGANIZATION}/usage`, label: 'Usage', Icon: Gauge, words: 'usage plan limits spend credit premium models', org: true },
{ href: KEYS, label: 'API keys', Icon: KeyRound, words: 'secret publishable default token credential revoke program automation', org: true },
]
/** The places a person can reach, narrowed by what they typed. */
export function find(places: Place[], query: string): Place[] {
const q = query.trim().toLowerCase()
if (!q) return places
return places.filter((p) => `${p.label} ${p.words}`.toLowerCase().includes(q))
}
/** The place an address is, or the nearest one above it. */
export const here = (route: string): Place | undefined =>
PLACES.find((p) => p.href === route) ?? PLACES.find((p) => p.href !== SETTINGS && route.startsWith(`${p.href}/`))