/*
* Copyright (c) 2024 Proton AG
*
* This file is part of ProtonVPN.
*
* ProtonVPN is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonVPN is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonVPN. If not, see .
*/
using System.ComponentModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using ProtonVPN.Api.Contracts.ReportAnIssue;
using ProtonVPN.Client.Common.Collections;
using ProtonVPN.Client.Core.Bases;
using ProtonVPN.Client.Core.Models.ReportIssue;
using ProtonVPN.Client.Core.Models.ReportIssue.Fields;
using ProtonVPN.Client.Core.Services.Navigation;
using ProtonVPN.Client.Logic.Feedback.Contracts;
using ProtonVPN.Client.Mappers;
using ProtonVPN.Client.UI.Dialogs.ReportIssue.Bases;
using ProtonVPN.Common.Legacy.Abstract;
using ProtonVPN.Logging.Contracts.Events.AppLogs;
namespace ProtonVPN.Client.UI.Dialogs.ReportIssue.Pages;
public partial class ReportIssueContactPageViewModel : ReportIssuePageViewModelBase
{
private readonly IReportIssueDataProvider _dataProvider;
private readonly IReportIssueSender _reportIssueSender;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(Title))]
[NotifyCanExecuteChangedFor(nameof(SendReportCommand))]
private IssueCategory? _category;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(SendReportCommand))]
private bool _isSendingReport;
[ObservableProperty]
private bool _includeLogs;
public override string Title => Category?.Name ?? string.Empty;
public NotifyErrorObservableCollection InputFields { get; }
public ReportIssueContactPageViewModel(
IReportIssueDataProvider dataProvider,
IReportIssueSender reportIssueSender,
IReportIssueViewNavigator parentViewNavigator,
IViewModelHelper viewModelHelper)
: base(parentViewNavigator, viewModelHelper)
{
_dataProvider = dataProvider;
_reportIssueSender = reportIssueSender;
InputFields = [];
InputFields.ItemErrorsChanged += OnInputFieldsItemErrorsChanged;
IncludeLogs = true;
}
public override void OnNavigatedTo(object parameter, bool isBackNavigation)
{
base.OnNavigatedTo(parameter, isBackNavigation);
Category = parameter as IssueCategory;
}
[RelayCommand(CanExecute = nameof(CanSendReport))]
public async Task SendReportAsync()
{
bool isReportSent = false;
try
{
IsSendingReport = true;
string email =
InputFields.First()
.Serialize().value;
Dictionary serializedFields =
InputFields.Skip(1)
.Select(f => f.Serialize())
.ToDictionary(a => a.key, a => a.value);
Result result = await _reportIssueSender.SendAsync(Category!.Key, email, serializedFields, IncludeLogs);
isReportSent = result.Success;
}
catch (Exception e)
{
Logger.Error("An error occured while sending the issue report", e);
}
finally
{
if (IsSendingReport)
{
IsSendingReport = false;
await ParentViewNavigator.NavigateToResultViewAsync(isReportSent);
}
}
}
public bool CanSendReport()
{
return !IsSendingReport
&& Category != null
&& InputFields.All(f => !f.HasErrors);
}
protected override async void OnLanguageChanged()
{
base.OnLanguageChanged();
await InvalidateCategoryAsync();
}
private void OnInputFieldsItemErrorsChanged(object? sender, DataErrorsChangedEventArgs e)
{
SendReportCommand.NotifyCanExecuteChanged();
}
private async Task InvalidateCategoryAsync()
{
if (Category == null)
{
return;
}
List categories = await _dataProvider.GetCategoriesAsync();
Category = ReportIssueMapper.Map(categories.First(c => c.SubmitLabel == Category.Key));
}
private void InvalidateInputFields()
{
InputFields.Clear();
if (Category == null)
{
throw new ArgumentException(nameof(Category), "Cannot load contact form with no category");
}
InputFields.Add(new EmailInputField(true)
{
Key = "Email",
Name = Localizer.Get("Dialogs_ReportIssue_ContactForm_Email"),
Placeholder = Localizer.Get("Dialogs_ReportIssue_ContactForm_Email_Description"),
});
foreach (IssueInputField field in Category.InputFields)
{
InputFields.Add(field);
}
}
partial void OnCategoryChanged(IssueCategory? value)
{
InvalidateInputFields();
}
partial void OnIsSendingReportChanged(bool value)
{
ParentViewNavigator.CanNavigate = !value;
}
protected override void OnDeactivated()
{
base.OnDeactivated();
if (IsSendingReport)
{
// If window is closed while sending the report, keep sending the report in background but reset the flag on the view model
IsSendingReport = false;
}
}
}