/** * Shared types for the team-management components. * * Mirrors the @startsimpli/api shapes, but redeclared here so the UI * package doesn't pull @startsimpli/api as a peer. Each component accepts * the data it actually renders — apps pass through whatever @startsimpli/api * gave them. startsim-o7s. */ import type * as React from 'react' export type TeamRole = 'owner' | 'admin' | 'member' | 'viewer' export interface TeamLite { id: string slug: string name: string companyId: string } export interface CompanyLite { id: string slug: string name: string } /** User shape rendered next to each row. Optional fields stay optional. */ export interface MemberUserLite { id: string email: string firstName?: string lastName?: string fullName?: string /** Optional URL to an avatar image. */ avatarUrl?: string } export interface MemberRow { id: string userId: string teamId: string role: TeamRole joinedAt: string /** Optionally embedded; when absent, the email + role-only render path is used. */ user?: MemberUserLite } export interface InvitationLite { id: string email: string teamId: string role: TeamRole /** Only present on the create-response; otherwise the backend redacts. */ token?: string expiresAt: string acceptedAt?: string | null revokedAt?: string | null isExpired: boolean isAccepted: boolean } export type DomainVerificationMethod = 'dns_txt' | 'email_attestation' export interface DomainClaimLite { id: string companyId: string domain: string verified: boolean verificationMethod?: DomainVerificationMethod | null verificationToken?: string | null verifiedAt?: string | null createdAt: string } /** * Helper: render a human-friendly label for a user — fullName wins, then * firstName + lastName, then email. */ export function userDisplayName(user: MemberUserLite | undefined): string { if (!user) return '' if (user.fullName) return user.fullName const fl = [user.firstName, user.lastName].filter(Boolean).join(' ').trim() return fl || user.email } /** Helper: render initials for the avatar fallback. */ export function userInitials(user: MemberUserLite | undefined): string { if (!user) return '?' const name = userDisplayName(user) const parts = name.split(/\s+/).filter(Boolean) if (parts.length === 0) return '?' if (parts.length === 1) return parts[0][0].toUpperCase() return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase() } /** Common React-prop alias used by every team component. */ export type ChildrenProps = { children?: React.ReactNode }