|
@@ -38,52 +38,15 @@ const parseTextWithLinks = (text?: string): React.ReactNode => {
|
|
if (!text) return null;
|
|
if (!text) return null;
|
|
|
|
|
|
const urlRegex = /((https?:\/\/[^\s]+)|(?<!\w)(www\.[^\s]+))/g;
|
|
const urlRegex = /((https?:\/\/[^\s]+)|(?<!\w)(www\.[^\s]+))/g;
|
|
- const eventPageRegex = /Event page\s+(https?:\/\/[^\s]+)\s+([^\n]+)/i;
|
|
|
|
|
|
|
|
const result: React.ReactNode[] = [];
|
|
const result: React.ReactNode[] = [];
|
|
let lastIndex = 0;
|
|
let lastIndex = 0;
|
|
|
|
|
|
- const eventMatch = text.match(eventPageRegex);
|
|
|
|
- let handledEvent = false;
|
|
|
|
-
|
|
|
|
- if (eventMatch) {
|
|
|
|
- const [fullMatch, eventUrl, locationCandidate] = eventMatch;
|
|
|
|
- const eventStart = eventMatch.index ?? 0;
|
|
|
|
- const eventEnd = eventStart + fullMatch.length;
|
|
|
|
-
|
|
|
|
- if (eventStart > 0) {
|
|
|
|
- result.push(<Text key="text-before-event">{text.slice(0, eventStart)}</Text>);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- result.push(
|
|
|
|
- <Text
|
|
|
|
- key="event-url"
|
|
|
|
- style={{ color: Colors.ORANGE, textDecorationLine: 'underline' }}
|
|
|
|
- onPress={() => Linking.openURL(eventUrl)}
|
|
|
|
- >
|
|
|
|
- {eventUrl}
|
|
|
|
- </Text>
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- result.push(
|
|
|
|
- <Text
|
|
|
|
- key="event-location"
|
|
|
|
- style={{ color: Colors.ORANGE, textDecorationLine: 'none' }}
|
|
|
|
- onPress={() => openLocation(locationCandidate)}
|
|
|
|
- >
|
|
|
|
- {' ' + locationCandidate.trim()}
|
|
|
|
- </Text>
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- lastIndex = eventEnd;
|
|
|
|
- handledEvent = true;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
Array.from(text.matchAll(urlRegex)).forEach((match, index) => {
|
|
Array.from(text.matchAll(urlRegex)).forEach((match, index) => {
|
|
const matchText = match[0];
|
|
const matchText = match[0];
|
|
const matchIndex = match.index ?? 0;
|
|
const matchIndex = match.index ?? 0;
|
|
|
|
|
|
- if (handledEvent && matchIndex < lastIndex) return;
|
|
|
|
|
|
+ if (matchIndex < lastIndex) return;
|
|
|
|
|
|
if (lastIndex < matchIndex) {
|
|
if (lastIndex < matchIndex) {
|
|
result.push(<Text key={`text-${index}`}>{text.slice(lastIndex, matchIndex)}</Text>);
|
|
result.push(<Text key={`text-${index}`}>{text.slice(lastIndex, matchIndex)}</Text>);
|
|
@@ -120,7 +83,7 @@ const parseTextWithLinks = (text?: string): React.ReactNode => {
|
|
result.push(
|
|
result.push(
|
|
<Text
|
|
<Text
|
|
key={`link-${index}`}
|
|
key={`link-${index}`}
|
|
- style={{ color: Colors.ORANGE, textDecorationLine: 'underline' }}
|
|
|
|
|
|
+ style={{ color: Colors.ORANGE, textDecorationLine: 'none' }}
|
|
onPress={handlePress}
|
|
onPress={handlePress}
|
|
>
|
|
>
|
|
{matchText}
|
|
{matchText}
|
|
@@ -137,46 +100,6 @@ const parseTextWithLinks = (text?: string): React.ReactNode => {
|
|
return result;
|
|
return result;
|
|
};
|
|
};
|
|
|
|
|
|
-const openLocation = async (address: string) => {
|
|
|
|
- const endpoint =
|
|
|
|
- `https://maps.googleapis.com/maps/api/place/findplacefromtext/json` +
|
|
|
|
- `?input=${encodeURIComponent(address)}` +
|
|
|
|
- `&inputtype=textquery` +
|
|
|
|
- `&fields=geometry,formatted_address,name` +
|
|
|
|
- `&key=${GOOGLE_MAP_PLACES_APIKEY}`;
|
|
|
|
-
|
|
|
|
- try {
|
|
|
|
- const response = await fetch(endpoint);
|
|
|
|
- const data = await response.json();
|
|
|
|
-
|
|
|
|
- if (data.status === 'OK' && data.candidates?.length > 0) {
|
|
|
|
- const place = data.candidates[0];
|
|
|
|
- const { lat, lng } = place.geometry.location;
|
|
|
|
- const label = place.name || place.formatted_address || address;
|
|
|
|
- const encodedLabel = encodeURIComponent(label);
|
|
|
|
- const fallbackUrl = `https://www.google.com/maps/search/?api=1&query=${lat},${lng}`;
|
|
|
|
-
|
|
|
|
- let mapsUrl: string;
|
|
|
|
-
|
|
|
|
- if (Platform.OS === 'ios') {
|
|
|
|
- const canOpenGoogleMaps = await Linking.canOpenURL('comgooglemaps://');
|
|
|
|
- mapsUrl = canOpenGoogleMaps
|
|
|
|
- ? `comgooglemaps://?center=${lat},${lng}&q=${encodedLabel}@${lat},${lng}`
|
|
|
|
- : `http://maps.apple.com/?ll=${lat},${lng}&q=${encodedLabel}`;
|
|
|
|
- } else {
|
|
|
|
- mapsUrl = `geo:${lat},${lng}?q=${encodedLabel}`;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- const supported = await Linking.canOpenURL(mapsUrl);
|
|
|
|
- await Linking.openURL(supported ? mapsUrl : fallbackUrl);
|
|
|
|
- } else {
|
|
|
|
- console.warn('Places API did not return valid results:', data.status);
|
|
|
|
- }
|
|
|
|
- } catch (error) {
|
|
|
|
- console.error('Places API error:', error);
|
|
|
|
- }
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
export const Input: FC<Props> = ({
|
|
export const Input: FC<Props> = ({
|
|
onChange,
|
|
onChange,
|
|
placeholder,
|
|
placeholder,
|