diff --git a/config/config.exs b/config/config.exs
index 5874de5af..23f3cb4ee 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -210,6 +210,9 @@ config :mobilizon, :maps,
tiles: [
endpoint: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
attribution: "© The OpenStreetMap Contributors"
+ ],
+ routing: [
+ type: :openstreetmap
]
config :mobilizon, :anonymous,
diff --git a/js/schema.graphql b/js/schema.graphql
index c9e3930dd..86f757e80 100644
--- a/js/schema.graphql
+++ b/js/schema.graphql
@@ -238,6 +238,12 @@ type Tag {
related: [Tag]
}
+"Instance map routing configuration"
+type Routing {
+ "The instance's routing type"
+ type: RoutingType
+}
+
"Language information"
type Language {
"The iso-639-3 language code"
@@ -420,6 +426,9 @@ type Events {
type Maps {
"The instance's maps tiles configuration"
tiles: Tiles
+
+ "The instance's maps routing configuration"
+ routing: Routing
}
"Search groups result"
@@ -659,6 +668,14 @@ interface Interactable {
url: String
}
+enum RoutingType {
+ "Redirect to openstreetmap.org's direction endpoint"
+ OPENSTREETMAP
+
+ "Redirect to Google Maps's direction endpoint"
+ GOOGLE_MAPS
+}
+
"A struct containing the id of the deleted object"
type DeletedObject {
id: ID
@@ -2856,7 +2873,7 @@ type PaginatedGroupList {
total: Int
}
-"Instance tiles configuration"
+"Instance map tiles configuration"
type Tiles {
"The instance's tiles endpoint"
endpoint: String
diff --git a/js/src/graphql/config.ts b/js/src/graphql/config.ts
index 33d3e40e2..3dd903581 100644
--- a/js/src/graphql/config.ts
+++ b/js/src/graphql/config.ts
@@ -51,6 +51,9 @@ export const CONFIG = gql`
endpoint
attribution
}
+ routing {
+ type
+ }
}
geocoding {
provider
diff --git a/js/src/i18n/en_US.json b/js/src/i18n/en_US.json
index c4a686b25..24f6c7b79 100644
--- a/js/src/i18n/en_US.json
+++ b/js/src/i18n/en_US.json
@@ -813,12 +813,15 @@
"View all events": "View all events",
"You will find here all the events you have created or of which you are a participant.": "You will find here all the events you have created or of which you are a participant.",
"Create event": "Create event",
- "You didn't create or join any event yet": "You didn't create or join any event yet",
+ "You didn't create or join any event yet.": "You didn't create or join any event yet.",
"create an event": "create an event",
"explore the events": "explore the events",
"Do you wish to {create_event} or {explore_events}?": "Do you wish to {create_event} or {explore_events}?",
- "You are not part of any group": "You are not part of any group",
+ "You are not part of any group.": "You are not part of any group.",
"create a group": "create a group",
"explore the groups": "explore the groups",
- "Do you wish to {create_group} or {explore_groups}?": "Do you wish to {create_group} or {explore_groups}?"
+ "Do you wish to {create_group} or {explore_groups}?": "Do you wish to {create_group} or {explore_groups}?",
+ "Type or select a date…": "Type or select a date…",
+ "Getting there": "Getting there",
+ "Groups are not enabled on this instance.": "Groups are not enabled on this instance."
}
diff --git a/js/src/i18n/fr_FR.json b/js/src/i18n/fr_FR.json
index 8d4b9a144..f3a5e6570 100644
--- a/js/src/i18n/fr_FR.json
+++ b/js/src/i18n/fr_FR.json
@@ -914,5 +914,8 @@
"You are not part of any group.": "Vous ne faites partie d'aucun groupe.",
"create a group": "créer un groupe",
"explore the groups": "explorer les groupes",
- "Do you wish to {create_group} or {explore_groups}?": "Voulez-vous {create_group} ou {explore_groups} ?"
+ "Do you wish to {create_group} or {explore_groups}?": "Voulez-vous {create_group} ou {explore_groups} ?",
+ "Type or select a date…": "Entrez ou sélectionnez une date…",
+ "Getting there": "S'y rendre",
+ "Groups are not enabled on this instance.": "Les groupes ne sont pas activés sur cette instance."
}
diff --git a/js/src/types/address.model.ts b/js/src/types/address.model.ts
index 6bc2f7052..7ba83b53d 100644
--- a/js/src/types/address.model.ts
+++ b/js/src/types/address.model.ts
@@ -15,6 +15,12 @@ export interface IAddress {
originId?: string;
}
+export interface IPoiInfo {
+ name: string;
+ alternativeName: string;
+ poiIcon: IPOIIcon;
+}
+
export class Address implements IAddress {
country = "";
@@ -54,7 +60,7 @@ export class Address implements IAddress {
this.originId = hash.originId;
}
- get poiInfos(): { name: string; alternativeName: string; poiIcon: IPOIIcon } {
+ get poiInfos(): IPoiInfo {
/* generate name corresponding to poi type */
let name = "";
let alternativeName = "";
diff --git a/js/src/types/config.model.ts b/js/src/types/config.model.ts
index af43f666e..6d391d0a8 100644
--- a/js/src/types/config.model.ts
+++ b/js/src/types/config.model.ts
@@ -1,4 +1,4 @@
-import { InstancePrivacyType, InstanceTermsType } from "./enums";
+import { InstancePrivacyType, InstanceTermsType, RoutingType } from "./enums";
import type { IProvider } from "./resource";
export interface IOAuthProvider {
@@ -58,6 +58,9 @@ export interface IConfig {
endpoint: string;
attribution: string | null;
};
+ routing: {
+ type: RoutingType;
+ };
};
geocoding: {
provider: string;
diff --git a/js/src/types/enums.ts b/js/src/types/enums.ts
index 9eeeb5af9..a081a3463 100644
--- a/js/src/types/enums.ts
+++ b/js/src/types/enums.ts
@@ -160,3 +160,15 @@ export enum Openness {
MODERATED = "MODERATED",
OPEN = "OPEN",
}
+
+export enum RoutingType {
+ OPENSTREETMAP = "OPENSTREETMAP",
+ GOOGLE_MAPS = "GOOGLE_MAPS",
+}
+
+export enum RoutingTransportationType {
+ FOOT = "FOOT",
+ BIKE = "BIKE",
+ TRANSIT = "TRANSIT",
+ CAR = "CAR",
+}
diff --git a/js/src/views/Event/Event.vue b/js/src/views/Event/Event.vue
old mode 100644
new mode 100755
index 5c665e347..290dee24f
--- a/js/src/views/Event/Event.vue
+++ b/js/src/views/Event/Event.vue
@@ -84,9 +84,9 @@
{{ tag.title }}
- {{
- $t("Draft")
- }}
+ {{ $t("Draft") }}
+
{{ $t("Show map") }}
@@ -526,8 +526,8 @@
class="button"
ref="cancelButton"
@click="isJoinConfirmationModalActive = false"
- >{{ $t("Cancel") }}
+ >{{ $t("Cancel") }}
+
{{ $t("Confirm my participation") }}
@@ -537,17 +537,77 @@
-
@@ -563,6 +623,8 @@ import {
EventStatus,
EventVisibility,
ParticipantRole,
+ RoutingTransportationType,
+ RoutingType,
} from "@/types/enums";
import {
EVENT_PERSON_PARTICIPATION,
@@ -602,6 +664,7 @@ import ActorCard from "../../components/Account/ActorCard.vue";
import PopoverActorCard from "../../components/Account/PopoverActorCard.vue";
import { IParticipant } from "../../types/participant.model";
+// noinspection TypeScriptValidateTypes
@Component({
components: {
EventMetadataBlock,
@@ -734,6 +797,65 @@ export default class Event extends EventMixin {
messageForConfirmation = "";
+ RoutingParamType = {
+ [RoutingType.OPENSTREETMAP]: {
+ [RoutingTransportationType.FOOT]: "engine=fossgis_osrm_foot",
+ [RoutingTransportationType.BIKE]: "engine=fossgis_osrm_bike",
+ [RoutingTransportationType.TRANSIT]: null,
+ [RoutingTransportationType.CAR]: "engine=fossgis_osrm_car",
+ },
+ [RoutingType.GOOGLE_MAPS]: {
+ [RoutingTransportationType.FOOT]: "dirflg=w",
+ [RoutingTransportationType.BIKE]: "dirflg=b",
+ [RoutingTransportationType.TRANSIT]: "dirflg=r",
+ [RoutingTransportationType.CAR]: "driving",
+ },
+ };
+
+ makeNavigationPath(
+ transportationType: RoutingTransportationType
+ ): string | undefined {
+ const geometry = this.physicalAddress?.geom;
+ if (geometry) {
+ const routingType = this.config.maps.routing.type;
+ /**
+ * build urls to routing map
+ */
+ if (!this.RoutingParamType[routingType][transportationType]) {
+ return;
+ }
+
+ const urlGeometry = geometry.split(";").reverse().join(",");
+
+ switch (routingType) {
+ case RoutingType.GOOGLE_MAPS:
+ return `https://maps.google.com/?saddr=Current+Location&daddr=${urlGeometry}&${this.RoutingParamType[routingType][transportationType]}`;
+ case RoutingType.OPENSTREETMAP:
+ default: {
+ const bboxX = geometry.split(";").reverse()[0];
+ const bboxY = geometry.split(";").reverse()[1];
+ return `https://www.openstreetmap.org/directions?from=&to=${urlGeometry}&${this.RoutingParamType[routingType][transportationType]}#map=14/${bboxX}/${bboxY}`;
+ }
+ }
+ }
+ }
+
+ get addressLinkToRouteByCar(): undefined | string {
+ return this.makeNavigationPath(RoutingTransportationType.CAR);
+ }
+
+ get addressLinkToRouteByBike(): undefined | string {
+ return this.makeNavigationPath(RoutingTransportationType.BIKE);
+ }
+
+ get addressLinkToRouteByFeet(): undefined | string {
+ return this.makeNavigationPath(RoutingTransportationType.FOOT);
+ }
+
+ get addressLinkToRouteByTransit(): undefined | string {
+ return this.makeNavigationPath(RoutingTransportationType.TRANSIT);
+ }
+
get eventTitle(): undefined | string {
if (!this.event) return undefined;
return this.event.title;
@@ -1096,6 +1218,7 @@ export default class Event extends EventMixin {
get physicalAddress(): Address | null {
if (!this.event.physicalAddress) return null;
+
return new Address(this.event.physicalAddress);
}
@@ -1225,6 +1348,7 @@ div.sidebar {
a {
text-decoration: none;
}
+
span {
&.tag {
margin: 0 2px;
@@ -1389,9 +1513,31 @@ a.participations-link {
font-size: 1rem;
}
-div.map {
- height: 900px;
- width: 100%;
- padding: 25px 5px 0;
+.map-modal {
+ .modal-card-head {
+ justify-content: flex-end;
+ button.delete {
+ margin-right: 1rem;
+ }
+ }
+
+ section.map {
+ height: calc(100% - 8rem);
+ width: calc(100% - 20px);
+ }
+
+ section.map-footer {
+ p.address {
+ margin: 1rem auto;
+ }
+ div.buttons {
+ justify-content: center;
+ }
+ }
+}
+
+.no-border {
+ border: 0;
+ cursor: auto;
}
diff --git a/js/src/views/Search.vue b/js/src/views/Search.vue
index e02794676..765c96899 100644
--- a/js/src/views/Search.vue
+++ b/js/src/views/Search.vue
@@ -127,7 +127,7 @@
- {{ $t("Groups are not enabled on your server.") }}
+ {{ $t("Groups are not enabled on this instance.") }}
diff --git a/js/tests/unit/specs/mocks/config.ts b/js/tests/unit/specs/mocks/config.ts
index 84c4f80b1..271d71ce3 100644
--- a/js/tests/unit/specs/mocks/config.ts
+++ b/js/tests/unit/specs/mocks/config.ts
@@ -56,6 +56,9 @@ export const configMock = {
attribution: "© The OpenStreetMap Contributors",
endpoint: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
},
+ routing: {
+ type: "OPENSTREETMAP",
+ },
},
name: "Mobilizon",
registrationsAllowlist: false,
diff --git a/lib/graphql/resolvers/config.ex b/lib/graphql/resolvers/config.ex
index 181caa0e4..a1b8c3e8c 100644
--- a/lib/graphql/resolvers/config.ex
+++ b/lib/graphql/resolvers/config.ex
@@ -117,6 +117,9 @@ defmodule Mobilizon.GraphQL.Resolvers.Config do
tiles: %{
endpoint: Config.instance_maps_tiles_endpoint(),
attribution: Config.instance_maps_tiles_attribution()
+ },
+ routing: %{
+ type: Config.instance_maps_routing_type()
}
},
resource_providers: Config.instance_resource_providers(),
diff --git a/lib/graphql/schema/config.ex b/lib/graphql/schema/config.ex
index c48058446..a2d9d02ab 100644
--- a/lib/graphql/schema/config.ex
+++ b/lib/graphql/schema/config.ex
@@ -106,16 +106,29 @@ defmodule Mobilizon.GraphQL.Schema.ConfigType do
"""
object :maps do
field(:tiles, :tiles, description: "The instance's maps tiles configuration")
+ field(:routing, :routing, description: "The instance's maps routing configuration")
end
@desc """
- Instance tiles configuration
+ Instance map tiles configuration
"""
object :tiles do
field(:endpoint, :string, description: "The instance's tiles endpoint")
field(:attribution, :string, description: "The instance's tiles attribution text")
end
+ @desc """
+ Instance map routing configuration
+ """
+ object :routing do
+ field(:type, :routing_type, description: "The instance's routing type")
+ end
+
+ enum :routing_type do
+ value(:openstreetmap, description: "Redirect to openstreetmap.org's direction endpoint")
+ value(:google_maps, description: "Redirect to Google Maps's direction endpoint")
+ end
+
@desc """
Instance anonymous configuration
"""
diff --git a/lib/mobilizon/config.ex b/lib/mobilizon/config.ex
index 87ad8ce5c..600ae63c8 100644
--- a/lib/mobilizon/config.ex
+++ b/lib/mobilizon/config.ex
@@ -151,6 +151,10 @@ defmodule Mobilizon.Config do
def instance_maps_tiles_attribution,
do: Application.get_env(:mobilizon, :maps)[:tiles][:attribution]
+ @spec instance_maps_routing_type :: atom()
+ def instance_maps_routing_type,
+ do: Application.get_env(:mobilizon, :maps)[:routing][:type]
+
@spec anonymous_participation? :: boolean
def anonymous_participation?,
do: Application.get_env(:mobilizon, :anonymous)[:participation][:allowed]
diff --git a/yarn.lock b/yarn.lock
new file mode 100644
index 000000000..fb57ccd13
--- /dev/null
+++ b/yarn.lock
@@ -0,0 +1,4 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+