91 lines
2.8 KiB
TypeScript
91 lines
2.8 KiB
TypeScript
import { Paper, Text, Stack, Group, Badge, ScrollArea } from '@mantine/core'
|
|
import { IconMapPin, IconVolume } from '@tabler/icons-react'
|
|
import { ActionIcon } from '@mantine/core'
|
|
import type { GuideResponse } from '../lib/api'
|
|
|
|
interface GuidePanelProps {
|
|
response: GuideResponse | null
|
|
loading: boolean
|
|
onSpeak: (text: string) => void
|
|
speaking: boolean
|
|
onStopSpeaking: () => void
|
|
}
|
|
|
|
export function GuidePanel({ response, loading, onSpeak, speaking, onStopSpeaking }: GuidePanelProps) {
|
|
if (loading) {
|
|
return (
|
|
<Paper withBorder p="md" radius="md">
|
|
<Text size="sm" c="dimmed">Consultando tu entorno...</Text>
|
|
</Paper>
|
|
)
|
|
}
|
|
|
|
if (!response) {
|
|
return (
|
|
<Paper withBorder p="md" radius="md">
|
|
<Text size="sm" c="dimmed">
|
|
Pulsa el micrófono o el botón de explorar para recibir información sobre tu entorno.
|
|
</Text>
|
|
</Paper>
|
|
)
|
|
}
|
|
|
|
const { guide, location, pois } = response
|
|
|
|
return (
|
|
<Stack gap="sm">
|
|
{/* Location header */}
|
|
<Paper withBorder p="sm" radius="md">
|
|
<Group gap="xs" wrap="nowrap">
|
|
<IconMapPin size={16} style={{ flexShrink: 0 }} />
|
|
<Text size="xs" lineClamp={2}>
|
|
{location.street ? `${location.street}, ` : ''}
|
|
{location.neighbourhood ? `${location.neighbourhood}, ` : ''}
|
|
{location.city}
|
|
</Text>
|
|
</Group>
|
|
</Paper>
|
|
|
|
{/* Guide text */}
|
|
<Paper withBorder p="md" radius="md">
|
|
<Group justify="space-between" mb="xs">
|
|
<Text fw={600} size="sm">Guía</Text>
|
|
<ActionIcon
|
|
variant={speaking ? 'filled' : 'subtle'}
|
|
color="teal"
|
|
size="sm"
|
|
onClick={() => speaking ? onStopSpeaking() : onSpeak(guide)}
|
|
>
|
|
<IconVolume size={14} />
|
|
</ActionIcon>
|
|
</Group>
|
|
<Text size="sm" style={{ whiteSpace: 'pre-wrap' }}>{guide}</Text>
|
|
</Paper>
|
|
|
|
{/* POIs */}
|
|
{pois.length > 0 && (
|
|
<Paper withBorder p="sm" radius="md">
|
|
<Text fw={600} size="sm" mb="xs">Lugares cercanos</Text>
|
|
<ScrollArea.Autosize mah={200}>
|
|
<Stack gap={4}>
|
|
{pois.map(poi => (
|
|
<Group key={poi.id} gap="xs" wrap="nowrap">
|
|
<Text size="xs" fw={500} style={{ flex: 1 }} lineClamp={1}>
|
|
{poi.name}
|
|
</Text>
|
|
<Badge size="xs" variant="light">{poi.category}</Badge>
|
|
{(poi.score ?? 0) > 0 && (
|
|
<Badge size="xs" variant="dot" color="teal">
|
|
{poi.score?.toFixed(1)}
|
|
</Badge>
|
|
)}
|
|
</Group>
|
|
))}
|
|
</Stack>
|
|
</ScrollArea.Autosize>
|
|
</Paper>
|
|
)}
|
|
</Stack>
|
|
)
|
|
}
|