u
This commit is contained in:
@@ -69,6 +69,48 @@ else
|
|||||||
<MudPaper Elevation="2" Class="pa-6 rounded-2xl mud-theme-surface mt-4">
|
<MudPaper Elevation="2" Class="pa-6 rounded-2xl mud-theme-surface mt-4">
|
||||||
<MudText Typo="Typo.h6" Class="mb-4 mud-typography-subtitle1">نظرات کاربران</MudText>
|
<MudText Typo="Typo.h6" Class="mb-4 mud-typography-subtitle1">نظرات کاربران</MudText>
|
||||||
|
|
||||||
|
<!-- Comment Submission Form (only for authenticated users) -->
|
||||||
|
@if (_isAuthenticated)
|
||||||
|
{
|
||||||
|
<MudPaper Outlined="true" Class="pa-4 rounded-lg mb-4">
|
||||||
|
<MudStack Row="true" AlignItems="AlignItems.Center">
|
||||||
|
<MudText Typo="Typo.subtitle1" Class="mb-3 fw-600">نظر خود را ثبت کنید</MudText>
|
||||||
|
<MudSpacer />
|
||||||
|
<MudRating @bind-Value="_newComment.Rating" Size="Size.Medium" />
|
||||||
|
</MudStack>
|
||||||
|
<MudStack Spacing="3">
|
||||||
|
<MudTextField @bind-Value="_newComment.Comment"
|
||||||
|
Label="نظر شما"
|
||||||
|
Variant="Variant.Outlined"
|
||||||
|
Lines="3"
|
||||||
|
Placeholder="نظر خود را درباره این پکیج بنویسید..." />
|
||||||
|
<MudStack AlignItems="AlignItems.Start">
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Color="Color.Primary"
|
||||||
|
OnClick="SubmitComment"
|
||||||
|
Disabled="_isSubmittingComment"
|
||||||
|
StartIcon="@Icons.Material.Filled.Send">
|
||||||
|
@(_isSubmittingComment ? "در حال ارسال..." : "ارسال نظر")
|
||||||
|
</MudButton>
|
||||||
|
</MudStack>
|
||||||
|
</MudStack>
|
||||||
|
</MudPaper>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<MudPaper Outlined="true" Class="pa-4 rounded-lg mb-4">
|
||||||
|
<MudStack AlignItems="AlignItems.Center" Spacing="2">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.Lock" Size="Size.Medium" Color="Color.Default" />
|
||||||
|
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||||
|
برای ثبت نظر ابتدا
|
||||||
|
<MudLink Href="javascript:void(0)" OnClick="() => Navigation.NavigateTo(RouteConstants.Auth.Phone)" Class="text-primary">وارد حساب کاربری</MudLink>
|
||||||
|
شوید.
|
||||||
|
</MudText>
|
||||||
|
</MudStack>
|
||||||
|
</MudPaper>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Reviews List -->
|
||||||
@if (_reviews.Any())
|
@if (_reviews.Any())
|
||||||
{
|
{
|
||||||
<MudStack Spacing="3">
|
<MudStack Spacing="3">
|
||||||
@@ -111,7 +153,7 @@ else
|
|||||||
<MudPaper Class="pa-2 rounded-xl" Style="background: radial-gradient(600px 280px at 120% 0, #daccff 0, transparent 60%), radial-gradient(600px 280px at -10% 100%, #ffe2f2 0, transparent 60%), linear-gradient(180deg, #fff, #fbfaff);">
|
<MudPaper Class="pa-2 rounded-xl" Style="background: radial-gradient(600px 280px at 120% 0, #daccff 0, transparent 60%), radial-gradient(600px 280px at -10% 100%, #ffe2f2 0, transparent 60%), linear-gradient(180deg, #fff, #fbfaff);">
|
||||||
<MudImage Src="@_package.Image"
|
<MudImage Src="@_package.Image"
|
||||||
Alt="@_package.Title"
|
Alt="@_package.Title"
|
||||||
Height="300"
|
Height="250"
|
||||||
ObjectFit="ObjectFit.Cover"
|
ObjectFit="ObjectFit.Cover"
|
||||||
ObjectPosition="ObjectPosition.Center"
|
ObjectPosition="ObjectPosition.Center"
|
||||||
Style="width:100%"
|
Style="width:100%"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Blazored.LocalStorage;
|
||||||
using FrontOffice.BFF.Package.Protobuf.Protos.Package;
|
using FrontOffice.BFF.Package.Protobuf.Protos.Package;
|
||||||
using FrontOffice.Main.Utilities;
|
using FrontOffice.Main.Utilities;
|
||||||
using Grpc.Core;
|
using Grpc.Core;
|
||||||
@@ -11,14 +12,20 @@ public partial class PackageDetail : IDisposable
|
|||||||
[Parameter] public long Id { get; set; }
|
[Parameter] public long Id { get; set; }
|
||||||
|
|
||||||
[Inject] private PackageContract.PackageContractClient PackageClient { get; set; } = default!;
|
[Inject] private PackageContract.PackageContractClient PackageClient { get; set; } = default!;
|
||||||
|
[Inject] private ILocalStorageService LocalStorage { get; set; } = default!;
|
||||||
|
|
||||||
private PackageDetailDto? _package;
|
private PackageDetailDto? _package;
|
||||||
private List<Review> _reviews = new();
|
private List<Review> _reviews = new();
|
||||||
private List<RelatedPackage> _relatedPackages = new();
|
private List<RelatedPackage> _relatedPackages = new();
|
||||||
private bool _isLoading = true;
|
private bool _isLoading = true;
|
||||||
private bool _isPurchasing;
|
private bool _isPurchasing;
|
||||||
|
private bool _isAuthenticated;
|
||||||
private CancellationTokenSource? _loadCts;
|
private CancellationTokenSource? _loadCts;
|
||||||
|
|
||||||
|
// Comment form
|
||||||
|
private NewComment _newComment = new();
|
||||||
|
private bool _isSubmittingComment;
|
||||||
|
|
||||||
|
|
||||||
private List<BreadcrumbItem> _breadcrumbItems = new()
|
private List<BreadcrumbItem> _breadcrumbItems = new()
|
||||||
{
|
{
|
||||||
@@ -28,6 +35,8 @@ public partial class PackageDetail : IDisposable
|
|||||||
};
|
};
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
|
await CheckAuthStatus();
|
||||||
|
|
||||||
if (Id < 1)
|
if (Id < 1)
|
||||||
{
|
{
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
@@ -55,7 +64,6 @@ public partial class PackageDetail : IDisposable
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Load package details
|
// Load package details
|
||||||
var packageRequest = new GetPackageRequest { Id = Id };
|
|
||||||
var packageResponse = await PackageClient.GetPackageAsync(request: new() { Id = Id}, cancellationToken: _loadCts.Token);
|
var packageResponse = await PackageClient.GetPackageAsync(request: new() { Id = Id}, cancellationToken: _loadCts.Token);
|
||||||
|
|
||||||
if (packageResponse != null)
|
if (packageResponse != null)
|
||||||
@@ -157,6 +165,64 @@ public partial class PackageDetail : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task CheckAuthStatus()
|
||||||
|
{
|
||||||
|
var token = await LocalStorage.GetItemAsync<string>("auth:token");
|
||||||
|
_isAuthenticated = !string.IsNullOrWhiteSpace(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SubmitComment()
|
||||||
|
{
|
||||||
|
if (!_isAuthenticated)
|
||||||
|
{
|
||||||
|
Snackbar.Add("برای ثبت نظر ابتدا وارد حساب کاربری شوید.", Severity.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(_newComment.Comment))
|
||||||
|
{
|
||||||
|
Snackbar.Add("لطفاً نظر خود را وارد کنید.", Severity.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_newComment.Rating < 1 || _newComment.Rating > 5)
|
||||||
|
{
|
||||||
|
Snackbar.Add("لطفاً امتیاز را انتخاب کنید.", Severity.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isSubmittingComment = true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// TODO: Submit comment to API
|
||||||
|
await Task.Delay(1000); // Simulate API call
|
||||||
|
|
||||||
|
// Add the new comment to the list
|
||||||
|
var newReview = new Review
|
||||||
|
{
|
||||||
|
UserName = "کاربر فعلی", // TODO: Get from user profile
|
||||||
|
Rating = _newComment.Rating,
|
||||||
|
Comment = _newComment.Comment,
|
||||||
|
Date = DateTime.Now.ToString("yyyy/MM/dd")
|
||||||
|
};
|
||||||
|
|
||||||
|
_reviews.Insert(0, newReview);
|
||||||
|
_newComment = new NewComment();
|
||||||
|
|
||||||
|
Snackbar.Add("نظر شما با موفقیت ثبت شد.", Severity.Success);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Snackbar.Add($"خطا در ثبت نظر: {ex.Message}", Severity.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_isSubmittingComment = false;
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void NavigateToPackage(string packageId)
|
private void NavigateToPackage(string packageId)
|
||||||
{
|
{
|
||||||
Navigation.NavigateTo($"{RouteConstants.Package.Detail}/{packageId}");
|
Navigation.NavigateTo($"{RouteConstants.Package.Detail}/{packageId}");
|
||||||
@@ -211,4 +277,10 @@ public partial class PackageDetail : IDisposable
|
|||||||
public string? Image { get; set; }
|
public string? Image { get; set; }
|
||||||
public PricingInfo Pricing { get; set; } = new();
|
public PricingInfo Pricing { get; set; } = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class NewComment
|
||||||
|
{
|
||||||
|
public int Rating { get; set; } = 5;
|
||||||
|
public string? Comment { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user