Merge branch 'events' into 'develop'
Revert "Remove 'show on map' for now" See merge request soapbox-pub/soapbox!1982
This commit is contained in:
commit
523e573fd7
|
@ -249,6 +249,7 @@ const submitEvent = () =>
|
||||||
status,
|
status,
|
||||||
start_time: startTime,
|
start_time: startTime,
|
||||||
join_mode: joinMode,
|
join_mode: joinMode,
|
||||||
|
content_type: 'text/markdown',
|
||||||
};
|
};
|
||||||
|
|
||||||
if (endTime) params.end_time = endTime;
|
if (endTime) params.end_time = endTime;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import { FormattedDate, FormattedMessage } from 'react-intl';
|
import { FormattedDate, FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import { openModal } from 'soapbox/actions/modals';
|
||||||
import { fetchStatus } from 'soapbox/actions/statuses';
|
import { fetchStatus } from 'soapbox/actions/statuses';
|
||||||
import MissingIndicator from 'soapbox/components/missing-indicator';
|
import MissingIndicator from 'soapbox/components/missing-indicator';
|
||||||
import StatusContent from 'soapbox/components/status-content';
|
import StatusContent from 'soapbox/components/status-content';
|
||||||
|
@ -8,7 +9,7 @@ import StatusMedia from 'soapbox/components/status-media';
|
||||||
import TranslateButton from 'soapbox/components/translate-button';
|
import TranslateButton from 'soapbox/components/translate-button';
|
||||||
import { HStack, Icon, Stack, Text } from 'soapbox/components/ui';
|
import { HStack, Icon, Stack, Text } from 'soapbox/components/ui';
|
||||||
import QuotedStatus from 'soapbox/features/status/containers/quoted-status-container';
|
import QuotedStatus from 'soapbox/features/status/containers/quoted-status-container';
|
||||||
import { useAppDispatch, useAppSelector, useSettings } from 'soapbox/hooks';
|
import { useAppDispatch, useAppSelector, useSettings, useSoapboxConfig } from 'soapbox/hooks';
|
||||||
import { makeGetStatus } from 'soapbox/selectors';
|
import { makeGetStatus } from 'soapbox/selectors';
|
||||||
import { defaultMediaVisibility } from 'soapbox/utils/status';
|
import { defaultMediaVisibility } from 'soapbox/utils/status';
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ const EventInformation: React.FC<IEventInformation> = ({ params }) => {
|
||||||
|
|
||||||
const status = useAppSelector(state => getStatus(state, { id: params.statusId })) as StatusEntity;
|
const status = useAppSelector(state => getStatus(state, { id: params.statusId })) as StatusEntity;
|
||||||
|
|
||||||
|
const { tileServer } = useSoapboxConfig();
|
||||||
const settings = useSettings();
|
const settings = useSettings();
|
||||||
const displayMedia = settings.get('displayMedia') as string;
|
const displayMedia = settings.get('displayMedia') as string;
|
||||||
|
|
||||||
|
@ -46,6 +48,14 @@ const EventInformation: React.FC<IEventInformation> = ({ params }) => {
|
||||||
setShowMedia(!showMedia);
|
setShowMedia(!showMedia);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleShowMap: React.MouseEventHandler<HTMLAnchorElement> = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
dispatch(openModal('EVENT_MAP', {
|
||||||
|
statusId: status.id,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
const renderEventLocation = useCallback(() => {
|
const renderEventLocation = useCallback(() => {
|
||||||
const event = status!.event!;
|
const event = status!.event!;
|
||||||
|
|
||||||
|
@ -64,6 +74,12 @@ const EventInformation: React.FC<IEventInformation> = ({ params }) => {
|
||||||
<br />
|
<br />
|
||||||
</>)}
|
</>)}
|
||||||
{[event.location.get('postalCode'), event.location.get('locality'), event.location.get('country')].filter(text => text).join(', ')}
|
{[event.location.get('postalCode'), event.location.get('locality'), event.location.get('country')].filter(text => text).join(', ')}
|
||||||
|
{tileServer && event.location.get('latitude') && (<>
|
||||||
|
<br />
|
||||||
|
<a href='#' className='text-primary-600 dark:text-accent-blue hover:underline' onClick={handleShowMap}>
|
||||||
|
<FormattedMessage id='event.show_on_map' defaultMessage='Show on map' />
|
||||||
|
</a>
|
||||||
|
</>)}
|
||||||
</Text>
|
</Text>
|
||||||
</HStack>
|
</HStack>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
|
@ -22,7 +22,7 @@ import {
|
||||||
Toggle,
|
Toggle,
|
||||||
} from 'soapbox/components/ui';
|
} from 'soapbox/components/ui';
|
||||||
import ThemeSelector from 'soapbox/features/ui/components/theme-selector';
|
import ThemeSelector from 'soapbox/features/ui/components/theme-selector';
|
||||||
import { useAppSelector, useAppDispatch } from 'soapbox/hooks';
|
import { useAppSelector, useAppDispatch, useFeatures } from 'soapbox/hooks';
|
||||||
import { normalizeSoapboxConfig } from 'soapbox/normalizers';
|
import { normalizeSoapboxConfig } from 'soapbox/normalizers';
|
||||||
|
|
||||||
import ColorWithPicker from './components/color-with-picker';
|
import ColorWithPicker from './components/color-with-picker';
|
||||||
|
@ -54,6 +54,8 @@ const messages = defineMessages({
|
||||||
singleUserModeProfileHint: { id: 'soapbox_config.single_user_mode_profile_hint', defaultMessage: '@handle' },
|
singleUserModeProfileHint: { id: 'soapbox_config.single_user_mode_profile_hint', defaultMessage: '@handle' },
|
||||||
feedInjectionLabel: { id: 'soapbox_config.feed_injection_label', defaultMessage: 'Feed injection' },
|
feedInjectionLabel: { id: 'soapbox_config.feed_injection_label', defaultMessage: 'Feed injection' },
|
||||||
feedInjectionHint: { id: 'soapbox_config.feed_injection_hint', defaultMessage: 'Inject the feed with additional content, such as suggested profiles.' },
|
feedInjectionHint: { id: 'soapbox_config.feed_injection_hint', defaultMessage: 'Inject the feed with additional content, such as suggested profiles.' },
|
||||||
|
tileServerLabel: { id: 'soapbox_config.tile_server_label', defaultMessage: 'Map tile server' },
|
||||||
|
tileServerAttributionLabel: { id: 'soapbox_config.tile_server_attribution_label', defaultMessage: 'Map tiles attribution' },
|
||||||
});
|
});
|
||||||
|
|
||||||
type ValueGetter<T = Element> = (e: React.ChangeEvent<T>) => any;
|
type ValueGetter<T = Element> = (e: React.ChangeEvent<T>) => any;
|
||||||
|
@ -72,6 +74,8 @@ const SoapboxConfig: React.FC = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
const features = useFeatures();
|
||||||
|
|
||||||
const initialData = useAppSelector(state => state.soapbox);
|
const initialData = useAppSelector(state => state.soapbox);
|
||||||
|
|
||||||
const [isLoading, setLoading] = useState(false);
|
const [isLoading, setLoading] = useState(false);
|
||||||
|
@ -345,6 +349,32 @@ const SoapboxConfig: React.FC = () => {
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
|
{features.events && (
|
||||||
|
<>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle title={<FormattedMessage id='soapbox_config.headings.events' defaultMessage='Events' />} />
|
||||||
|
</CardHeader>
|
||||||
|
|
||||||
|
<FormGroup labelText={intl.formatMessage(messages.tileServerLabel)}>
|
||||||
|
<Input
|
||||||
|
type='text'
|
||||||
|
placeholder={intl.formatMessage(messages.tileServerLabel)}
|
||||||
|
value={soapbox.tileServer}
|
||||||
|
onChange={handleChange(['tileServer'], (e) => e.target.value)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
|
||||||
|
<FormGroup labelText={intl.formatMessage(messages.tileServerAttributionLabel)}>
|
||||||
|
<Input
|
||||||
|
type='text'
|
||||||
|
placeholder={intl.formatMessage(messages.tileServerAttributionLabel)}
|
||||||
|
value={soapbox.tileServerAttribution}
|
||||||
|
onChange={handleChange(['tileServerAttribution'], (e) => e.target.value)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle title={<FormattedMessage id='soapbox_config.headings.cryptocurrency' defaultMessage='Cryptocurrency' />} />
|
<CardTitle title={<FormattedMessage id='soapbox_config.headings.cryptocurrency' defaultMessage='Cryptocurrency' />} />
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|
|
@ -43,9 +43,6 @@ const LinkFooter: React.FC = (): JSX.Element => {
|
||||||
{features.profileDirectory && (
|
{features.profileDirectory && (
|
||||||
<FooterLink to='/directory'><FormattedMessage id='navigation_bar.profile_directory' defaultMessage='Profile directory' /></FooterLink>
|
<FooterLink to='/directory'><FormattedMessage id='navigation_bar.profile_directory' defaultMessage='Profile directory' /></FooterLink>
|
||||||
)}
|
)}
|
||||||
{features.events && (
|
|
||||||
<FooterLink to='/events'><FormattedMessage id='navigation_bar.events' defaultMessage='Events' /></FooterLink>
|
|
||||||
)}
|
|
||||||
<FooterLink to='/blocks'><FormattedMessage id='navigation_bar.blocks' defaultMessage='Blocks' /></FooterLink>
|
<FooterLink to='/blocks'><FormattedMessage id='navigation_bar.blocks' defaultMessage='Blocks' /></FooterLink>
|
||||||
<FooterLink to='/mutes'><FormattedMessage id='navigation_bar.mutes' defaultMessage='Mutes' /></FooterLink>
|
<FooterLink to='/mutes'><FormattedMessage id='navigation_bar.mutes' defaultMessage='Mutes' /></FooterLink>
|
||||||
{features.filters && (
|
{features.filters && (
|
||||||
|
|
|
@ -33,6 +33,7 @@ import {
|
||||||
ComposeEventModal,
|
ComposeEventModal,
|
||||||
JoinEventModal,
|
JoinEventModal,
|
||||||
AccountModerationModal,
|
AccountModerationModal,
|
||||||
|
EventMapModal,
|
||||||
EventParticipantsModal,
|
EventParticipantsModal,
|
||||||
PolicyModal,
|
PolicyModal,
|
||||||
} from 'soapbox/features/ui/util/async-components';
|
} from 'soapbox/features/ui/util/async-components';
|
||||||
|
@ -75,6 +76,7 @@ const MODAL_COMPONENTS = {
|
||||||
'COMPOSE_EVENT': ComposeEventModal,
|
'COMPOSE_EVENT': ComposeEventModal,
|
||||||
'JOIN_EVENT': JoinEventModal,
|
'JOIN_EVENT': JoinEventModal,
|
||||||
'ACCOUNT_MODERATION': AccountModerationModal,
|
'ACCOUNT_MODERATION': AccountModerationModal,
|
||||||
|
'EVENT_MAP': EventMapModal,
|
||||||
'EVENT_PARTICIPANTS': EventParticipantsModal,
|
'EVENT_PARTICIPANTS': EventParticipantsModal,
|
||||||
'POLICY': PolicyModal,
|
'POLICY': PolicyModal,
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
import L from 'leaflet';
|
||||||
|
import React, { useCallback, useEffect, useRef } from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import { Button, Modal, Stack } from 'soapbox/components/ui';
|
||||||
|
import { useAppSelector, useSoapboxConfig } from 'soapbox/hooks';
|
||||||
|
import { makeGetStatus } from 'soapbox/selectors';
|
||||||
|
|
||||||
|
import type { Status as StatusEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
import 'leaflet/dist/leaflet.css';
|
||||||
|
|
||||||
|
L.Icon.Default.mergeOptions({
|
||||||
|
iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
|
||||||
|
iconUrl: require('leaflet/dist/images/marker-icon.png'),
|
||||||
|
shadowUrl: require('leaflet/dist/images/marker-shadow.png'),
|
||||||
|
});
|
||||||
|
|
||||||
|
interface IEventMapModal {
|
||||||
|
onClose: (type: string) => void,
|
||||||
|
statusId: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
const EventMapModal: React.FC<IEventMapModal> = ({ onClose, statusId }) => {
|
||||||
|
const { tileServer, tileServerAttribution } = useSoapboxConfig();
|
||||||
|
|
||||||
|
const getStatus = useCallback(makeGetStatus(), []);
|
||||||
|
const status = useAppSelector(state => getStatus(state, { id: statusId })) as StatusEntity;
|
||||||
|
const location = status.event!.location!;
|
||||||
|
|
||||||
|
const map = useRef<L.Map>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const latlng: [number, number] = [+location.get('latitude'), +location.get('longitude')];
|
||||||
|
|
||||||
|
map.current = L.map('event-map').setView(latlng, 15);
|
||||||
|
|
||||||
|
L.marker(latlng, {
|
||||||
|
title: location.get('name'),
|
||||||
|
}).addTo(map.current);
|
||||||
|
|
||||||
|
L.tileLayer(tileServer, {
|
||||||
|
attribution: tileServerAttribution,
|
||||||
|
}).addTo(map.current);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
map.current?.remove();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onClickClose = () => {
|
||||||
|
onClose('EVENT_MAP');
|
||||||
|
};
|
||||||
|
|
||||||
|
const onClickNavigate = () => {
|
||||||
|
window.open(`https://www.openstreetmap.org/directions?from=&to=${location.get('latitude')},${location.get('longitude')}#map=14/${location.get('latitude')}/${location.get('longitude')}`, '_blank');
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title={<FormattedMessage id='column.event_map' defaultMessage='Event location' />}
|
||||||
|
onClose={onClickClose}
|
||||||
|
width='2xl'
|
||||||
|
>
|
||||||
|
<Stack alignItems='center' space={6}>
|
||||||
|
<div className='h-96 w-full' id='event-map' />
|
||||||
|
<Button onClick={onClickNavigate} icon={require('@tabler/icons/gps.svg')}>
|
||||||
|
<FormattedMessage id='event_map.navigate' defaultMessage='Navigate' />
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EventMapModal;
|
|
@ -530,6 +530,10 @@ export function EventDiscussion() {
|
||||||
return import(/* webpackChunkName: "features/event" */'../../event/event-discussion');
|
return import(/* webpackChunkName: "features/event" */'../../event/event-discussion');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function EventMapModal() {
|
||||||
|
return import(/* webpackChunkName: "modals/event-map-modal" */'../components/modals/event-map-modal');
|
||||||
|
}
|
||||||
|
|
||||||
export function EventParticipantsModal() {
|
export function EventParticipantsModal() {
|
||||||
return import(/* webpackChunkName: "modals/event-participants-modal" */'../components/modals/event-participants-modal');
|
return import(/* webpackChunkName: "modals/event-participants-modal" */'../components/modals/event-participants-modal');
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,8 @@ export const SoapboxConfigRecord = ImmutableRecord({
|
||||||
displayCta: true,
|
displayCta: true,
|
||||||
/** Whether to inject suggested profiles into the Home feed. */
|
/** Whether to inject suggested profiles into the Home feed. */
|
||||||
feedInjection: true,
|
feedInjection: true,
|
||||||
|
tileServer: '',
|
||||||
|
tileServerAttribution: '',
|
||||||
}, 'SoapboxConfig');
|
}, 'SoapboxConfig');
|
||||||
|
|
||||||
type SoapboxConfigMap = ImmutableMap<string, any>;
|
type SoapboxConfigMap = ImmutableMap<string, any>;
|
||||||
|
|
|
@ -76,6 +76,7 @@
|
||||||
"@types/escape-html": "^1.0.1",
|
"@types/escape-html": "^1.0.1",
|
||||||
"@types/http-link-header": "^1.0.3",
|
"@types/http-link-header": "^1.0.3",
|
||||||
"@types/jest": "^28.1.4",
|
"@types/jest": "^28.1.4",
|
||||||
|
"@types/leaflet": "^1.8.0",
|
||||||
"@types/lodash": "^4.14.180",
|
"@types/lodash": "^4.14.180",
|
||||||
"@types/object-assign": "^4.0.30",
|
"@types/object-assign": "^4.0.30",
|
||||||
"@types/object-fit-images": "^3.2.3",
|
"@types/object-fit-images": "^3.2.3",
|
||||||
|
@ -139,6 +140,7 @@
|
||||||
"intl-pluralrules": "^1.3.1",
|
"intl-pluralrules": "^1.3.1",
|
||||||
"is-nan": "^1.2.1",
|
"is-nan": "^1.2.1",
|
||||||
"jsdoc": "~3.6.7",
|
"jsdoc": "~3.6.7",
|
||||||
|
"leaflet": "^1.8.0",
|
||||||
"libphonenumber-js": "^1.10.8",
|
"libphonenumber-js": "^1.10.8",
|
||||||
"line-awesome": "^1.3.0",
|
"line-awesome": "^1.3.0",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
|
|
|
@ -13,6 +13,7 @@ const rules: RuleSetRule[] = [{
|
||||||
include: [
|
include: [
|
||||||
resolve('app', 'assets', 'images'),
|
resolve('app', 'assets', 'images'),
|
||||||
resolve('node_modules', 'emoji-datasource'),
|
resolve('node_modules', 'emoji-datasource'),
|
||||||
|
resolve('node_modules', 'leaflet'),
|
||||||
],
|
],
|
||||||
generator: {
|
generator: {
|
||||||
filename: 'packs/images/[name]-[contenthash:8][ext]',
|
filename: 'packs/images/[name]-[contenthash:8][ext]',
|
||||||
|
|
17
yarn.lock
17
yarn.lock
|
@ -2550,6 +2550,11 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
|
"@types/geojson@*":
|
||||||
|
version "7946.0.10"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.10.tgz#6dfbf5ea17142f7f9a043809f1cd4c448cb68249"
|
||||||
|
integrity sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==
|
||||||
|
|
||||||
"@types/graceful-fs@^4.1.3":
|
"@types/graceful-fs@^4.1.3":
|
||||||
version "4.1.5"
|
version "4.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15"
|
resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15"
|
||||||
|
@ -2658,6 +2663,13 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
||||||
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
|
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
|
||||||
|
|
||||||
|
"@types/leaflet@^1.8.0":
|
||||||
|
version "1.8.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.8.0.tgz#dc92d3e868fb6d5067b4b59fa08cd4441f84fabe"
|
||||||
|
integrity sha512-+sXFmiJTFdhaXXIGFlV5re9AdqtAODoXbGAvxx02e5SHXL3ir7ClP5J7pahO8VmzKY3dth4RUS1nf2BTT+DW1A==
|
||||||
|
dependencies:
|
||||||
|
"@types/geojson" "*"
|
||||||
|
|
||||||
"@types/lodash@^4.14.180":
|
"@types/lodash@^4.14.180":
|
||||||
version "4.14.180"
|
version "4.14.180"
|
||||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.180.tgz#4ab7c9ddfc92ec4a887886483bc14c79fb380670"
|
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.180.tgz#4ab7c9ddfc92ec4a887886483bc14c79fb380670"
|
||||||
|
@ -7953,6 +7965,11 @@ language-tags@^1.0.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
language-subtag-registry "~0.3.2"
|
language-subtag-registry "~0.3.2"
|
||||||
|
|
||||||
|
leaflet@^1.8.0:
|
||||||
|
version "1.8.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.8.0.tgz#4615db4a22a304e8e692cae9270b983b38a2055e"
|
||||||
|
integrity sha512-gwhMjFCQiYs3x/Sf+d49f10ERXaEFCPr+nVTryhAW8DWbMGqJqt9G4XuIaHmFW08zYvhgdzqXGr8AlW8v8dQkA==
|
||||||
|
|
||||||
leven@^3.1.0:
|
leven@^3.1.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
|
resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
|
||||||
|
|
Loading…
Reference in New Issue