From 91e78a12703ab91efcffc31dfb3e5ce934eb9bad Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Sun, 6 Sep 2026 16:58:39 +0100 Subject: [PATCH] postit: add mapsui location picker to rdv form --- src/PostIt/Directory.Packages.props | 2 + .../BillingCommandPageViewModelTests.cs | 20 ++++++ src/PostIt/PostIt/PostIt.csproj | 2 + .../ViewModels/Commands/RdvViewModel.cs | 14 ++++ .../PostIt/Views/Commands/RdvPage.axaml | 12 +++- .../PostIt/Views/Commands/RdvPage.axaml.cs | 65 +++++++++++++++++++ 6 files changed, 114 insertions(+), 1 deletion(-) diff --git a/src/PostIt/Directory.Packages.props b/src/PostIt/Directory.Packages.props index 4dd4b2889..2f27340e9 100644 --- a/src/PostIt/Directory.Packages.props +++ b/src/PostIt/Directory.Packages.props @@ -16,6 +16,8 @@ + + diff --git a/src/PostIt/PostIt.Tests/BillingCommandPageViewModelTests.cs b/src/PostIt/PostIt.Tests/BillingCommandPageViewModelTests.cs index c7b5b926b..da366d284 100644 --- a/src/PostIt/PostIt.Tests/BillingCommandPageViewModelTests.cs +++ b/src/PostIt/PostIt.Tests/BillingCommandPageViewModelTests.cs @@ -115,6 +115,26 @@ public class BillingCommandPageViewModelTests } } + [Fact] + public void ApplyLocationFromMap_sets_coordinates_and_updates_status() + { + var api = new RecordingApi(); + var client = new BillingApiClient(api, "https://business.example/api/v1/"); + var vm = + new CommandFormSummary { Id = 12, ActionName = "Rdv", Title = "Rendez-vous" } + .CreateCommandPageViewModel( + new ActivityInfo { Code = "dev", Name = "Développement" }, + new ActivityUserDisplayItem { PerformerId = "perf-1", UserName = "Alice" }, + client) as RdvViewModel; + + vm!.Address = string.Empty; + vm.ApplyLocationFromMap(48.85661234, 2.35224567); + + Assert.Equal(48.856612, vm.Latitude); + Assert.Equal(2.352246, vm.Longitude); + Assert.Contains("Position sélectionnée", vm.StatusMessage, StringComparison.OrdinalIgnoreCase); + } + [Fact] public async Task InitializeAsync_loads_prestations_for_brush_and_submit_posts_selected_prestation() { diff --git a/src/PostIt/PostIt/PostIt.csproj b/src/PostIt/PostIt/PostIt.csproj index 177e346d3..09632bdf8 100644 --- a/src/PostIt/PostIt/PostIt.csproj +++ b/src/PostIt/PostIt/PostIt.csproj @@ -29,6 +29,8 @@ None All + + diff --git a/src/PostIt/PostIt/ViewModels/Commands/RdvViewModel.cs b/src/PostIt/PostIt/ViewModels/Commands/RdvViewModel.cs index afd0c54bd..44293f03e 100644 --- a/src/PostIt/PostIt/ViewModels/Commands/RdvViewModel.cs +++ b/src/PostIt/PostIt/ViewModels/Commands/RdvViewModel.cs @@ -113,6 +113,20 @@ public partial class RdvViewModel : BillingCommandPageViewModel }; } + public void ApplyLocationFromMap(double latitude, double longitude) + { + Latitude = Math.Round(latitude, 6); + Longitude = Math.Round(longitude, 6); + + if (string.IsNullOrWhiteSpace(Address)) + { + this.SetInfoStatus("Position sélectionnée sur la carte. Complétez l'adresse puis envoyez la commande."); + return; + } + + this.SetInfoStatus("Position sélectionnée sur la carte."); + } + protected override async Task SubmitAsync() { diff --git a/src/PostIt/PostIt/Views/Commands/RdvPage.axaml b/src/PostIt/PostIt/Views/Commands/RdvPage.axaml index 4c88b0108..cee3c5c79 100644 --- a/src/PostIt/PostIt/Views/Commands/RdvPage.axaml +++ b/src/PostIt/PostIt/Views/Commands/RdvPage.axaml @@ -1,12 +1,13 @@ - + + + ("LocationMap"); + if (_locationMap is null) + return; + + var map = new Map(); + map.Layers.Add(OpenStreetMap.CreateTileLayer()); + _locationMap.Map = map; + _locationMap.MapTapped += OnMapTapped; + + DataContextChanged += OnDataContextChanged; + CenterFromViewModel(); + } + + private void OnDataContextChanged(object? sender, System.EventArgs e) + { + CenterFromViewModel(); + } + + private void OnMapTapped(object? sender, MapEventArgs e) + { + if (DataContext is not RdvViewModel vm) + return; + + var (longitude, latitude) = SphericalMercator.ToLonLat(e.WorldPosition.X, e.WorldPosition.Y); + vm.ApplyLocationFromMap(latitude, longitude); + CenterMap(latitude, longitude, zoomLevel: 13); + } + + private void CenterFromViewModel() + { + if (DataContext is not RdvViewModel vm) + { + CenterMap(48.8566, 2.3522, zoomLevel: 4); + return; + } + + if (vm.Latitude.HasValue && vm.Longitude.HasValue) + { + CenterMap(vm.Latitude.Value, vm.Longitude.Value, zoomLevel: 13); + return; + } + + CenterMap(48.8566, 2.3522, zoomLevel: 4); + } + + private void CenterMap(double latitude, double longitude, int zoomLevel) + { + if (_locationMap?.Map is null) + return; + + var (x, y) = SphericalMercator.FromLonLat(longitude, latitude); + _locationMap.Map.Navigator.CenterOn(x, y); + _locationMap.Map.Navigator.ZoomToLevel(zoomLevel); + } }