import { useState, useMemo, useEffect, useContext } from 'react' import { ModalType } from '../types/ModalType' import { Event, nip19 } from 'nostr-tools' import { getRelayList } from "../libraries/Nostr" import { useGeolocationData } from "../hooks/useGeolocationData" import { formatTimes, isOpenNow } from '../libraries/decodeDay' import { DraftPlaceContextType, Place } from '../types/Place' import { beaconToDraftPlace } from '../libraries/draftPlace' import { CursorPositionType } from '../providers/GeolocationProvider' import { IdentityContextType, IdentityType } from '../types/IdentityType' import { RelayList } from '../types/NostrRelay' import { MapPin } from './MapPin' import { FancyButton } from './FancyButton' import { Shared } from './Shared' import { ModeContext } from '../providers/ModeProvider' import { useNavigationTarget } from '../hooks/useNavigationTarget' import { TbNavigationFilled as NavIcon } from 'react-icons/tb' import { IdentityContext } from '../providers/IdentityProvider' import { Nip05Verifier } from './Nip05Verifier' import { useNavigate } from 'react-router-dom' type BeaconProps = { currentUserPubkey: string | undefined ownerProfile: (Event & {content: IdentityType }) | undefined beaconData: Place modal: ModalType open: boolean, focusHandler: () => void editHandler: () => void draft: DraftPlaceContextType } const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent) function sendSMS(phoneNumber: string) { const uri = isMobile ? `sms:${phoneNumber}` : `tel:${phoneNumber}` window.open(uri, '_blank') } export const Beacon = ({ currentUserPubkey, ownerProfile, beaconData, modal, open, focusHandler, editHandler, draft }: BeaconProps) => { const [shared, setShared] = useState(false) const { setDraftPlace } = draft const { position, setCursorPosition } = useGeolocationData() const {relays} = useContext(IdentityContext) const relayList: RelayList = getRelayList(relays, ['read']) const picture = ownerProfile?.content?.picture const {setMode} = useContext(ModeContext) const {setTarget} = useNavigationTarget() const navigate = useNavigate() const toggle = () => { if (!modal?.placeForm) { focusHandler() if (!open) { // we are opening the beacon details setCursorPosition(null) setMode(null) } else { // we are closing the beacon details } } } const editPlace = () => { toggle() editHandler() // set cursor to beacon's current coordinates const lnglat: CursorPositionType = { lng: beaconData.content.geometry.coordinates[0], lat: beaconData.content.geometry.coordinates[1] } setCursorPosition(lnglat) // load place data into modal const newPlace = beaconToDraftPlace(beaconData, relayList) // set draft place setDraftPlace(newPlace) modal?.setPlaceForm('edit') setMode(null) } // e is a click event const sharePlace = (e: React.MouseEvent ) => { e.stopPropagation() // copy URL to clipboard const url = window.location.href navigator.clipboard.writeText(url) // show toast setShared(true) } const handleShowProfile = (e: React.MouseEvent) => { e.stopPropagation() toggle() navigate(`/user/${nip19.npubEncode(beaconData.pubkey)}`) } useEffect(() => { if (shared) { setTimeout(() => { setShared(false) }, 3000) } }, [shared]) const mapMarker = useMemo( () => { return (
) // eslint-disable-next-line react-hooks/exhaustive-deps }, [picture, toggle]) const showBeaconInfo = () => { let beaconName = null try { beaconName =

{beaconData.content.properties.name}

} catch (e) { console.log('failed to parse name', e) } let beaconDescription = null try { beaconDescription =

{beaconData.content.properties.description}

} catch (e) { console.log('failed to parse description', e) } let hours = null if (beaconData.content.properties.hours) { try { hours =

{ beaconData.content.properties.hours ? isOpenNow(beaconData.content.properties.hours) ? "🟢 Open Now" : "💤 Not Open Right Now" : null }
{formatTimes(beaconData.content.properties.hours)}

} catch (e) { // console.log('failed to parse hours', e) } } let typeInfo = null try { const currentType = beaconData.content.properties.type if (currentType) { typeInfo =

{currentType.replace(/_/g,' ')}

} } catch (e) { console.log('failed to parse type', e) } let statusInfo = null try { const currentStatus = beaconData.content.properties.status if (currentStatus !== 'OPERATIONAL' || currentStatus === undefined) { // don't render OPERATIONAL because it is implied const currentStatusColor = currentStatus === 'CLOSED_TEMPORARILY' ? 'gray' : 'red' const currentStatusEmoji = currentStatus === 'CLOSED_TEMPORARILY' ? 'â›”' : 'â›”' statusInfo =

{currentStatus ? currentStatus.replace('_',' ') : null} {currentStatusEmoji}

} } catch (e) { console.log('failed to parse status', e) } let tele = null if (beaconData.content?.properties?.phone) tele = {beaconData.content.properties.phone} let authorInfo = null authorInfo =

Created by {ownerProfile?.content?.displayName || ownerProfile?.content?.display_name || ownerProfile?.content?.username || beaconData.pubkey} {/* could add here a lud16 button */} {/* */}

let edit = null try { if (currentUserPubkey === beaconData.pubkey) edit = Edit } catch (e) { console.log(e) } let share = null try { share = } catch (e) { console.log(e) } let sms = null try { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion sms = beaconData.content?.properties?.phone ? : null } catch(e) { console.log(e) } let nav = null try { nav = } catch(e) { console.log(e) } return ( <>
{beaconName} {typeInfo} {statusInfo}
{beaconDescription} {hours} {tele} {authorInfo}
{edit} {share} {sms} {position ? nav : null}
) } const beaconClasses = `beacon ${open ? 'beacon--show' : ''}` return (
{mapMarker} {open ? showBeaconInfo() : null}
) }