import React from 'react'; import { Pressable, StyleSheet, Text, View } from 'react-native'; import type { SduiBlock } from '@proulr/sdui-contract'; import { Card } from '../ui/Card'; import { fonts, m3Colors, m3Shape, spacing } from '../theme/proulr-theme'; import { resolveDataRef, resolveDataRefString } from '../lib/resolve-data-ref'; import { useSduiHybridRenderer } from '../sdui-hybrid-renderer-context'; import type { SduiBlockRenderProps } from './SduiPrimitiveBlocks'; function readStringProp(block: SduiBlock, key: string): string | undefined { const value = block.props[key]; return typeof value === 'string' ? value : undefined; } function readStringRecordProp(block: SduiBlock, key: string): Record | undefined { const value = block.props[key]; if (!value || typeof value !== 'object') return undefined; const entries = Object.entries(value as Record).filter( (entry): entry is [string, string] => typeof entry[1] === 'string', ); return entries.length > 0 ? Object.fromEntries(entries) : undefined; } type HubSegmentWire = { id: string; label: string; glyph?: string }; function readHubSegments(data: Record, ref?: string): HubSegmentWire[] { const hub = resolveDataRef(data, ref?.split('.')[0] ?? 'hub'); if (!hub || typeof hub !== 'object') return []; const segments = (hub as Record).segments; if (!Array.isArray(segments)) return []; return segments.filter( (item): item is HubSegmentWire => Boolean(item && typeof item === 'object' && typeof (item as HubSegmentWire).id === 'string'), ); } function readActiveSegment(data: Record, ref?: string): string { const value = resolveDataRefString(data, ref ?? 'hub.active_segment'); return value || 'chats'; } export function SduiSegmentedTabsBlock({ block, data, onAction }: SduiBlockRenderProps) { const hybrid = useSduiHybridRenderer(); if (hybrid.renderSegmentedTabs) { return ( <> {hybrid.renderSegmentedTabs({ block, data, onAction, segmentsRef: readStringProp(block, 'segments_ref'), activeRef: readStringProp(block, 'active_ref'), actionPrefix: readStringProp(block, 'action_prefix') ?? 'select_segment_', })} ); } const segmentsRef = readStringProp(block, 'segments_ref') ?? 'hub.segments'; const activeRef = readStringProp(block, 'active_ref') ?? 'hub.active_segment'; const actionPrefix = readStringProp(block, 'action_prefix') ?? 'select_segment_'; const segments = readHubSegments(data, segmentsRef); const active = readActiveSegment(data, activeRef); return ( {segments.map((segment) => { const selected = segment.id === active; return ( onAction(`${actionPrefix}${segment.id}`)} accessibilityRole="tab" accessibilityState={{ selected }} > {segment.glyph ? {segment.glyph} : null} {segment.label} ); })} ); } export function SduiEmptyStateBlock({ block, data }: SduiBlockRenderProps) { const hybrid = useSduiHybridRenderer(); const title = readStringProp(block, 'title') || resolveDataRefString(data, readStringProp(block, 'title_ref')); const hint = readStringProp(block, 'hint') || resolveDataRefString(data, readStringProp(block, 'hint_ref')); if (hybrid.renderEmptyState) { return <>{hybrid.renderEmptyState({ title, hint })}; } return ( {title} {hint ? {hint} : null} ); } export function SduiInboxPersonRowBlock({ block, data, onAction }: SduiBlockRenderProps) { const hybrid = useSduiHybridRenderer(); const variant = readStringProp(block, 'variant'); const rowRef = readStringProp(block, 'row_ref'); const actionId = readStringProp(block, 'action_id'); const actionParams = readStringRecordProp(block, 'action_params'); if ( hybrid.renderInboxPersonRow && variant && rowRef && (variant === 'visit' || variant === 'flash' || variant === 'chat') ) { return ( <> {hybrid.renderInboxPersonRow({ block, data, onAction, variant, rowRef, actionId, actionParams, })} ); } const row = rowRef ? resolveDataRef(data, rowRef) : null; if (!row || typeof row !== 'object') return null; const record = row as Record; const title = resolveDataRefString(data, `${rowRef}.viewer_name`) || resolveDataRefString(data, `${rowRef}.sender_name`) || resolveDataRefString(data, `${rowRef}.peer_display_name`) || 'Alguém'; return ( actionId && onAction(actionId, actionParams)} disabled={!actionId} > {title} {typeof record.viewed_at === 'string' ? ( Visualizou seu perfil ) : null} ); } export function SduiInboxSearchFieldBlock({ block, data, onAction }: SduiBlockRenderProps) { const hybrid = useSduiHybridRenderer(); const placeholder = readStringProp(block, 'placeholder') ?? 'Buscar…'; const layout = readStringProp(block, 'layout') ?? 'wide_only'; const segment = readStringProp(block, 'segment') ?? 'chats'; const activeSegment = readActiveSegment(data, 'hub.active_segment'); if (segment && activeSegment !== segment) return null; if (hybrid.renderInboxSearchField) { return ( <> {hybrid.renderInboxSearchField({ block, data, onAction, placeholder, layout, segment, })} ); } return null; } function CapabilitiesShell({ block, data, onAction, rendererKey, }: SduiBlockRenderProps & { rendererKey: | 'renderChatInboxCapabilities' | 'renderFlashInboxCapabilities' | 'renderProfileVisitsCapabilities'; }) { const hybrid = useSduiHybridRenderer(); const renderer = hybrid[rendererKey]; if (typeof renderer !== 'function') return null; return ( <> {renderer({ block, data, onAction, dataRef: readStringProp(block, 'data_ref'), })} ); } export function SduiChatInboxCapabilitiesBlock(props: SduiBlockRenderProps) { return ; } export function SduiFlashInboxCapabilitiesBlock(props: SduiBlockRenderProps) { return ; } export function SduiProfileVisitsCapabilitiesBlock(props: SduiBlockRenderProps) { return ; } export function SduiFloatingCreateMenuBlock(props: SduiBlockRenderProps) { const hybrid = useSduiHybridRenderer(); if (typeof hybrid.renderFloatingCreateMenu !== 'function') return null; return <>{hybrid.renderFloatingCreateMenu(props)}; } export function SduiInboxHubChromeBlock(props: SduiBlockRenderProps) { const hybrid = useSduiHybridRenderer(); if (typeof hybrid.renderInboxHubChrome !== 'function') return null; return ( <> {hybrid.renderInboxHubChrome({ ...props, hubRef: readStringProp(props.block, 'hub_ref') ?? 'hub', activeFilterRef: readStringProp(props.block, 'active_filter_ref') ?? 'active_filter', })} ); } const styles = StyleSheet.create({ segmentTrack: { flexDirection: 'row', flexGrow: 0, flexShrink: 0, alignSelf: 'stretch', gap: spacing.sm, backgroundColor: m3Colors.surfaceContainerHigh, borderRadius: m3Shape.cornerFull, padding: spacing.xs, marginHorizontal: spacing.sm, }, segment: { flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: spacing.xs, paddingVertical: spacing.sm, paddingHorizontal: spacing.sm, borderRadius: m3Shape.cornerFull, minHeight: 40, }, segmentActive: { backgroundColor: m3Colors.primaryContainer, }, segmentGlyph: { fontSize: 14, }, segmentLabel: { color: m3Colors.onSurfaceVariant, fontFamily: fonts.semibold, fontSize: 14, }, segmentLabelActive: { color: m3Colors.onPrimaryContainer, }, emptyCard: { alignItems: 'center', gap: spacing.sm, paddingVertical: spacing.xxl, marginHorizontal: spacing.sm, }, emptyTitle: { color: m3Colors.onSurfaceVariant, fontSize: 15, fontFamily: fonts.medium, textAlign: 'center', }, emptyHint: { color: m3Colors.onSurfaceVariant, fontSize: 13, textAlign: 'center', }, rowCard: { padding: spacing.md, marginHorizontal: spacing.sm, }, rowTitle: { color: m3Colors.onSurface, fontSize: 16, fontFamily: fonts.semibold, }, rowMeta: { color: m3Colors.onSurfaceVariant, fontSize: 12, marginTop: spacing.xs, }, });