postit: add billing query details page and refresh rc14 changelog
This commit is contained in:
parent
c2574ac1d4
commit
dc42b6ed0c
8 changed files with 444 additions and 31 deletions
10
CHANGELOG.md
10
CHANGELOG.md
|
|
@ -4,13 +4,23 @@
|
|||
|
||||
### Added
|
||||
|
||||
* [PostIt] Ajout d'un `BillingQueryDetailsPageViewModel` et de sa page associee pour afficher le detail d'une commande billing depuis l'historique.
|
||||
* [PostIt] Ajout d'un mode detail avec section metier (statut, date, description, motif, infos) et section technique repliable (code, client, provision, lieu, prestations).
|
||||
* [PostIt] Ajout d'un badge de statut enrichi (couleur + pictogramme) sur le detail d'une commande pour visualiser l'etat en un coup d'oeil.
|
||||
* [PostIt] Ajout d'un bloc d'actions rapide en tete du detail (`Retour`, `Ouvrir en edition`) pour eviter le scroll jusqu'au bas de page.
|
||||
* [PostIt] Ajout d'un style monospace sur les metadonnees techniques (code billing, client, provision, lieu, prestations) pour faciliter la lecture des identifiants et valeurs brutes.
|
||||
|
||||
### Changed
|
||||
|
||||
* [PostIt] Le bouton d'ouverture depuis la liste billing ouvre maintenant une page de detail dediee avant l'eventuelle edition.
|
||||
* [PostIt] Amelioration UX des pages billing: badges de statut colores, actions remontees en haut de page, et typographie monospace sur les metadonnees techniques.
|
||||
|
||||
### Fixed
|
||||
|
||||
* [Yavsc.Api] Correction d'un 500 sur le refresh du catalogue d'activites lorsque `Activity.Description` est `NULL` en base (nullabilite explicite + projection null-safe + gardes sur codes vides).
|
||||
* [Yavsc.Api] Correction des erreurs 400/500 sur les routes billing (`Rdv`, `Brush`, `MBrush`) en imposant `ClientId` depuis l'utilisateur authentifie et en ignorant les champs server-owned lors de la validation modele.
|
||||
* [Yavsc.Api] Correction du `PUT /api/v1/billing/Rdv/{id}`: mise a jour controlee de l'entite existante (et non remplacement brut du graphe JSON), ce qui supprime les `BadRequest` parasites.
|
||||
* [Yavsc.Api] Correction PostgreSQL `timestamptz` sur RDV: normalisation UTC de `EventDate` sur `POST/PUT /api/v1/billing/Rdv` pour eviter l'erreur `Cannot write DateTime with Kind=Local`.
|
||||
* [Yavsc.Api] Correction du flux FrontOffice accept/reject de query: sauvegarde avec contexte utilisateur et fallback d'injection pour `IBillingService` afin d'eviter les erreurs serveur en environnement de test.
|
||||
* [Yavsc.Blogs] Correction des `BadRequest` sur `POST/PUT /api/v1/blogspot` avec payload JSON (PostIt): les proprietes de navigation/serveur (`Author`, `Tags`, `Comments`, audit) ne bloquent plus la validation.
|
||||
* [Yavsc.Org] Correction du flux MVC de creation de commentaire: `SaveChangesAsync(userId)` est utilise pour renseigner les champs d'audit requis (`UserCreated`/`UserModified`).
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ public static class ServiceCollectionHelpers
|
|||
services.AddTransient<RdvPage>();
|
||||
services.AddTransient<BrushPage>();
|
||||
services.AddTransient<BillingQueriesPage>();
|
||||
services.AddTransient<BillingQueryDetailsPage>();
|
||||
// ViewModels
|
||||
services.AddSingleton(settings);
|
||||
services.AddSingleton<YavscApiClient>(api);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace PostIt;
|
|||
public class ViewLocator : IDataTemplate
|
||||
{
|
||||
|
||||
public Control Build(object? data)
|
||||
public Control Build(object? data)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
@ -49,10 +49,12 @@ public class ViewLocator : IDataTemplate
|
|||
AddCircleMemberDialogViewModel => services.GetRequiredService<AddCircleMemberDialog>(),
|
||||
CirclesPageViewModel => services.GetRequiredService<CirclesPage>(),
|
||||
PostAclDialogViewModel => services.GetRequiredService<PostAclDialog>(),
|
||||
BillingQueriesPageViewModel => services.GetRequiredService<BillingQueriesPage>(),
|
||||
BillingQueryDetailsPageViewModel => services.GetRequiredService<BillingQueryDetailsPage>(),
|
||||
null => new TextBlock { Text = "No view for <null>" },
|
||||
_ => new TextBlock { Text = $"No view for {data.GetType().Name}" }
|
||||
};
|
||||
}
|
||||
|
||||
public bool Match(object? data) => data is ViewModelBase;
|
||||
public bool Match(object? data) => data is ViewModelBase;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ public partial class BillingQueriesPageViewModel : ViewModelBase, IActionStatusV
|
|||
? $"Demandes en cours ({Form.Title})"
|
||||
: $"Commandes {Form.Title}";
|
||||
public string ContextLabel => $"{Performer.UserName} · {Activity.Name}";
|
||||
public bool CanOpenDetails => !IsReadOnly;
|
||||
public bool CanOpenDetails => true;
|
||||
|
||||
public override bool CanNavigateNext
|
||||
{
|
||||
|
|
@ -75,7 +75,7 @@ public partial class BillingQueriesPageViewModel : ViewModelBase, IActionStatusV
|
|||
|
||||
public Task InitializeAsync() => RefreshAsync();
|
||||
|
||||
private bool CanOpenSelectedQuery() => !IsReadOnly && SelectedQuery is not null;
|
||||
private bool CanOpenSelectedQuery() => SelectedQuery is not null;
|
||||
|
||||
[RelayCommand]
|
||||
public async Task RefreshAsync()
|
||||
|
|
@ -114,12 +114,6 @@ public partial class BillingQueriesPageViewModel : ViewModelBase, IActionStatusV
|
|||
[RelayCommand(CanExecute = nameof(CanOpenSelectedQuery))]
|
||||
public async Task OpenSelectedQueryAsync()
|
||||
{
|
||||
if (IsReadOnly)
|
||||
{
|
||||
this.SetWarningStatus("Mode lecture seule: l'ouverture en modification est désactivée.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (SelectedQuery is null)
|
||||
{
|
||||
this.SetWarningStatus("Sélectionnez une commande.");
|
||||
|
|
@ -136,8 +130,13 @@ public partial class BillingQueriesPageViewModel : ViewModelBase, IActionStatusV
|
|||
try
|
||||
{
|
||||
var details = await _billingClient.GetQueryAsync(Form.ActionName, SelectedQuery.Id).ConfigureAwait(true);
|
||||
var vm = Form.CreateCommandPageViewModel(Activity, Performer, _billingClient);
|
||||
await vm!.InitializeAsync(details).ConfigureAwait(true);
|
||||
var vm = new BillingQueryDetailsPageViewModel(
|
||||
Activity,
|
||||
Performer,
|
||||
Form,
|
||||
_billingClient,
|
||||
details,
|
||||
IsReadOnly);
|
||||
await app.PushPageAsync(vm).ConfigureAwait(true);
|
||||
}
|
||||
catch (HttpRequestException ex) when (ex.StatusCode is HttpStatusCode.Unauthorized or HttpStatusCode.Forbidden)
|
||||
|
|
|
|||
208
src/PostIt/PostIt/ViewModels/BillingQueryDetailsPageViewModel.cs
Normal file
208
src/PostIt/PostIt/ViewModels/BillingQueryDetailsPageViewModel.cs
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using PostIt.Helpers;
|
||||
using Yavsc;
|
||||
using Yavsc.Abstract.Workflow;
|
||||
using Yavsc.Api.Client;
|
||||
|
||||
namespace PostIt.ViewModels;
|
||||
|
||||
public partial class BillingQueryDetailsPageViewModel : ViewModelBase, IActionStatusViewModel
|
||||
{
|
||||
private readonly BillingApiClient _billingClient;
|
||||
private readonly BillingQueryDetailsDto _details;
|
||||
|
||||
public ActivityInfo Activity { get; }
|
||||
public ActivityUserDisplayItem Performer { get; }
|
||||
public CommandFormSummary Form { get; }
|
||||
public bool IsReadOnly { get; }
|
||||
|
||||
public long Id => _details.Id;
|
||||
public string Title => $"Detail commande #{_details.Id}";
|
||||
public string ContextLabel => $"{Performer.UserName} · {Activity.Name} · {Form.Title}";
|
||||
public string StatusLabel => _details.Status.ToString();
|
||||
public string StatusGlyph => GetStatusGlyph(_details.Status);
|
||||
public string StatusBadgeBackground => GetStatusBadgeBackground(_details.Status);
|
||||
public string StatusBadgeBorder => GetStatusBadgeBorder(_details.Status);
|
||||
public string StatusBadgeForeground => GetStatusBadgeForeground(_details.Status);
|
||||
public string TitleForeground => StatusBadgeForeground;
|
||||
public string BillingCode => _details.BillingCode;
|
||||
public string Description => EmptyAsPlaceholder(_details.Description, "(sans description)");
|
||||
public string Reason => EmptyAsPlaceholder(_details.Reason, "(aucun motif)");
|
||||
public string AdditionalInfo => EmptyAsPlaceholder(_details.AdditionalInfo, "(aucune info complementaire)");
|
||||
public string ClientId => EmptyAsPlaceholder(_details.ClientId, "(non renseigne)");
|
||||
public string EventDateLabel => _details.EventDate?.ToLocalTime().ToString("f") ?? "Date non precisee";
|
||||
public string ConsentLabel => _details.Consent ? "Oui" : "Non";
|
||||
public string ProvisionalLabel => _details.Provisional.HasValue ? _details.Provisional.Value.ToString("0.00") : "(non renseigne)";
|
||||
public string LocationLabel => BuildLocationLabel(_details.Location);
|
||||
public string PrestationsLabel => BuildPrestationsLabel(_details);
|
||||
public bool CanEdit => !IsReadOnly;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool IsBusy { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string StatusMessage { get; set; } = "Pret.";
|
||||
|
||||
[ObservableProperty]
|
||||
public partial StatusNotice ActionStatus { get; set; } = StatusNotice.Info("Pret.");
|
||||
|
||||
public override bool CanNavigateNext
|
||||
{
|
||||
get => false;
|
||||
protected set { _ = value; }
|
||||
}
|
||||
|
||||
public override bool CanNavigatePrevious
|
||||
{
|
||||
get => true;
|
||||
protected set { _ = value; }
|
||||
}
|
||||
|
||||
public BillingQueryDetailsPageViewModel(
|
||||
ActivityInfo activity,
|
||||
ActivityUserDisplayItem performer,
|
||||
CommandFormSummary form,
|
||||
BillingApiClient billingClient,
|
||||
BillingQueryDetailsDto details,
|
||||
bool isReadOnly)
|
||||
{
|
||||
Activity = activity ?? throw new ArgumentNullException(nameof(activity));
|
||||
Performer = performer ?? throw new ArgumentNullException(nameof(performer));
|
||||
Form = form ?? throw new ArgumentNullException(nameof(form));
|
||||
_billingClient = billingClient ?? throw new ArgumentNullException(nameof(billingClient));
|
||||
_details = details ?? throw new ArgumentNullException(nameof(details));
|
||||
IsReadOnly = isReadOnly;
|
||||
|
||||
this.SetInfoStatus("Details de commande charges.");
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task OpenEditorAsync()
|
||||
{
|
||||
if (IsReadOnly)
|
||||
{
|
||||
this.SetWarningStatus("Mode lecture seule: edition desactivee.");
|
||||
return;
|
||||
}
|
||||
|
||||
var app = (App?)Application.Current;
|
||||
if (app is null)
|
||||
{
|
||||
throw new InvalidOperationException("Application PostIt indisponible.");
|
||||
}
|
||||
|
||||
IsBusy = true;
|
||||
try
|
||||
{
|
||||
var vm = Form.CreateCommandPageViewModel(Activity, Performer, _billingClient);
|
||||
if (vm is null)
|
||||
{
|
||||
this.SetWarningStatus("Ce formulaire n'est pas encore pris en charge en edition.");
|
||||
return;
|
||||
}
|
||||
|
||||
await vm.InitializeAsync(_details).ConfigureAwait(true);
|
||||
await app.PushPageAsync(vm).ConfigureAwait(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.SetErrorStatus($"Erreur lors de l'ouverture en edition: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task BackAsync()
|
||||
{
|
||||
var app = (App?)Application.Current;
|
||||
if (app is null)
|
||||
{
|
||||
throw new InvalidOperationException("Application PostIt indisponible.");
|
||||
}
|
||||
|
||||
await app.GoBackAsync().ConfigureAwait(true);
|
||||
}
|
||||
|
||||
private static string EmptyAsPlaceholder(string? value, string placeholder)
|
||||
=> string.IsNullOrWhiteSpace(value) ? placeholder : value;
|
||||
|
||||
private static string BuildLocationLabel(BillingLocationDto? location)
|
||||
{
|
||||
if (location is null)
|
||||
{
|
||||
return "(non renseignee)";
|
||||
}
|
||||
|
||||
var text = EmptyAsPlaceholder(location.Address, "adresse vide");
|
||||
if (location.Latitude.HasValue && location.Longitude.HasValue)
|
||||
{
|
||||
text += $" ({location.Latitude.Value:0.####}, {location.Longitude.Value:0.####})";
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
private static string BuildPrestationsLabel(BillingQueryDetailsDto details)
|
||||
{
|
||||
if (details.PrestationIds.Count > 0)
|
||||
{
|
||||
return string.Join(", ", details.PrestationIds.Select(static id => id.ToString()));
|
||||
}
|
||||
|
||||
return details.PrestationId.HasValue
|
||||
? details.PrestationId.Value.ToString()
|
||||
: "(aucune)";
|
||||
}
|
||||
|
||||
private static string GetStatusBadgeBackground(QueryStatus status)
|
||||
=> status switch
|
||||
{
|
||||
QueryStatus.Accepted => "#E6F7EC",
|
||||
QueryStatus.InProgress => "#FFF4D6",
|
||||
QueryStatus.Rejected => "#FDECEA",
|
||||
QueryStatus.Failed => "#ECEFF1",
|
||||
QueryStatus.Success => "#E8F8EF",
|
||||
_ => "#EAF3FF",
|
||||
};
|
||||
|
||||
private static string GetStatusBadgeBorder(QueryStatus status)
|
||||
=> status switch
|
||||
{
|
||||
QueryStatus.Accepted => "#2E7D32",
|
||||
QueryStatus.InProgress => "#B26A00",
|
||||
QueryStatus.Rejected => "#C62828",
|
||||
QueryStatus.Failed => "#607D8B",
|
||||
QueryStatus.Success => "#1E8E3E",
|
||||
_ => "#2A5EA8",
|
||||
};
|
||||
|
||||
private static string GetStatusBadgeForeground(QueryStatus status)
|
||||
=> status switch
|
||||
{
|
||||
QueryStatus.Accepted => "#1B5E20",
|
||||
QueryStatus.InProgress => "#7A4A00",
|
||||
QueryStatus.Rejected => "#8E0000",
|
||||
QueryStatus.Failed => "#37474F",
|
||||
QueryStatus.Success => "#145A2A",
|
||||
_ => "#1A4178",
|
||||
};
|
||||
|
||||
private static string GetStatusGlyph(QueryStatus status)
|
||||
=> status switch
|
||||
{
|
||||
QueryStatus.Accepted => "OK",
|
||||
QueryStatus.InProgress => "~",
|
||||
QueryStatus.Rejected => "!",
|
||||
QueryStatus.Failed => "X",
|
||||
QueryStatus.Success => "V",
|
||||
_ => "i",
|
||||
};
|
||||
}
|
||||
|
|
@ -5,38 +5,83 @@
|
|||
x:Class="PostIt.Views.BillingQueriesPage"
|
||||
x:DataType="vm:BillingQueriesPageViewModel"
|
||||
Header="Commandes billing">
|
||||
<Grid RowDefinitions="Auto,Auto,*,Auto" Margin="12">
|
||||
<StackPanel Grid.Row="0" Spacing="2">
|
||||
<TextBlock Text="{Binding Title}" FontSize="18" FontWeight="Bold" />
|
||||
<Grid RowDefinitions="Auto,Auto,Auto,*,Auto" Margin="12">
|
||||
<StackPanel Grid.Row="0" Spacing="3">
|
||||
<TextBlock Text="{Binding Title}" FontSize="20" FontWeight="Bold" />
|
||||
<TextBlock Text="{Binding ContextLabel}" Opacity="0.75" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="1" Orientation="Horizontal" Spacing="8" Margin="0,12,0,12">
|
||||
<Button Content="Rafraîchir" Command="{Binding RefreshCommand}" />
|
||||
<Button Content="Ouvrir la commande"
|
||||
<Grid Grid.Row="1" Margin="0,10,0,0" ColumnDefinitions="Auto,8,Auto,8,*">
|
||||
<Border Grid.Column="0" Background="#EAF3FF" BorderBrush="#2A5EA8" BorderThickness="1" CornerRadius="6" Padding="8,3">
|
||||
<TextBlock Text="{Binding IsReadOnly, StringFormat='Lecture seule : {0}'}" FontSize="11" />
|
||||
</Border>
|
||||
<Border Grid.Column="2" Background="#F2F7F2" BorderBrush="#2F6D2F" BorderThickness="1" CornerRadius="6" Padding="8,3">
|
||||
<TextBlock Text="{Binding OngoingOnly, StringFormat='En cours uniquement : {0}'}" FontSize="11" />
|
||||
</Border>
|
||||
<TextBlock Grid.Column="4"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Queries.Count, StringFormat='Résultats : {0}'}"
|
||||
Opacity="0.7" />
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="2" ColumnDefinitions="Auto,8,Auto,*" Margin="0,12,0,12">
|
||||
<Button Grid.Column="0" Content="Rafraîchir" Command="{Binding RefreshCommand}" />
|
||||
<Button Content="Voir le detail"
|
||||
Grid.Column="2"
|
||||
Command="{Binding OpenSelectedQueryCommand}"
|
||||
IsVisible="{Binding CanOpenDetails}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<ListBox Grid.Row="2" ItemsSource="{Binding Queries}" SelectedItem="{Binding SelectedQuery, Mode=TwoWay}">
|
||||
<ListBox Grid.Row="3"
|
||||
ItemsSource="{Binding Queries}"
|
||||
SelectedItem="{Binding SelectedQuery, Mode=TwoWay}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:BillingQueryDisplayItem">
|
||||
<Border BorderThickness="0,0,0,1" BorderBrush="#22000000" Padding="0,0,0,10" Margin="0,0,0,10">
|
||||
<StackPanel Spacing="3">
|
||||
<TextBlock Text="{Binding Description}" FontWeight="Bold" />
|
||||
<TextBlock Text="{Binding Summary}" TextWrapping="Wrap" FontSize="12" Opacity="0.8" />
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<TextBlock Text="{Binding EventDateLabel}" FontSize="11" Opacity="0.7" />
|
||||
<TextBlock Text="{Binding StatusLabel}" FontSize="11" Opacity="0.7" />
|
||||
<TextBlock Text="{Binding BillingCode}" FontSize="11" Opacity="0.6" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<Border BorderThickness="1"
|
||||
BorderBrush="#22000000"
|
||||
CornerRadius="8"
|
||||
Padding="10"
|
||||
Margin="0,0,0,8">
|
||||
<Grid RowDefinitions="Auto,Auto,Auto" ColumnDefinitions="*,Auto">
|
||||
<TextBlock Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Text="{Binding Description}"
|
||||
FontWeight="Bold"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Text="{Binding StatusLabel}"
|
||||
FontSize="11"
|
||||
Opacity="0.75"
|
||||
HorizontalAlignment="Right" />
|
||||
|
||||
<TextBlock Grid.Row="1"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="0,4,0,0"
|
||||
Text="{Binding Summary}"
|
||||
TextWrapping="Wrap"
|
||||
FontSize="12"
|
||||
Opacity="0.85" />
|
||||
|
||||
<Grid Grid.Row="2" Grid.ColumnSpan="2" ColumnDefinitions="*,Auto" Margin="0,8,0,0">
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="{Binding EventDateLabel, StringFormat='Date : {0}'}"
|
||||
FontSize="11"
|
||||
Opacity="0.7" />
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{Binding BillingCode, StringFormat='Code : {0}'}"
|
||||
FontSize="11"
|
||||
Opacity="0.65"
|
||||
HorizontalAlignment="Right" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
|
||||
<Grid Grid.Row="3" ColumnDefinitions="*,Auto" Margin="0,12,0,0">
|
||||
<Grid Grid.Row="4" ColumnDefinitions="*,Auto" Margin="0,12,0,0">
|
||||
<postitControls:StatusBar Grid.Column="0"
|
||||
DataContext="{Binding ActionStatus}" />
|
||||
<ProgressBar Grid.Column="1" Width="120" IsIndeterminate="True" IsVisible="{Binding IsBusy}" />
|
||||
|
|
|
|||
131
src/PostIt/PostIt/Views/BillingQueryDetailsPage.axaml
Normal file
131
src/PostIt/PostIt/Views/BillingQueryDetailsPage.axaml
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
<ContentPage xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:vm="using:PostIt.ViewModels"
|
||||
xmlns:postitControls="using:PostIt.Controls"
|
||||
x:Class="PostIt.Views.BillingQueryDetailsPage"
|
||||
x:DataType="vm:BillingQueryDetailsPageViewModel"
|
||||
Header="Detail commande">
|
||||
<Grid RowDefinitions="Auto,Auto,*,Auto" Margin="12">
|
||||
<StackPanel Grid.Row="0" Spacing="4">
|
||||
<TextBlock Text="{Binding Title}"
|
||||
FontSize="20"
|
||||
FontWeight="Bold"
|
||||
Foreground="{Binding TitleForeground}" />
|
||||
<TextBlock Text="{Binding ContextLabel}" Opacity="0.75" />
|
||||
</StackPanel>
|
||||
|
||||
<Grid Grid.Row="1" Margin="0,10,0,0" ColumnDefinitions="Auto,8,Auto,*">
|
||||
<Button Grid.Column="0"
|
||||
Content="Retour"
|
||||
Command="{Binding BackCommand}" />
|
||||
<Button Grid.Column="2"
|
||||
Content="Ouvrir en edition"
|
||||
Command="{Binding OpenEditorCommand}"
|
||||
IsVisible="{Binding CanEdit}" />
|
||||
</Grid>
|
||||
|
||||
<ScrollViewer Grid.Row="2" Margin="0,12,0,12">
|
||||
<StackPanel Spacing="10">
|
||||
<Border BorderThickness="1"
|
||||
BorderBrush="#22000000"
|
||||
CornerRadius="8"
|
||||
Padding="10">
|
||||
<Grid ColumnDefinitions="Auto,12,*" RowDefinitions="Auto,Auto" RowSpacing="8">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="Statut" FontWeight="SemiBold" />
|
||||
<Border Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
Background="{Binding StatusBadgeBackground}"
|
||||
BorderBrush="{Binding StatusBadgeBorder}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="6"
|
||||
Padding="8,3"
|
||||
HorizontalAlignment="Left">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<TextBlock Text="{Binding StatusGlyph}"
|
||||
Foreground="{Binding StatusBadgeForeground}"
|
||||
FontWeight="Bold" />
|
||||
<TextBlock Text="{Binding StatusLabel}"
|
||||
Foreground="{Binding StatusBadgeForeground}"
|
||||
FontWeight="SemiBold" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Text="Date" FontWeight="SemiBold" />
|
||||
<TextBlock Grid.Row="1" Grid.Column="2" Text="{Binding EventDateLabel}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<Border BorderThickness="1"
|
||||
BorderBrush="#22000000"
|
||||
CornerRadius="8"
|
||||
Padding="10">
|
||||
<Grid ColumnDefinitions="Auto,12,*" RowDefinitions="Auto,Auto,Auto,Auto" RowSpacing="8">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="Description" FontWeight="SemiBold" />
|
||||
<TextBlock Grid.Row="0" Grid.Column="2" Text="{Binding Description}" TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Text="Motif" FontWeight="SemiBold" />
|
||||
<TextBlock Grid.Row="1" Grid.Column="2" Text="{Binding Reason}" TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Text="Infos" FontWeight="SemiBold" />
|
||||
<TextBlock Grid.Row="2" Grid.Column="2" Text="{Binding AdditionalInfo}" TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Text="Consentement" FontWeight="SemiBold" />
|
||||
<TextBlock Grid.Row="3" Grid.Column="2" Text="{Binding ConsentLabel}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<Expander Header="Metadonnees techniques"
|
||||
IsExpanded="False">
|
||||
<Border BorderThickness="1"
|
||||
BorderBrush="#22000000"
|
||||
CornerRadius="8"
|
||||
Padding="10"
|
||||
Margin="0,6,0,0">
|
||||
<Grid ColumnDefinitions="Auto,12,*" RowDefinitions="Auto,Auto,Auto,Auto,Auto" RowSpacing="8">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="Code" FontWeight="SemiBold" />
|
||||
<TextBlock Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
Text="{Binding BillingCode}"
|
||||
FontFamily="Consolas, Courier New, monospace" />
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Text="Client" FontWeight="SemiBold" />
|
||||
<TextBlock Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Text="{Binding ClientId}"
|
||||
FontFamily="Consolas, Courier New, monospace" />
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Text="Provision" FontWeight="SemiBold" />
|
||||
<TextBlock Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
Text="{Binding ProvisionalLabel}"
|
||||
FontFamily="Consolas, Courier New, monospace" />
|
||||
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Text="Lieu" FontWeight="SemiBold" />
|
||||
<TextBlock Grid.Row="3"
|
||||
Grid.Column="2"
|
||||
Text="{Binding LocationLabel}"
|
||||
TextWrapping="Wrap"
|
||||
FontFamily="Consolas, Courier New, monospace" />
|
||||
|
||||
<TextBlock Grid.Row="4" Grid.Column="0" Text="Prestations" FontWeight="SemiBold" />
|
||||
<TextBlock Grid.Row="4"
|
||||
Grid.Column="2"
|
||||
Text="{Binding PrestationsLabel}"
|
||||
TextWrapping="Wrap"
|
||||
FontFamily="Consolas, Courier New, monospace" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</Expander>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<Grid Grid.Row="3" ColumnDefinitions="*,Auto" Margin="0,8,0,0">
|
||||
<postitControls:StatusBar Grid.Column="0"
|
||||
DataContext="{Binding ActionStatus}" />
|
||||
<ProgressBar Grid.Column="1"
|
||||
Width="120"
|
||||
IsIndeterminate="True"
|
||||
IsVisible="{Binding IsBusy}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ContentPage>
|
||||
17
src/PostIt/PostIt/Views/BillingQueryDetailsPage.axaml.cs
Normal file
17
src/PostIt/PostIt/Views/BillingQueryDetailsPage.axaml.cs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace PostIt.Views;
|
||||
|
||||
public partial class BillingQueryDetailsPage : ContentPage
|
||||
{
|
||||
public BillingQueryDetailsPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue