Compare commits

...

6 Commits

Author SHA1 Message Date
masoodafar-web 230453e491 feat(config): add production configuration for gateway URL and authentication
Build and Deploy to Production / build-and-deploy (push) Successful in 4m5s
2025-12-27 07:46:54 +03:30
masoodafar-web 1a65babb9d feat(UserPayouts): update status options and colors for user payouts
Build and Deploy / build (push) Successful in 2m8s
2025-12-27 07:34:38 +03:30
masoodafar-web bbe783dc83 feat(UserPayouts): implement withdrawal approval and rejection functionality
Build and Deploy / build (push) Successful in 2m6s
2025-12-27 06:22:11 +03:30
masoodafar-web 6f5bfba0a5 feat(AppVersionEditDialog): replace ReleaseNotes text field with HTML editor for enhanced formatting
Build and Deploy / build (push) Successful in 2m9s
2025-12-27 05:08:14 +03:30
masoodafar-web 98a4ba9e99 feat(config): Add staging configuration for backend URL and authentication
Build and Deploy / build (push) Has been cancelled
2025-12-27 05:07:50 +03:30
masoodafar-web ece29956b2 feat(app-versions): Add functionality to create new app versions and update UI components
Build and Deploy / build (push) Successful in 2m26s
2025-12-27 02:45:47 +03:30
8 changed files with 186 additions and 40 deletions
@@ -31,7 +31,10 @@
<MudSelectItem Value="@((int?)null)">همه</MudSelectItem> <MudSelectItem Value="@((int?)null)">همه</MudSelectItem>
<MudSelectItem Value="@((int?)0)">در انتظار</MudSelectItem> <MudSelectItem Value="@((int?)0)">در انتظار</MudSelectItem>
<MudSelectItem Value="@((int?)1)">پرداخت شده</MudSelectItem> <MudSelectItem Value="@((int?)1)">پرداخت شده</MudSelectItem>
<MudSelectItem Value="@((int?)2)">شکست خورده</MudSelectItem> <MudSelectItem Value="@((int?)2)">درخواست برداشت</MudSelectItem>
<MudSelectItem Value="@((int?)3)">برداشت شده</MudSelectItem>
<MudSelectItem Value="@((int?)4)">شکست خورده</MudSelectItem>
<MudSelectItem Value="@((int?)5)">لغو شده</MudSelectItem>
</MudSelect> </MudSelect>
<MudButton Variant="Variant.Filled" <MudButton Variant="Variant.Filled"
Color="Color.Primary" Color="Color.Primary"
@@ -109,13 +112,19 @@
Color="Color.Info" Color="Color.Info"
OnClick="@(() => ViewDetails(context.Item))" /> OnClick="@(() => ViewDetails(context.Item))" />
</MudTooltip> </MudTooltip>
@if (context.Item.Status == 0) @if (context.Item.Status == 2) @* WithdrawRequested *@
{ {
<MudTooltip Text="پردازش برداشت"> <MudTooltip Text="تایید برداشت">
<MudIconButton Icon="@Icons.Material.Filled.Payment" <MudIconButton Icon="@Icons.Material.Filled.CheckCircle"
Size="Size.Small" Size="Size.Small"
Color="Color.Success" Color="Color.Success"
OnClick="@(() => ProcessWithdrawal(context.Item))" /> OnClick="@(() => ApproveWithdrawal(context.Item))" />
</MudTooltip>
<MudTooltip Text="رد برداشت">
<MudIconButton Icon="@Icons.Material.Filled.Cancel"
Size="Size.Small"
Color="Color.Error"
OnClick="@(() => RejectWithdrawal(context.Item))" />
</MudTooltip> </MudTooltip>
} }
</MudStack> </MudStack>
@@ -79,9 +79,12 @@ public partial class UserPayouts
{ {
return status switch return status switch
{ {
0 => Color.Warning, // Pending 0 => Color.Warning, // Pending - در انتظار
1 => Color.Success, // Paid 1 => Color.Success, // Paid - پرداخت شده
2 => Color.Error, // Failed 2 => Color.Info, // WithdrawRequested - درخواست برداشت
3 => Color.Primary, // Withdrawn - برداشت شده
4 => Color.Error, // PaymentFailed - شکست خورده
5 => Color.Dark, // Cancelled - لغو شده
_ => Color.Default _ => Color.Default
}; };
} }
@@ -92,7 +95,10 @@ public partial class UserPayouts
{ {
0 => "در انتظار", 0 => "در انتظار",
1 => "پرداخت شده", 1 => "پرداخت شده",
2 => "شکست خورده", 2 => "درخواست برداشت",
3 => "برداشت شده",
4 => "شکست خورده",
5 => "لغو شده",
_ => "نامشخص" _ => "نامشخص"
}; };
} }
@@ -112,24 +118,55 @@ public partial class UserPayouts
}); });
} }
private async Task ProcessWithdrawal(UserCommissionPayoutModel payout) private async Task ApproveWithdrawal(UserCommissionPayoutModel payout)
{ {
var confirmed = await DialogService.ShowMessageBox( var confirmed = await DialogService.ShowMessageBox(
"تایید پردازش برداشت", "تایید برداشت",
$"آیا از پردازش برداشت برای کاربر {payout.UserName} (مبلغ: {payout.TotalAmount:N0} ریال) مطمئن هستید؟", $"آیا از تایید برداشت برای کاربر {payout.UserName} (مبلغ: {payout.TotalAmount:N0} ریال) مطمئن هستید؟",
yesText: "تایید", cancelText: "لغو"); yesText: "تایید", cancelText: "لغو");
if (confirmed == true) if (confirmed == true)
{ {
try try
{ {
// TODO: Call ProcessWithdrawal API await CommissionContract.ProcessWithdrawalAsync(new ProcessWithdrawalRequest
Snackbar.Add("درخواست برداشت با موفقیت پردازش شد", Severity.Success); {
PayoutId = payout.Id,
IsApproved = true
});
Snackbar.Add("درخواست برداشت با موفقیت تایید شد", Severity.Success);
await ApplyFilter(); await ApplyFilter();
} }
catch (Exception ex) catch (Exception ex)
{ {
Snackbar.Add($"خطا در پردازش: {ex.Message}", Severity.Error); Snackbar.Add($"خطا در تایید: {ex.Message}", Severity.Error);
}
}
}
private async Task RejectWithdrawal(UserCommissionPayoutModel payout)
{
var reason = await DialogService.ShowMessageBox(
"رد برداشت",
$"آیا از رد برداشت برای کاربر {payout.UserName} مطمئن هستید؟",
yesText: "رد کردن", cancelText: "لغو");
if (reason == true)
{
try
{
await CommissionContract.ProcessWithdrawalAsync(new ProcessWithdrawalRequest
{
PayoutId = payout.Id,
IsApproved = false,
Reason = "رد شده توسط ادمین"
});
Snackbar.Add("درخواست برداشت رد شد", Severity.Warning);
await ApplyFilter();
}
catch (Exception ex)
{
Snackbar.Add($"خطا در رد: {ex.Message}", Severity.Error);
} }
} }
} }
@@ -26,6 +26,13 @@
T="bool" T="bool"
ValueChanged="@(async (bool val) => { _includeInactive = val; await LoadVersions(); })" /> ValueChanged="@(async (bool val) => { _includeInactive = val; await LoadVersions(); })" />
<MudStack Row="true" Spacing="2">
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Add"
OnClick="@OpenCreateDialog">
افزودن نسخه جدید
</MudButton>
<MudButton Variant="Variant.Outlined" <MudButton Variant="Variant.Outlined"
Color="Color.Primary" Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Refresh" StartIcon="@Icons.Material.Filled.Refresh"
@@ -33,6 +40,7 @@
بارگذاری مجدد بارگذاری مجدد
</MudButton> </MudButton>
</MudStack> </MudStack>
</MudStack>
@if (_loading) @if (_loading)
{ {
@@ -61,7 +69,7 @@
<TemplateColumn Title="نسخه فعلی"> <TemplateColumn Title="نسخه فعلی">
<CellTemplate> <CellTemplate>
<MudChip T="string" Color="Color.Primary" Size="Size.Small" Variant="Variant.Outlined"> <MudChip T="string" Color="Color.Primary" Size="Size.Small" Variant="Variant.Outlined">
v@context.Item.CurrentVersion @context.Item.CurrentVersion
</MudChip> </MudChip>
</CellTemplate> </CellTemplate>
</TemplateColumn> </TemplateColumn>
@@ -71,7 +79,7 @@
@if (!string.IsNullOrEmpty(context.Item.MinRequiredVersion)) @if (!string.IsNullOrEmpty(context.Item.MinRequiredVersion))
{ {
<MudChip T="string" Color="Color.Warning" Size="Size.Small" Variant="Variant.Outlined"> <MudChip T="string" Color="Color.Warning" Size="Size.Small" Variant="Variant.Outlined">
v@context.Item.MinRequiredVersion @context.Item.MinRequiredVersion
</MudChip> </MudChip>
} }
else else
@@ -151,14 +159,14 @@
<MudStack Spacing="2"> <MudStack Spacing="2">
<MudStack Row="true" Justify="Justify.SpaceBetween"> <MudStack Row="true" Justify="Justify.SpaceBetween">
<MudText Typo="Typo.body2">نسخه فعلی:</MudText> <MudText Typo="Typo.body2">نسخه فعلی:</MudText>
<MudChip T="string" Color="Color.Primary" Size="Size.Small">v@version.CurrentVersion</MudChip> <MudChip T="string" Color="Color.Primary" Size="Size.Small">@version.CurrentVersion</MudChip>
</MudStack> </MudStack>
<MudStack Row="true" Justify="Justify.SpaceBetween"> <MudStack Row="true" Justify="Justify.SpaceBetween">
<MudText Typo="Typo.body2">حداقل نسخه:</MudText> <MudText Typo="Typo.body2">حداقل نسخه:</MudText>
@if (!string.IsNullOrEmpty(version.MinRequiredVersion)) @if (!string.IsNullOrEmpty(version.MinRequiredVersion))
{ {
<MudChip T="string" Color="Color.Warning" Size="Size.Small">v@version.MinRequiredVersion</MudChip> <MudChip T="string" Color="Color.Warning" Size="Size.Small">@version.MinRequiredVersion</MudChip>
} }
else else
{ {
@@ -215,6 +223,52 @@
} }
} }
private async Task OpenCreateDialog()
{
var parameters = new DialogParameters<AppVersionEditDialog>
{
{ x => x.Model, new UpdateAppVersionDto
{
AppName = "",
CurrentVersion = "1.0.0",
MinRequiredVersion = null,
RequiresFullCacheClear = false,
UpdateMessage = null,
ReleaseNotes = null
}
},
{ x => x.IsNew, true }
};
var options = new DialogOptions
{
CloseButton = true,
MaxWidth = MaxWidth.Medium,
FullWidth = true
};
var dialog = await DialogService.ShowAsync<AppVersionEditDialog>(
"افزودن نسخه جدید",
parameters,
options);
var result = await dialog.Result;
if (result is { Canceled: false, Data: UpdateAppVersionDto dto })
{
try
{
await AppVersionService.UpdateAsync(dto);
Snackbar.Add("نسخه جدید با موفقیت ایجاد شد", Severity.Success);
await LoadVersions();
}
catch (Exception ex)
{
Snackbar.Add($"خطا در ایجاد: {ex.Message}", Severity.Error);
}
}
}
private async Task OpenEditDialog(AppVersionDto version) private async Task OpenEditDialog(AppVersionDto version)
{ {
var parameters = new DialogParameters<AppVersionEditDialog> var parameters = new DialogParameters<AppVersionEditDialog>
@@ -296,15 +350,15 @@
private string GetAppIcon(string appName) => appName switch private string GetAppIcon(string appName) => appName switch
{ {
"FoursatMarketApp" => Icons.Material.Filled.ShoppingCart, "KaraBazarApp" => Icons.Material.Filled.ShoppingCart,
"FoursatClubApp" => Icons.Material.Filled.Groups, "KaraBazarAdminApp" => Icons.Material.Filled.AdminPanelSettings,
_ => Icons.Material.Filled.PhoneAndroid _ => Icons.Material.Filled.PhoneAndroid
}; };
private Color GetAppColor(string appName) => appName switch private Color GetAppColor(string appName) => appName switch
{ {
"FoursatMarketApp" => Color.Primary, "KaraBazarApp" => Color.Primary,
"FoursatClubApp" => Color.Secondary, "KaraBazarAdminApp" => Color.Secondary,
_ => Color.Default _ => Color.Default
}; };
} }
@@ -1,15 +1,30 @@
@using BackOffice.Services.AppVersion @using BackOffice.Services.AppVersion
@using Tizzani.MudBlazor.HtmlEditor
@inject ISnackbar Snackbar @inject ISnackbar Snackbar
<MudDialog> <MudDialog>
<DialogContent> <DialogContent>
<MudForm @ref="_form" @bind-IsValid="_isValid"> <MudForm @ref="_form" @bind-IsValid="_isValid">
<MudStack Spacing="3"> <MudStack Spacing="3">
@if (IsNew)
{
<MudSelect @bind-Value="Model.AppName"
Label="نام اپلیکیشن"
Variant="Variant.Outlined"
Required="true"
RequiredError="انتخاب اپلیکیشن اجباری است">
<MudSelectItem Value="@("KaraBazarApp")">کارابازار</MudSelectItem>
<MudSelectItem Value="@("KaraBazarAdminApp")">ادمین کارابازار</MudSelectItem>
</MudSelect>
}
else
{
<MudTextField @bind-Value="Model.AppName" <MudTextField @bind-Value="Model.AppName"
Label="نام اپلیکیشن" Label="نام اپلیکیشن"
Variant="Variant.Outlined" Variant="Variant.Outlined"
ReadOnly="true" ReadOnly="true"
Disabled="true" /> Disabled="true" />
}
<MudTextField @bind-Value="Model.CurrentVersion" <MudTextField @bind-Value="Model.CurrentVersion"
Label="نسخه فعلی" Label="نسخه فعلی"
@@ -33,11 +48,11 @@
Lines="2" Lines="2"
HelperText="پیامی که به کاربر نمایش داده می‌شود" /> HelperText="پیامی که به کاربر نمایش داده می‌شود" />
<MudTextField @bind-Value="Model.ReleaseNotes" <MudText Typo="Typo.subtitle2" Class="mt-2">یادداشت‌های انتشار (HTML)</MudText>
Label="یادداشت‌های انتشار" <MudHtmlEditor @bind-Html="Model.ReleaseNotes"
Variant="Variant.Outlined" Placeholder="توضیحات تغییرات این نسخه..."
Lines="4" MinHeight="150px">
HelperText="توضیحات تغییرات این نسخه" /> </MudHtmlEditor>
<MudDivider Class="my-2" /> <MudDivider Class="my-2" />
@@ -68,6 +83,9 @@
[Parameter] [Parameter]
public UpdateAppVersionDto Model { get; set; } = new(); public UpdateAppVersionDto Model { get; set; } = new();
[Parameter]
public bool IsNew { get; set; } = false;
private MudForm? _form; private MudForm? _form;
private bool _isValid; private bool _isValid;
+11
View File
@@ -252,6 +252,15 @@
تنظیمات سیستم تنظیمات سیستم
</MudNavLink> </MudNavLink>
} }
@if (CanViewSettings)
{
<MudNavLink Match="NavLinkMatch.Prefix"
Href="/settings/app-versions"
Icon="@Icons.Material.Filled.PhoneAndroid">
نسخه اپلیکیشن‌ها
</MudNavLink>
}
</Authorized> </Authorized>
</AuthorizeView> </AuthorizeView>
@@ -295,6 +304,7 @@
private bool CanViewSystemAlerts; private bool CanViewSystemAlerts;
private bool CanViewSystemHealth; private bool CanViewSystemHealth;
private bool CanManageSystemConfiguration; private bool CanManageSystemConfiguration;
private bool CanViewSettings;
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
@@ -323,6 +333,7 @@
CanViewSystemAlerts = await AuthorizationService.HasPermissionAsync("system.alerts.view"); CanViewSystemAlerts = await AuthorizationService.HasPermissionAsync("system.alerts.view");
CanViewSystemHealth = await AuthorizationService.HasPermissionAsync("system.health.view"); CanViewSystemHealth = await AuthorizationService.HasPermissionAsync("system.health.view");
CanManageSystemConfiguration = await AuthorizationService.HasPermissionAsync("settings.manage_configuration"); CanManageSystemConfiguration = await AuthorizationService.HasPermissionAsync("settings.manage_configuration");
CanViewSettings = await AuthorizationService.HasPermissionAsync("settings.view");
_initialized = true; _initialized = true;
StateHasChanged(); StateHasChanged();
@@ -0,0 +1,8 @@
{
// "GwUrl": "https://localhost:6468",
"GwUrl": "https://bogw.kbs2.ir",
"Authentication": {
"Authority": "https://ids.afrino.co/",
"ClientId": "client_backoffice_spa"
}
}
@@ -0,0 +1,8 @@
{
// "GwUrl": "https://localhost:6468",
"GwUrl": "https://backoffice-bff.foursat.afrino.co",
"Authentication": {
"Authority": "https://ids.afrino.co/",
"ClientId": "client_backoffice_spa"
}
}
+2 -1
View File
@@ -1,5 +1,6 @@
{ {
"GwUrl": "https://bogw.kbs2.ir", // "GwUrl": "https://localhost:6468",
"GwUrl": "https://backoffice-bff.foursat.afrino.co",
"Authentication": { "Authentication": {
"Authority": "https://ids.afrino.co/", "Authority": "https://ids.afrino.co/",
"ClientId": "client_backoffice_spa" "ClientId": "client_backoffice_spa"