diff --git a/lib/src/Components/Profile/Subcomponents/RoutingLinksView.spec.tsx b/lib/src/Components/Profile/Subcomponents/RoutingLinksView.spec.tsx new file mode 100644 index 00000000..41f281e3 --- /dev/null +++ b/lib/src/Components/Profile/Subcomponents/RoutingLinksView.spec.tsx @@ -0,0 +1,93 @@ +import { render } from '@testing-library/react' +import { describe, it, expect } from 'vitest' + +import { RoutingLinksView } from './RoutingLinksView' + +import type { Item } from '#types/Item' + +const itemWithPosition: Item = { + id: '1', + name: 'Test Location', + position: { + type: 'Point', + coordinates: [9.667615, 50.588632], // longitude, latitude format + }, +} + +const itemWithoutPosition: Item = { + id: '2', + name: 'Test Item Without Position', +} + +const itemWithNullPosition: Item = { + id: '3', + name: 'Test Item With Null Position', + position: null, +} + +describe('', () => { + describe('when item has position coordinates', () => { + it('renders routing service links', () => { + const wrapper = render() + + expect(wrapper.getByText('Get Directions')).toBeInTheDocument() + expect(wrapper.getByText('Google Maps')).toBeInTheDocument() + expect(wrapper.getByText('Apple Maps')).toBeInTheDocument() + expect(wrapper.getByText('OpenStreetMap')).toBeInTheDocument() + }) + + it('generates correct Google Maps URL', () => { + const wrapper = render() + const googleMapsLink = wrapper.getByText('Google Maps').closest('a') + + expect(googleMapsLink).toHaveAttribute( + 'href', + 'https://www.google.com/maps/dir/?api=1&destination=50.588632,9.667615', + ) + }) + + it('generates correct Apple Maps URL', () => { + const wrapper = render() + const appleMapsLink = wrapper.getByText('Apple Maps').closest('a') + + expect(appleMapsLink).toHaveAttribute( + 'href', + 'https://maps.apple.com/?daddr=50.588632,9.667615', + ) + }) + + it('generates correct OpenStreetMap URL', () => { + const wrapper = render() + const osmLink = wrapper.getByText('OpenStreetMap').closest('a') + + expect(osmLink).toHaveAttribute( + 'href', + 'https://www.openstreetmap.org/directions?to=50.588632,9.667615', + ) + }) + + it('opens links in new tab', () => { + const wrapper = render() + const links = wrapper.container.querySelectorAll('a') + + links.forEach((link) => { + expect(link).toHaveAttribute('target', '_blank') + expect(link).toHaveAttribute('rel', 'noopener noreferrer') + }) + }) + }) + + describe('when item does not have position', () => { + it('does not render anything', () => { + const wrapper = render() + expect(wrapper.container.firstChild).toBeNull() + }) + }) + + describe('when item has null position', () => { + it('does not render anything', () => { + const wrapper = render() + expect(wrapper.container.firstChild).toBeNull() + }) + }) +}) diff --git a/lib/src/Components/Profile/Subcomponents/RoutingLinksView.tsx b/lib/src/Components/Profile/Subcomponents/RoutingLinksView.tsx new file mode 100644 index 00000000..f2a1753a --- /dev/null +++ b/lib/src/Components/Profile/Subcomponents/RoutingLinksView.tsx @@ -0,0 +1,52 @@ +import MapPinIcon from '@heroicons/react/24/outline/MapPinIcon' + +import type { Item } from '#types/Item' + +export const RoutingLinksView = ({ item }: { item: Item }) => { + // Only show if item has position coordinates + if (!item.position?.coordinates) return null + + const [longitude, latitude] = item.position.coordinates + + const routingServices = [ + { + name: 'Google Maps', + url: `https://www.google.com/maps/dir/?api=1&destination=${latitude},${longitude}`, + icon: 'πŸ—ΊοΈ', + }, + { + name: 'Apple Maps', + url: `https://maps.apple.com/?daddr=${latitude},${longitude}`, + icon: '🍎', + }, + { + name: 'OpenStreetMap', + url: `https://www.openstreetmap.org/directions?to=${latitude},${longitude}`, + icon: '🌍', + }, + ] + + return ( +
+

+ + Get Directions +

+
+ {routingServices.map((service) => ( + + ))} +
+
+ ) +} diff --git a/lib/src/Components/Profile/Templates/FlexView.tsx b/lib/src/Components/Profile/Templates/FlexView.tsx index e3024c45..71e3d60c 100644 --- a/lib/src/Components/Profile/Templates/FlexView.tsx +++ b/lib/src/Components/Profile/Templates/FlexView.tsx @@ -8,6 +8,7 @@ import { InviteLinkView } from '#components/Profile/Subcomponents/InviteLinkView import { ProfileStartEndView } from '#components/Profile/Subcomponents/ProfileStartEndView' import { ProfileTextView } from '#components/Profile/Subcomponents/ProfileTextView' import { RelationsView } from '#components/Profile/Subcomponents/RelationsView' +import { RoutingLinksView } from '#components/Profile/Subcomponents/RoutingLinksView' import type { Item } from '#types/Item' import type { Key } from 'react' @@ -21,6 +22,7 @@ const componentMap = { crowdfundings: CrowdfundingView, inviteLinks: InviteLinkView, relations: RelationsView, + routingLinks: RoutingLinksView, // weitere Komponenten hier } diff --git a/lib/src/Components/Profile/Templates/OnepagerView.tsx b/lib/src/Components/Profile/Templates/OnepagerView.tsx index 7c2d8077..adb72089 100644 --- a/lib/src/Components/Profile/Templates/OnepagerView.tsx +++ b/lib/src/Components/Profile/Templates/OnepagerView.tsx @@ -2,6 +2,7 @@ import { TextView } from '#components/Map/Subcomponents/ItemPopupComponents' import { ContactInfoView } from '#components/Profile/Subcomponents/ContactInfoView' import { GroupSubHeaderView } from '#components/Profile/Subcomponents/GroupSubHeaderView' +import { RoutingLinksView } from '#components/Profile/Subcomponents/RoutingLinksView' import type { Item } from '#types/Item' @@ -13,6 +14,7 @@ export const OnepagerView = ({ item }: { item: Item }) => { shareBaseUrl={`https://www.wuerdekompass.org/aktivitaeten/gruppensuche/#/gruppe/${item.slug}`} /> {item.user_created?.first_name && } + {/* Description Section */}
diff --git a/lib/src/Components/Profile/Templates/TabsView.tsx b/lib/src/Components/Profile/Templates/TabsView.tsx index 0844f8fa..f1250e6e 100644 --- a/lib/src/Components/Profile/Templates/TabsView.tsx +++ b/lib/src/Components/Profile/Templates/TabsView.tsx @@ -15,6 +15,7 @@ import { useItems } from '#components/Map/hooks/useItems' import { StartEndView, TextView } from '#components/Map/Subcomponents/ItemPopupComponents' import { ActionButton } from '#components/Profile/Subcomponents/ActionsButton' import { LinkedItemsHeaderView } from '#components/Profile/Subcomponents/LinkedItemsHeaderView' +import { RoutingLinksView } from '#components/Profile/Subcomponents/RoutingLinksView' import { TagView } from '#components/Templates/TagView' import { timeAgo } from '#utils/TimeAgo' @@ -107,6 +108,9 @@ export const TabsView = ({
+
+ +
{item.layer?.itemType.questlog && ( <>