using FrontOffice.BFF.Configuration.Protobuf.Protos.AppVersion; using Blazored.LocalStorage; using Microsoft.JSInterop; namespace FrontOffice.Main.Utilities; /// /// نتیجه بررسی نسخه اپلیکیشن /// public class VersionCheckResult { /// /// آیا نسخه جدیدی وجود دارد /// public bool HasNewVersion { get; set; } /// /// آیا آپدیت اجباری است (force update) /// public bool IsForceUpdate { get; set; } /// /// نسخه فعلی (local) /// public string? OldVersion { get; set; } /// /// نسخه جدید (server) /// public string? NewVersion { get; set; } /// /// یادداشت‌های انتشار /// public string? ReleaseNotes { get; set; } /// /// پیام آپدیت /// public string? UpdateMessage { get; set; } /// /// آیا کش باید پاک شود /// public bool RequiresCacheClear { get; set; } } /// /// سرویس مدیریت نسخه اپلیکیشن و کش /// وقتی نسخه جدید منتشر بشه، این سرویس متوجه میشه و کش رو پاک می‌کنه /// public class AppVersionService { private readonly AppVersionContract.AppVersionContractClient _client; private readonly ILocalStorageService _localStorage; private readonly IJSRuntime _jsRuntime; private readonly ILogger _logger; private const string APP_NAME = "KaraBazarApp"; private const string LOCAL_VERSION_KEY = "app_version"; private const string LAST_CHECK_KEY = "app_version_last_check"; private const string SKIPPED_VERSION_KEY = "app_version_skipped"; private const string LAST_DIALOG_SHOWN_KEY = "app_version_last_dialog_shown"; public AppVersionService( AppVersionContract.AppVersionContractClient client, ILocalStorageService localStorage, IJSRuntime jsRuntime, ILogger logger) { _client = client; _localStorage = localStorage; _jsRuntime = jsRuntime; _logger = logger; } /// /// بررسی نسخه اپلیکیشن و برگرداندن نتیجه /// /// اگر true باشه، نسخه‌های skip شده هم نشون داده میشن (برای آیکون منو) /// اگر true باشه، چک میکنه که یک روز از آخرین نمایش گذشته (برای popup) public async Task CheckVersionAsync(bool ignoreSkipped = false, bool forDialog = false) { var result = new VersionCheckResult(); try { // دریافت نسخه فعلی از localStorage var localVersion = await _localStorage.GetItemAsStringAsync(LOCAL_VERSION_KEY); var skippedVersion = await _localStorage.GetItemAsStringAsync(SKIPPED_VERSION_KEY); var lastDialogShown = await _localStorage.GetItemAsStringAsync(LAST_DIALOG_SHOWN_KEY); result.OldVersion = localVersion; // بررسی نسخه از سرور var response = await _client.GetAppVersionAsync(new GetAppVersionRequest { AppName = APP_NAME, CurrentClientVersion = localVersion }); if (!response.Found) { _logger.LogWarning("App version not found on server for {AppName}", APP_NAME); return result; } var serverVersion = response.CurrentVersion; result.NewVersion = serverVersion; result.ReleaseNotes = response.ReleaseNotes; result.UpdateMessage = response.UpdateMessage; result.RequiresCacheClear = response.RequiresFullCacheClear; result.IsForceUpdate = response.RequiresUpdate; // اگر نسخه کمتر از حداقل باشه // آیا نسخه جدید داریم؟ if (localVersion != serverVersion) { result.HasNewVersion = true; // اگر این نسخه رو قبلاً skip کرده و force نیست if (!result.IsForceUpdate && skippedVersion == serverVersion && !ignoreSkipped) { // برای popup: چک کن یک روز گذشته یا نه if (forDialog) { var oneDayPassed = await HasOneDayPassedSinceLastDialogAsync(lastDialogShown); if (!oneDayPassed) { result.HasNewVersion = false; } // اگه یک روز گذشته، HasNewVersion = true میمونه } else { result.HasNewVersion = false; } } _logger.LogInformation( "Version check: {OldVersion} -> {NewVersion}, Force: {Force}, Skipped: {Skipped}", localVersion ?? "null", serverVersion, result.IsForceUpdate, skippedVersion); } } catch (Exception ex) { _logger.LogError(ex, "Error checking app version"); } return result; } /// /// چک کردن اینکه یک روز از آخرین نمایش دیالوگ گذشته یا نه /// private async Task HasOneDayPassedSinceLastDialogAsync(string? lastDialogShown) { if (string.IsNullOrEmpty(lastDialogShown)) return true; // اگه هیچوقت نشون نداده، نشون بده if (DateTime.TryParse(lastDialogShown, out var lastShown)) { return DateTime.UtcNow.Subtract(lastShown).TotalDays >= 1; } return true; } /// /// ثبت زمان نمایش دیالوگ /// public async Task RecordDialogShownAsync() { await _localStorage.SetItemAsStringAsync(LAST_DIALOG_SHOWN_KEY, DateTime.UtcNow.ToString("O")); } /// /// اعمال آپدیت - پاک کردن کش و ذخیره نسخه جدید /// public async Task ApplyUpdateAsync(string newVersion) { try { _logger.LogInformation("Applying update to version {Version}", newVersion); // پاک کردن کش await ClearAllCacheAsync(); // ذخیره نسخه جدید await _localStorage.SetItemAsStringAsync(LOCAL_VERSION_KEY, newVersion); await _localStorage.SetItemAsStringAsync(LAST_CHECK_KEY, DateTime.UtcNow.ToString("O")); // پاک کردن نسخه skip شده await _localStorage.RemoveItemAsync(SKIPPED_VERSION_KEY); _logger.LogInformation("Update applied successfully to {Version}", newVersion); } catch (Exception ex) { _logger.LogError(ex, "Error applying update"); throw; } } /// /// Skip کردن این نسخه (بعداً) /// public async Task SkipVersionAsync(string version) { try { await _localStorage.SetItemAsStringAsync(SKIPPED_VERSION_KEY, version); _logger.LogInformation("Version {Version} skipped by user", version); } catch (Exception ex) { _logger.LogError(ex, "Error skipping version"); } } /// /// پاک کردن همه کش‌های اپلیکیشن /// private async Task ClearAllCacheAsync() { try { // پاک کردن کش مرورگر (Cache Storage و Service Worker) await _jsRuntime.InvokeVoidAsync("clearBrowserCache"); _logger.LogInformation("Browser cache cleared successfully"); } catch (Exception ex) { _logger.LogError(ex, "Error clearing browser cache"); } } /// /// دریافت اطلاعات نسخه فعلی /// public async Task GetCurrentVersionInfoAsync() { try { var response = await _client.GetAppVersionAsync(new GetAppVersionRequest { AppName = APP_NAME }); if (!response.Found) return null; return new AppVersionInfo { CurrentVersion = response.CurrentVersion, MinRequiredVersion = response.MinRequiredVersion, RequiresUpdate = response.RequiresUpdate, UpdateMessage = response.UpdateMessage, ReleaseNotes = response.ReleaseNotes, LastUpdated = response.LastUpdated?.ToDateTime() }; } catch (Exception ex) { _logger.LogError(ex, "Error getting version info"); return null; } } } public class AppVersionInfo { public string CurrentVersion { get; set; } = string.Empty; public string MinRequiredVersion { get; set; } = string.Empty; public bool RequiresUpdate { get; set; } public string? UpdateMessage { get; set; } public string? ReleaseNotes { get; set; } public DateTime? LastUpdated { get; set; } }