diff --git a/FinTrack/Assets/Images/Icons/calendar.png b/FinTrack/Assets/Images/Icons/calendar.png new file mode 100644 index 0000000..5e10270 Binary files /dev/null and b/FinTrack/Assets/Images/Icons/calendar.png differ diff --git a/FinTrack/Assets/Images/Icons/credit-card.png b/FinTrack/Assets/Images/Icons/credit-card.png new file mode 100644 index 0000000..5f33a8f Binary files /dev/null and b/FinTrack/Assets/Images/Icons/credit-card.png differ diff --git a/FinTrack/Assets/Images/Icons/investment.png b/FinTrack/Assets/Images/Icons/investment.png new file mode 100644 index 0000000..3f3d26d Binary files /dev/null and b/FinTrack/Assets/Images/Icons/investment.png differ diff --git a/FinTrack/Core/SecureTokenStorage.cs b/FinTrack/Core/SecureTokenStorage.cs index 5c154ed..8b47b58 100644 --- a/FinTrack/Core/SecureTokenStorage.cs +++ b/FinTrack/Core/SecureTokenStorage.cs @@ -1,4 +1,5 @@ -using System.IO; +using Microsoft.Extensions.Logging; +using System.IO; using System.Security.Cryptography; using System.Text; @@ -6,12 +7,16 @@ namespace FinTrack.Core { public class SecureTokenStorage : ISecureTokenStorage { + private readonly ILogger _logger; + private readonly string _filePath; private static readonly byte[] s_entropy = Encoding.UTF8.GetBytes("E5A3B8B8_4A8C_4F1D_9F0B_2B3A7F9C1D0E"); // [TEST] - public SecureTokenStorage() + public SecureTokenStorage(ILogger logger) { + _logger = logger; + var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); var appFolder = Path.Combine(appDataPath, "FinTrack"); Directory.CreateDirectory(appFolder); @@ -27,10 +32,11 @@ public void SaveToken(string token) { var encryptedToken = ProtectedData.Protect(Encoding.UTF8.GetBytes(token), s_entropy, DataProtectionScope.CurrentUser); File.WriteAllBytes(_filePath, encryptedToken); + _logger.LogInformation("Token başarıyla kaydedildi."); } catch (Exception ex) { - Console.WriteLine($"Error saving token: {ex.Message}"); + _logger.LogError(ex, "Token 'ı kaydederken hata oluştu."); throw; } } @@ -48,7 +54,7 @@ public void SaveToken(string token) } catch (Exception ex) { - Console.WriteLine($"Error retrieving token: {ex.Message}"); + _logger.LogError(ex, "Token 'ı alırken hata oluştu."); ClearToken(); return null; } @@ -61,10 +67,11 @@ public void ClearToken() try { File.Delete(_filePath); + _logger.LogInformation("Token başarıyla temizlendi."); } catch (Exception ex) { - Console.WriteLine($"Error clearing token: {ex.Message}"); + _logger.LogError(ex, "Token 'ı temizlerken hata oluştu."); } } } diff --git a/FinTrack/FinTrack.csproj b/FinTrack/FinTrack.csproj index 9a147b0..01f2a6c 100644 --- a/FinTrack/FinTrack.csproj +++ b/FinTrack/FinTrack.csproj @@ -13,13 +13,16 @@ + + + @@ -73,8 +76,11 @@ + + + diff --git a/FinTrack/Models/Account/AccountModel.cs b/FinTrack/Models/Account/AccountModel.cs index e759e93..722c5cd 100644 --- a/FinTrack/Models/Account/AccountModel.cs +++ b/FinTrack/Models/Account/AccountModel.cs @@ -10,7 +10,7 @@ public partial class AccountModel : ObservableObject private Guid id = Guid.NewGuid(); [ObservableProperty] - private string name; + private string name = string.Empty; [ObservableProperty] private AccountType type; @@ -30,9 +30,9 @@ public partial class AccountModel : ObservableObject public string IconPath => Type switch { AccountType.Checking => "/Assets/Images/Icons/bank.png", - AccountType.CreditCard => "/Assets/Images/Icons/credit_card.png", + AccountType.CreditCard => "/Assets/Images/Icons/credit-card.png", AccountType.Loan => "/Assets/Images/Icons/investment.png", - _ => string.Empty + _ => "/Assets/Images/Icons/money.png" }; public Brush IconBackground => Type switch diff --git a/FinTrack/Models/Currency/CurrencyModel.cs b/FinTrack/Models/Currency/CurrencyModel.cs index 69f006d..f760d11 100644 --- a/FinTrack/Models/Currency/CurrencyModel.cs +++ b/FinTrack/Models/Currency/CurrencyModel.cs @@ -25,6 +25,18 @@ public partial class CurrencyModel : ObservableObject [NotifyPropertyChangedFor(nameof(ToCurrencyChangeForeground))] private CurrencyConversionType type = CurrencyConversionType.Increase; + [ObservableProperty] + private string dailyLow = string.Empty; + + [ObservableProperty] + private string dailyHigh = string.Empty; + + [ObservableProperty] + private string weeklyChange = string.Empty; + + [ObservableProperty] + private string monthlyChange = string.Empty; + private static readonly Brush IncreaseBrush = new SolidColorBrush(Colors.Green); private static readonly Brush DecreaseBrush = new SolidColorBrush(Colors.Red); private static readonly Brush DefaultBrush = new SolidColorBrush(Colors.Gray); diff --git a/FinTrack/Models/Dashboard/DebtDashboard.cs b/FinTrack/Models/Dashboard/DebtDashboard.cs index abeddbc..19ca059 100644 --- a/FinTrack/Models/Dashboard/DebtDashboard.cs +++ b/FinTrack/Models/Dashboard/DebtDashboard.cs @@ -1,4 +1,6 @@ -namespace FinTrack.Models.Dashboard +using System.Windows.Media; + +namespace FinTrack.Models.Dashboard { public class DebtDashboard { @@ -7,7 +9,7 @@ public class DebtDashboard public string BorrowerName { get; set; } = string.Empty; public string BorrowerIconPath { get; set; } = string.Empty; public string Status { get; set; } = string.Empty; - public string StatusBrush { get; set; } = string.Empty; + public Brush StatusBrush { get; set; } = Brushes.Transparent; public string Amount { get; set; } = string.Empty; public string CreationDate { get; set; } = string.Empty; public string DueDate { get; set; } = string.Empty; diff --git a/FinTrack/Models/Dashboard/ReportDashboard.cs b/FinTrack/Models/Dashboard/ReportDashboard.cs deleted file mode 100644 index 9366a96..0000000 --- a/FinTrack/Models/Dashboard/ReportDashboard.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace FinTrack.Models.Dashboard -{ - public class ReportDashboard - { - public string Name { get; set; } = string.Empty; - public string IconPath { get; set; } = "/Assets/Icons/report.png"; - public string[] Formats { get; set; } = { "PDF", "WORD", "TEXT", "XML", "EXCEL", "MD" }; - } -} diff --git a/FinTrack/Models/Dashboard/ReportDashboardModel.cs b/FinTrack/Models/Dashboard/ReportDashboardModel.cs new file mode 100644 index 0000000..3c5480a --- /dev/null +++ b/FinTrack/Models/Dashboard/ReportDashboardModel.cs @@ -0,0 +1,39 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using FinTrack.Enums; +using Microsoft.Extensions.Logging; +using System.Collections.ObjectModel; +using System.Windows; + +namespace FinTrack.Models.Dashboard +{ + public partial class ReportDashboardModel : ObservableObject + { + [ObservableProperty] + private string name = string.Empty; + + public ObservableCollection Formats { get; set; } + + private readonly ILogger _logger; + + public ReportDashboardModel(ILogger logger) + { + _logger = logger; + + Formats = new ObservableCollection(); + + foreach (ExportFormat exportFormat in Enum.GetValues(typeof(ExportFormat))) + { + Formats.Add(exportFormat); + } + } + + [RelayCommand] + private void Generate(ExportFormat format) + { + + _logger.LogInformation("Rapor oluşturuluyor -> Rapor Adı: {ReportName}, Format: {Format}", this.Name, format); + MessageBox.Show($"Rapor oluşturuldu:\nAd: {this.Name}\nFormat: {format}", "Rapor Oluşturma", MessageBoxButton.OK, MessageBoxImage.Information); + } + } +} diff --git a/FinTrack/Models/Notification/NotificationModel.cs b/FinTrack/Models/Notification/NotificationModel.cs index 541f5ff..5339d65 100644 --- a/FinTrack/Models/Notification/NotificationModel.cs +++ b/FinTrack/Models/Notification/NotificationModel.cs @@ -18,10 +18,10 @@ public partial class NotificationModel : ObservableObject private NotificationType type; [ObservableProperty] - [NotifyPropertyChangedFor(nameof(isUnread))] + [NotifyPropertyChangedFor(nameof(IsUnread))] private bool isRead = false; - public bool isUnread => !IsRead; + public bool IsUnread => !IsRead; public NotificationModel(string title, string message, string? timestamp, NotificationType type, bool _isRead = false) { @@ -29,7 +29,7 @@ public NotificationModel(string title, string message, string? timestamp, Notifi Message = message; Type = type; Timestamp = timestamp ?? DateTime.Now.ToString(); - isRead = _isRead; + IsRead = _isRead; } } } diff --git a/FinTrack/Services/Api/ApiService.cs b/FinTrack/Services/Api/ApiService.cs index a8f511c..569f725 100644 --- a/FinTrack/Services/Api/ApiService.cs +++ b/FinTrack/Services/Api/ApiService.cs @@ -12,9 +12,8 @@ public class ApiService : IApiService private readonly HttpClient _httpClient; private readonly ILogger _logger; private readonly JsonSerializerOptions _jsonSerializerOptions; - private readonly ISecureTokenStorage _secureTokenStorage; - public ApiService(ILogger logger, ISecureTokenStorage secureTokenStorage) + public ApiService(ILogger logger) { _baseUrl = "http://localhost:5000/api/"; _httpClient = new HttpClient @@ -24,7 +23,6 @@ public ApiService(ILogger logger, ISecureTokenStorage secureTokenSto _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); _logger = logger; - _secureTokenStorage = secureTokenStorage; _jsonSerializerOptions = new JsonSerializerOptions { @@ -34,7 +32,7 @@ public ApiService(ILogger logger, ISecureTokenStorage secureTokenSto private void AddAuthorizationHeader() { - string token = _secureTokenStorage.GetToken() ?? "null"; + string token = SessionManager.CurrentToken; if (!string.IsNullOrEmpty(token)) { _httpClient.DefaultRequestHeaders.Authorization = null; diff --git a/FinTrack/ViewModels/ApplicationRecognizeSlideViewModel.cs b/FinTrack/ViewModels/ApplicationRecognizeSlideViewModel.cs index c69b199..5a197ec 100644 --- a/FinTrack/ViewModels/ApplicationRecognizeSlideViewModel.cs +++ b/FinTrack/ViewModels/ApplicationRecognizeSlideViewModel.cs @@ -1,5 +1,7 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; +using FinTrack.Core; +using Microsoft.Extensions.Logging; namespace FinTrack.ViewModels { @@ -94,10 +96,17 @@ Your financial advisor is now available 24/7. } }; + private readonly ILogger _logger; + + private readonly ISecureTokenStorage _secureToken; + private int currentSlideIndex = 0; - public ApplicationRecognizeSlideViewModel() + public ApplicationRecognizeSlideViewModel(ILogger logger, ISecureTokenStorage secureToken) { + _logger = logger; + _secureToken = secureToken; + UpdateCurrentSlide(CurrentSlide); } @@ -108,6 +117,7 @@ public void Back_ApplicationRecognizeSlideView_Button() { currentSlideIndex--; UpdateCurrentSlide(CurrentSlide); + _logger.LogInformation("Kullanıcı geri düğmesine bastı. Şu anki slayt: {CurrentSlideTitle}", CurrentSlide.Title); } } @@ -117,6 +127,7 @@ public void Next_ApplicationRecognizeSlideView_Button() if (currentSlideIndex < applicationRecognizeSlides.Count - 1) { currentSlideIndex++; + _logger.LogInformation("Kullanıcı ileri düğmesine bastı. Şu anki slayt: {CurrentSlideTitle}", CurrentSlide.Title); UpdateCurrentSlide(CurrentSlide); } } @@ -124,6 +135,7 @@ public void Next_ApplicationRecognizeSlideView_Button() [RelayCommand] public void Skip_ApplicationRecognizeSlideView_Button() { + _logger.LogInformation("Kullanıcı uygulama tanıtımını atladı. Giriş ekranına yönlendiriliyor."); NavigateToLoginRequested?.Invoke(); } diff --git a/FinTrack/ViewModels/AuthenticatorViewModel.cs b/FinTrack/ViewModels/AuthenticatorViewModel.cs index 507db44..950747f 100644 --- a/FinTrack/ViewModels/AuthenticatorViewModel.cs +++ b/FinTrack/ViewModels/AuthenticatorViewModel.cs @@ -1,4 +1,9 @@ using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Messaging; +using FinTrack.Core; +using FinTrack.Messages; +using Microsoft.Extensions.Logging; +using System.Windows; namespace FinTrack.ViewModels { @@ -13,12 +18,18 @@ public partial class AuthenticatorViewModel : ObservableObject private readonly ForgotPasswordViewModel _forgotPasswordViewModel; private readonly ApplicationRecognizeSlideViewModel _applicationRecognizeSlideViewModel; + private readonly ISecureTokenStorage _secureToken; + + private readonly ILogger _logger; + public AuthenticatorViewModel( LoginViewModel loginViewModel, RegisterViewModel registerViewModel, OtpVerificationViewModel otpVerificationViewModel, ForgotPasswordViewModel forgotPasswordViewModel, - ApplicationRecognizeSlideViewModel applicationRecognizeSlideViewModel) + ApplicationRecognizeSlideViewModel applicationRecognizeSlideViewModel, + ISecureTokenStorage secureToken, + ILogger logger) { _loginViewModel = loginViewModel; _registerViewModel = registerViewModel; @@ -41,6 +52,42 @@ public AuthenticatorViewModel( _forgotPasswordViewModel.NavigateToLoginRequested += () => CurrentViewModel = _loginViewModel; CurrentViewModel = _applicationRecognizeSlideViewModel; + + _registerViewModel.SendOtpVerificationRequested += OnSendOtpVerificationRequested; + + _logger = logger; + _secureToken = secureToken; + + SavedTokenLogin(); + } + + private void OnSendOtpVerificationRequested(object? sender, EventArgs e) + { + _otpVerificationViewModel.StartCounter(); + } + + private void SavedTokenLogin() + { + string? token = _secureToken.GetToken(); + if (token is not null) + { + bool isValid = TokenValidator.IsTokenValid(token); + if (!isValid) + { + MessageBox.Show("Token geçersiz. Lütfen tekrar giriş yapın.", "Hata", MessageBoxButton.OK, MessageBoxImage.Error); + _logger.LogWarning("Geçersiz token bulundu. Kullanıcıdan yeni giriş yapması istendi."); + SessionManager.ClearToken(); + _secureToken.ClearToken(); + } + + SessionManager.SetToken(token); + _logger.LogInformation("Kullanıcı zaten giriş yapmış. Token kullanıldı."); + WeakReferenceMessenger.Default.Send(new LoginSuccessMessage()); + } + else + { + _logger.LogInformation("Kullanıcı henüz giriş yapmamış. Uygulama tanıtım slaytları gösteriliyor."); + } } } } \ No newline at end of file diff --git a/FinTrack/ViewModels/BottomBarViewModel.cs b/FinTrack/ViewModels/BottomBarViewModel.cs index b000f3b..5881f52 100644 --- a/FinTrack/ViewModels/BottomBarViewModel.cs +++ b/FinTrack/ViewModels/BottomBarViewModel.cs @@ -1,8 +1,40 @@ using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using Microsoft.Extensions.Logging; +using System.Windows; + namespace FinTrack.ViewModels { public partial class BottomBarViewModel : ObservableObject { + [ObservableProperty] + private string company = string.Empty; + + [ObservableProperty] + private string version = string.Empty; + + [ObservableProperty] + private string lastSyncStatus = string.Empty; + + private readonly ILogger _logger; + + public BottomBarViewModel(ILogger logger) + { + _logger = logger; + + int year = DateTime.Now.Year; + Company = $"© {year} FinTrack Inc."; + + Version = "v1.0.0"; + LastSyncStatus = "Son Senkronizasyon: Başarılı"; + } + + [RelayCommand] + private void AddNewTransaction() + { + _logger.LogInformation("Yeni işlem ekleniyor..."); + MessageBox.Show("Yeni işlem ekleme özelliği henüz uygulanmadı.", "Bilgi", MessageBoxButton.OK, MessageBoxImage.Information); + } } } diff --git a/FinTrack/ViewModels/CurrenciesViewModel.cs b/FinTrack/ViewModels/CurrenciesViewModel.cs index 1bdf317..6010076 100644 --- a/FinTrack/ViewModels/CurrenciesViewModel.cs +++ b/FinTrack/ViewModels/CurrenciesViewModel.cs @@ -27,12 +27,6 @@ public partial class CurrenciesViewModel : ObservableObject [ObservableProperty] private string toCurrencyPrice = string.Empty; - [ObservableProperty] - private string weeklyChange = string.Empty; - - [ObservableProperty] - private string monthlyChange = string.Empty; - private readonly ILogger _logger; public CurrenciesViewModel(ILogger logger) @@ -74,7 +68,11 @@ private void LoadSampleData() ToCurrencyName = "Turkish Lira", ToCurrencyPrice = 32.56m, ToCurrencyChange = "+0.12 (0.37%)", - Type = Enums.CurrencyConversionType.Increase + Type = Enums.CurrencyConversionType.Increase, + DailyLow = "3.05", + DailyHigh = "3.08", + WeeklyChange = "-0.1%", + MonthlyChange = "+0.5%" }, new CurrencyModel { @@ -83,7 +81,11 @@ private void LoadSampleData() ToCurrencyName = "Euro", ToCurrencyPrice = 3.06m, ToCurrencyChange = "-0.12 (0.37%)", - Type = Enums.CurrencyConversionType.Decrease + Type = Enums.CurrencyConversionType.Decrease, + DailyLow = "3.05", + DailyHigh = "3.08", + WeeklyChange = "-0.1%", + MonthlyChange = "+0.5%" }, new CurrencyModel { @@ -92,7 +94,11 @@ private void LoadSampleData() ToCurrencyName = "British Pound", ToCurrencyPrice = 0.08m, ToCurrencyChange = "+0.20 (0.80%)", - Type = Enums.CurrencyConversionType.Decrease + Type = Enums.CurrencyConversionType.Decrease, + DailyLow = "3.05", + DailyHigh = "3.08", + WeeklyChange = "-0.1%", + MonthlyChange = "+0.5%" }, new CurrencyModel { @@ -101,7 +107,11 @@ private void LoadSampleData() ToCurrencyName = "Euro", ToCurrencyPrice = 3.06m, ToCurrencyChange = "-0.12 (0.37%)", - Type = Enums.CurrencyConversionType.Decrease + Type = Enums.CurrencyConversionType.Decrease, + DailyLow = "3.05", + DailyHigh = "3.08", + WeeklyChange = "-0.1%", + MonthlyChange = "+0.5%" }, new CurrencyModel { @@ -110,7 +120,11 @@ private void LoadSampleData() ToCurrencyName = "British Pound", ToCurrencyPrice = 0.08m, ToCurrencyChange = "+0.20 (0.80%)", - Type = Enums.CurrencyConversionType.Decrease + Type = Enums.CurrencyConversionType.Decrease, + DailyLow = "3.05", + DailyHigh = "3.08", + WeeklyChange = "-0.1%", + MonthlyChange = "+0.5%" }, new CurrencyModel { @@ -119,7 +133,11 @@ private void LoadSampleData() ToCurrencyName = "Euro", ToCurrencyPrice = 3.06m, ToCurrencyChange = "-0.12 (0.37%)", - Type = Enums.CurrencyConversionType.Decrease + Type = Enums.CurrencyConversionType.Decrease, + DailyLow = "32.40", + DailyHigh = "32.60", + WeeklyChange = "+0.2%", + MonthlyChange = "+1.5%" }, new CurrencyModel { @@ -128,7 +146,11 @@ private void LoadSampleData() ToCurrencyName = "British Pound", ToCurrencyPrice = 0.08m, ToCurrencyChange = "+0.20 (0.80%)", - Type = Enums.CurrencyConversionType.Decrease + Type = Enums.CurrencyConversionType.Decrease, + DailyLow = "3.05", + DailyHigh = "3.08", + WeeklyChange = "-0.1%", + MonthlyChange = "+0.5%" } }; FilterCurrencies(); diff --git a/FinTrack/ViewModels/DashboardViewModel.cs b/FinTrack/ViewModels/DashboardViewModel.cs index 0c758ae..41e120c 100644 --- a/FinTrack/ViewModels/DashboardViewModel.cs +++ b/FinTrack/ViewModels/DashboardViewModel.cs @@ -1,5 +1,7 @@ using CommunityToolkit.Mvvm.ComponentModel; +using FinTrack.Enums; using FinTrack.Models.Dashboard; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System.Collections.ObjectModel; using System.Windows; @@ -31,13 +33,19 @@ public partial class DashboardViewModel : ObservableObject private DebtDashboard _currentDebt_DashboardView_Multiple; [ObservableProperty] - private ObservableCollection _reports_DashboardView_ItemsControl; + private ObservableCollection _reports_DashboardView_ItemsControl; + + [ObservableProperty] + private string transactionSummary = string.Empty; private readonly ILogger _logger; - public DashboardViewModel(ILogger logger) + private readonly IServiceProvider _serviceProvider; + + public DashboardViewModel(ILogger logger, IServiceProvider serviceProvider) { _logger = logger; + _serviceProvider = serviceProvider; LoadData(); } @@ -84,6 +92,24 @@ private void LoadData() new TransactionDashboard { DateText = "03.01.2025", Description = "Elektrik Faturası", Amount = "-200$", Category = "Fatura", Type = Enums.TransactionType.Expense } }; + // [TEST] + double totalIncome = Transactions_DashboardView_ListView + .Where(t => t.Type == TransactionType.Income) + .Sum(t => + { + var cleaned = t.Amount.Replace("+", string.Empty).Replace("$", string.Empty).Trim(); + return double.TryParse(cleaned, out var value) ? value : 0; + }); + double totalExpense = Transactions_DashboardView_ListView + .Where(t => t.Type == TransactionType.Expense) + .Sum(t => + { + var cleaned = t.Amount.Replace("-", string.Empty).Replace("$", string.Empty).Trim(); + return double.TryParse(cleaned, out var value) ? value : 0; + }); + double remainingBalance = totalIncome - totalExpense; + TransactionSummary = $"Toplam {Transactions_DashboardView_ListView.Count} işlem bulundu. Gelir: +{totalIncome}$, Gider: -{totalExpense}$ Kalan: {remainingBalance}"; + // [TEST] CurrentMembership_DashboardView_Multiple = new MembershipDashboard { Level = "Pro | AKTF", StartDate = "01.01.2025", RenewalDate = "01.02.2025", Price = "9.99$" }; @@ -95,7 +121,7 @@ private void LoadData() BorrowerName = "Ahmet Mehmet", BorrowerIconPath = "https://pbs.twimg.com/profile_images/1144861916734451712/D76C3ugh_400x400.jpg", Status = "Ödenmemiş", - StatusBrush = "StatusGreenBrush", + StatusBrush = (Brush)Application.Current.FindResource("StatusGreenBrush"), Amount = "1.000$", CreationDate = "01.01.2025", DueDate = "01.02.2025", @@ -103,12 +129,23 @@ private void LoadData() }; // [TEST] - Reports_DashboardView_ItemsControl = new ObservableCollection + Reports_DashboardView_ItemsControl = new ObservableCollection + { + CreateReport("2025 Yılı Finansal Raporu"), + CreateReport("2024 Yılı Tasarruf Raporu"), + CreateReport("2023 Yılı Gelir-Gider Raporu"), + CreateReport("2022 Yılı Bütçe Raporu") + }; + } + + private ReportDashboardModel CreateReport(string name) + { + var reportLogger = _serviceProvider.GetRequiredService>(); + var report = new ReportDashboardModel(reportLogger) { - new ReportDashboard { Name = "Gelir Raporu" }, - new ReportDashboard { Name = "Gider Raporu" }, - new ReportDashboard { Name = "Bütçe Raporu" } + Name = name, }; + return report; } } } diff --git a/FinTrack/ViewModels/LoginViewModel.cs b/FinTrack/ViewModels/LoginViewModel.cs index 15f7735..2a3c91c 100644 --- a/FinTrack/ViewModels/LoginViewModel.cs +++ b/FinTrack/ViewModels/LoginViewModel.cs @@ -39,28 +39,6 @@ public LoginViewModel( _authService = authService; _logger = logger; _secureTokenStorage = secureTokenStorage; - SavedTokenLogin(); - } - - private void SavedTokenLogin() - { - string? token = _secureTokenStorage.GetToken(); - if (!string.IsNullOrEmpty(token)) - { - bool isValid = TokenValidator.IsTokenValid(token); - if (!isValid) - { - MessageBox.Show("Token geçersiz. Lütfen tekrar giriş yapın.", "Hata", MessageBoxButton.OK, MessageBoxImage.Error); - _logger.LogWarning("Geçersiz token bulundu. Kullanıcıdan yeni giriş yapması istendi."); - SessionManager.ClearToken(); - _secureTokenStorage.ClearToken(); - } - - SessionManager.SetToken(token); - MessageBox.Show("Giriş başarılı! Token kullanıldı.", "Bilgi", MessageBoxButton.OK, MessageBoxImage.Information); - _logger.LogInformation("Kullanıcı zaten giriş yapmış. Token kullanıldı."); - WeakReferenceMessenger.Default.Send(new LoginSuccessMessage()); - } } [RelayCommand] @@ -68,7 +46,6 @@ private async Task Login_LoginView_Button() { _logger.LogInformation("Kullanıcı giriş yapmaya çalışıyor. E-posta: {Email}", Email_LoginView_TextBox); - WeakReferenceMessenger.Default.Send(new LoginSuccessMessage()); // TODO: [TEST] if (string.IsNullOrEmpty(Email_LoginView_TextBox) || string.IsNullOrEmpty(Password_LoginView_TextBox)) { MessageBox.Show("Lütfen e-posta ve şifre alanlarını doldurun.", "Hata", MessageBoxButton.OK, MessageBoxImage.Error); @@ -85,10 +62,7 @@ private async Task Login_LoginView_Button() } SessionManager.SetToken(token); - _secureTokenStorage.SaveToken(token); - - MessageBox.Show("Giriş başarılı!", "Bilgi", MessageBoxButton.OK, MessageBoxImage.Information); _logger.LogInformation("Kullanıcı giriş yaptı ve token kaydedildi."); WeakReferenceMessenger.Default.Send(new LoginSuccessMessage()); diff --git a/FinTrack/ViewModels/NotificationViewModel.cs b/FinTrack/ViewModels/NotificationViewModel.cs index 41cead4..ce8681b 100644 --- a/FinTrack/ViewModels/NotificationViewModel.cs +++ b/FinTrack/ViewModels/NotificationViewModel.cs @@ -57,7 +57,7 @@ private void MarkAllAsRead() { foreach (var notification in Notifications) { - if (notification.isUnread) + if (notification.IsUnread) { notification.IsRead = true; _logger.LogInformation($"Notification '{notification.Title}' marked as read."); @@ -76,7 +76,7 @@ private void ClearAll() [RelayCommand] private void MarkAsRead(NotificationModel? notification) { - if (notification.isUnread) + if (notification.IsUnread) { notification.IsRead = true; _logger.LogInformation($"Notification '{notification.Title}' marked as read."); diff --git a/FinTrack/ViewModels/OtpVerificationViewModel.cs b/FinTrack/ViewModels/OtpVerificationViewModel.cs index d8218f1..f049065 100644 --- a/FinTrack/ViewModels/OtpVerificationViewModel.cs +++ b/FinTrack/ViewModels/OtpVerificationViewModel.cs @@ -20,6 +20,7 @@ public partial class OtpVerificationViewModel : ObservableObject public event Action? NavigateToRegisterRequested; private int _counter; + private Task? _counterTask; private readonly IAuthService _authService; private readonly ILogger _logger; @@ -28,21 +29,9 @@ public OtpVerificationViewModel(IAuthService authService, ILogger _logger; private readonly IAuthService _authService; + public event EventHandler SendOtpVerificationRequested; + public RegisterViewModel(ILogger logger, IAuthService authService) { _logger = logger; @@ -67,6 +69,7 @@ private async Task Register_RegisterView_Button() _logger.LogError("Kayıt işlemi başarısız oldu. E-posta: {Email}", Email_RegisterView_TextBox); return; } + SendOtpVerificationRequested?.Invoke(this, EventArgs.Empty); MessageBox.Show("Kayıt işlemi başarılı! Lütfen e-posta adresinize gelen doğrulama kodunu girin.", "Bilgi", MessageBoxButton.OK, MessageBoxImage.Information); _logger.LogInformation("Kayıt işlemi başarılı. E-posta: {Email}", Email_RegisterView_TextBox); diff --git a/FinTrack/ViewModels/ReportsViewModel.cs b/FinTrack/ViewModels/ReportsViewModel.cs index 345cd82..860a2a7 100644 --- a/FinTrack/ViewModels/ReportsViewModel.cs +++ b/FinTrack/ViewModels/ReportsViewModel.cs @@ -95,6 +95,13 @@ private void LoadSampleData() SelectedExportFormat = AvailableExportFormats.FirstOrDefault(); } + [RelayCommand] + private void SelectExportFormat(ExportFormat format) + { + SelectedExportFormat = format; + _logger?.LogInformation("Selected export format: {ExportFormat}", format); + } + [RelayCommand] private void CreateReport() { diff --git a/FinTrack/ViewModels/TopBarViewModel.cs b/FinTrack/ViewModels/TopBarViewModel.cs index 26793d1..16209f8 100644 --- a/FinTrack/ViewModels/TopBarViewModel.cs +++ b/FinTrack/ViewModels/TopBarViewModel.cs @@ -1,26 +1,25 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; -using CommunityToolkit.Mvvm.Messaging; +using FinTrack.Core; using FinTrack.Dtos; -using FinTrack.Messages; using FinTrack.Services.Api; using Microsoft.Extensions.Logging; namespace FinTrack.ViewModels { - public partial class TopBarViewModel : ObservableObject, IRecipient + public partial class TopBarViewModel : ObservableObject { [ObservableProperty] - private string? _userAvatar_TopBarView_Image; + private string userAvatar = "/Assets/Images/Icons/user-red.png"; [ObservableProperty] - private string? _userFullName_TopBarView_TextBlock; + private string userFullName = "User Full Name"; [ObservableProperty] - private string? _userEmail_TopBarView_TextBlock; + private string userEmail = "user@example.com"; [ObservableProperty] - private string? _userMembershipType_TopBarView_TextBlock; + private string userMembershipType = "Free"; public event Action? NavigateToDashboardRequested; public event Action? NavigateToAccountRequested; @@ -36,33 +35,36 @@ public partial class TopBarViewModel : ObservableObject, IRecipient _logger; private readonly IApiService _apiService; - private readonly IMessenger _messenger; - public TopBarViewModel(ILogger logger, IApiService apiService, IMessenger messenger) + public TopBarViewModel(ILogger logger, IApiService apiService) { _logger = logger; _apiService = apiService; - _messenger = messenger; - _messenger.Register(this); - } - - public void Receive(LoginSuccessMessage message) - { - _logger.LogInformation("Login başarılı, TopBarViewModel profil bilgilerini yüklüyor."); - _ = LoadProfile(); + if (SessionManager.IsLoggedIn) + { + _logger.LogInformation("Kullanıcı zaten giriş yapmış. TopBarViewModel profil bilgilerini yüklüyor."); + _ = LoadProfile(); + } } private async Task LoadProfile() { + if (!SessionManager.IsLoggedIn) + { + _logger.LogWarning("Kullanıcı oturumu açık değil, profil bilgileri yüklenemedi."); + return; + } var userProfile = await _apiService.GetAsync("user"); if (userProfile != null) { - UserAvatar_TopBarView_Image = userProfile.ProfilePicture; - UserFullName_TopBarView_TextBlock = userProfile.UserName; - UserEmail_TopBarView_TextBlock = userProfile.Email; - UserMembershipType_TopBarView_TextBlock = userProfile.MembershipType; + UserAvatar = userProfile.ProfilePicture; + UserFullName = userProfile.UserName; + UserEmail = userProfile.Email; + UserMembershipType = userProfile.MembershipType; + _logger.LogInformation("Kullanıcı profili başarıyla yüklendi. Kullanıcı Adı: {UserName}, Email: {Email}, Üyelik Tipi: {MembershipType}", + userProfile.UserName, userProfile.Email, userProfile.MembershipType); } else { diff --git a/FinTrack/Views/BottomBarView.xaml b/FinTrack/Views/BottomBarView.xaml index 37218a2..b1a36d2 100644 --- a/FinTrack/Views/BottomBarView.xaml +++ b/FinTrack/Views/BottomBarView.xaml @@ -24,15 +24,14 @@ VerticalAlignment="Center" HorizontalAlignment="Left" Margin="20,0,0,0"> - - - + diff --git a/FinTrack/Views/CurrenciesView.xaml b/FinTrack/Views/CurrenciesView.xaml index 0374396..0dd1ca2 100644 --- a/FinTrack/Views/CurrenciesView.xaml +++ b/FinTrack/Views/CurrenciesView.xaml @@ -90,19 +90,19 @@ - + - + - + - + diff --git a/FinTrack/Views/DashboardView.xaml b/FinTrack/Views/DashboardView.xaml index e4fda0e..7f7d917 100644 --- a/FinTrack/Views/DashboardView.xaml +++ b/FinTrack/Views/DashboardView.xaml @@ -308,7 +308,7 @@ - + @@ -323,14 +323,8 @@ + Command="{Binding DataContext.GenerateCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}" + CommandParameter="{Binding}"/> diff --git a/FinTrack/Views/NotificationView.xaml b/FinTrack/Views/NotificationView.xaml index 50dcb74..4787012 100644 --- a/FinTrack/Views/NotificationView.xaml +++ b/FinTrack/Views/NotificationView.xaml @@ -6,16 +6,11 @@ xmlns:vm="clr-namespace:FinTrack.ViewModels" xmlns:models="clr-namespace:FinTrack.Models.Notification" xmlns:enums="clr-namespace:FinTrack.Enums" - xmlns:helpers="clr-namespace:FinTrack.Helpers" mc:Ignorable="d" d:DesignHeight="800" d:DesignWidth="1200" d:DataContext="{d:DesignInstance Type=local:NotificationViewModel, IsDesignTimeCreatable=True}" Background="{StaticResource MainBackgroundBrush}"> - - - - @@ -98,7 +93,7 @@