UNPKG

stream-chat-react

Version:

React components to create chat conversations or livestream style chat

140 lines (139 loc) 8.07 kB
import React, { useCallback, useEffect, useMemo, useState, } from 'react'; import { useChatContext, useTranslationContext } from '../../context'; import { useMessageComposer } from '../MessageInput'; import { ModalHeader } from '../Modal/ModalHeader'; import { SimpleSwitchField } from '../Form/SwitchField'; import { Dropdown, useDropdownContext } from '../Form/Dropdown'; const MIN_LIVE_LOCATION_SHARE_DURATION = 60 * 1000; // 1 minute; const DEFAULT_SHARE_LOCATION_DURATIONS = [ 15 * 60 * 1000, // 15 minutes 60 * 60 * 1000, // 1 hour 8 * 60 * 60 * 1000, // 8 hours ]; const DefaultGeolocationMap = () => null; export const ShareLocationDialog = ({ close, GeolocationMap = DefaultGeolocationMap, shareDurations = DEFAULT_SHARE_LOCATION_DURATIONS, }) => { const { client } = useChatContext(); const { t } = useTranslationContext(); const messageComposer = useMessageComposer(); const [durations, setDurations] = useState([]); const [selectedDuration, setSelectedDuration] = useState(undefined); const [geolocationPosition, setGeolocationPosition] = useState(null); const [loadingLocation, setLoadingLocation] = useState(false); const [geolocationPositionError, setGeolocationPositionError] = useState(undefined); const validShareDurations = useMemo(() => shareDurations.filter((d) => d >= MIN_LIVE_LOCATION_SHARE_DURATION), [shareDurations]); const openDropdownButtonProps = useMemo(() => ({ children: (() => (React.createElement("div", null, t('duration/Share Location', { milliseconds: selectedDuration ?? durations[0], }))))(), // todo: make it a component }), [durations, selectedDuration, t]); const getPosition = useCallback(() => new Promise((resolve, reject) => { navigator.geolocation.getCurrentPosition((position) => { resolve(position); }, (positionError) => { console.warn(positionError); reject(positionError); }, { timeout: 1000 }); }), []); const setupPositionWatching = useCallback(() => { setLoadingLocation(true); const watch = navigator.geolocation.watchPosition((position) => { setGeolocationPosition(position); setLoadingLocation(false); setGeolocationPositionError(undefined); }, (error) => { setGeolocationPosition(null); setLoadingLocation(false); setGeolocationPositionError(error); }, { timeout: 1000 }); return () => { navigator.geolocation.clearWatch(watch); }; }, []); useEffect(() => setupPositionWatching(), [setupPositionWatching]); return (React.createElement("div", { className: 'str-chat__dialog str-chat__share-location-dialog', "data-testid": 'share-location-dialog' }, React.createElement(ModalHeader, { close: close, title: t('Share Location') }), React.createElement("div", { className: 'str-chat__dialog__body' }, React.createElement(GeolocationMap, { geolocationPositionError: geolocationPositionError, latitude: geolocationPosition?.coords.latitude, loadingLocation: loadingLocation, longitude: geolocationPosition?.coords.longitude, restartLocationWatching: setupPositionWatching }), validShareDurations.length > 0 && (React.createElement("div", { className: 'str-chat__live-location-activation' }, React.createElement(SimpleSwitchField, { checked: durations.length > 0, "data-testid": 'share-location-dialog-live-location-switch', disabled: !geolocationPosition, labelText: t('Share live location for'), onChange: (e) => { e.stopPropagation(); if (durations.length > 0) { setDurations([]); setSelectedDuration(undefined); } else { setDurations(validShareDurations); setSelectedDuration(validShareDurations[0]); } } }), durations.length > 0 && (React.createElement(Dropdown, { openButtonProps: openDropdownButtonProps, placement: 'bottom-start' }, React.createElement(DurationDropdownItems, { durations: durations, selectDuration: setSelectedDuration })))))), React.createElement("div", { className: 'str-chat__dialog__controls' }, React.createElement("button", { className: 'str-chat__dialog__controls-button str-chat__dialog__controls-button--cancel', onClick: () => { messageComposer.locationComposer.initState(); close(); } }, t('Cancel')), React.createElement("button", { className: 'str-chat__dialog__controls-button str-chat__dialog__controls-button--submit', disabled: !geolocationPosition, onClick: async () => { let coords = geolocationPosition && { latitude: geolocationPosition.coords.latitude, longitude: geolocationPosition.coords.longitude, }; if (!coords) { coords = (await getPosition()).coords; } messageComposer.locationComposer.setData({ ...coords, durationMs: selectedDuration, }); close(); }, type: 'submit' }, t('Attach')), React.createElement("button", { className: 'str-chat__dialog__controls-button str-chat__dialog__controls-button--submit', disabled: !geolocationPosition, onClick: async () => { let coords = geolocationPosition && { latitude: geolocationPosition.coords.latitude, longitude: geolocationPosition.coords.longitude, }; if (!coords) { try { coords = (await getPosition()).coords; } catch (e) { client.notifications.addError({ message: t('Failed to retrieve location'), options: { originalError: e instanceof Error ? e : undefined, type: 'browser-api:location:get:failed', }, origin: { emitter: 'ShareLocationDialog' }, }); return; } } messageComposer.locationComposer.setData({ ...coords, durationMs: selectedDuration, }); try { await messageComposer.sendLocation(); } catch (err) { client.notifications.addError({ message: t('Failed to share location'), options: { originalError: err instanceof Error ? err : undefined, type: 'api:location:share:failed', }, origin: { emitter: 'ShareLocationDialog' }, }); return; } close(); }, type: 'submit' }, t('Share'))))); }; const DurationDropdownItems = ({ durations, selectDuration, }) => { const { t } = useTranslationContext(); const { close } = useDropdownContext(); return durations.map((duration) => (React.createElement("button", { className: 'str-chat__live-location-sharing-duration-option', key: `duration-${duration}}`, onClick: () => { selectDuration(duration); close(); }, role: 'option' }, t('duration/Share Location', { milliseconds: duration })))); };