From 34c5c508e0e0a85c705a5a86f9461df647e87585 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Thu, 11 Jun 2026 23:33:40 +0330 Subject: [PATCH 1/4] feat: update package version and enhance network membership DTOs - Updated the version of the Foursat.CMSMicroservice.Protobuf package from 0.0.197 to 0.0.199. - Added a new property `PackageName` to `NetworkNodeDto` and `FlatNetworkNodeDto` for better representation of membership packages. - Updated mapping in `NetworkMembershipService` to include the new `PackageName` property. - Enhanced the org chart display by adding a badge for the package name in the UI. These changes improve the clarity and functionality of the network membership features. --- docs/CUSTOMER-SERVICES.md | 260 ++++++++++++++++++ src/FrontOffice.Main/FrontOffice.Main.csproj | 2 +- .../Utilities/NetworkMembershipDtos.cs | 13 +- .../Utilities/NetworkMembershipService.cs | 1 + .../wwwroot/css/org-chart.css | 17 ++ src/FrontOffice.Main/wwwroot/js/org-chart.js | 8 +- 6 files changed, 298 insertions(+), 3 deletions(-) create mode 100644 docs/CUSTOMER-SERVICES.md diff --git a/docs/CUSTOMER-SERVICES.md b/docs/CUSTOMER-SERVICES.md new file mode 100644 index 0000000..a7031de --- /dev/null +++ b/docs/CUSTOMER-SERVICES.md @@ -0,0 +1,260 @@ +# سرویس‌های FrontOffice (سمت مشتری) + +این سند تمام سرویس‌هایی را که **FrontOffice** (فرانت مشتری) به **CMS** از طریق gRPC Gateway (`GW_URL`) فراخوانی می‌کند، به ترتیب **Use Case** فهرست می‌کند. + +- **مسیر کد سرویس‌ها:** `FrontOffice/src/FrontOffice.Main/Utilities/` +- **ثبت gRPC:** `FrontOffice/src/FrontOffice.Main/ConfigureServices.cs` +- **تاریخ:** ۱۴۰۵/۰۳/۱۷ + +--- + +## ۱. احراز هویت و ثبت‌نام + +| # | سرویس / متد | gRPC Contract | صفحه / کامپوننت | کاربرد | +|---|-------------|---------------|-----------------|--------| +| 1.1 | `AuthService` — `RefreshTokenAsync` | `UserContract.RefreshToken` | `/profile` (`Profile/Index`) | تمدید JWT پس از بازگشت از درگاه پرداخت | +| 1.2 | `AuthService` — `InitUserAuthInfo` / claims | — (local JWT parse) | سراسری | خواندن UserId، نام، کدملی، وضعیت قرارداد/پکیج/باشگاه از توکن | +| 1.3 | `UserContract.CreateNewOtpToken` | `UserContract` | `Shared/AuthDialog` | ارسال OTP ورود/ثبت‌نام با موبایل | +| 1.4 | `UserContract.VerifyOtpToken` | `UserContract` | `Shared/AuthDialog` | تأیید OTP و دریافت JWT | +| 1.5 | `UserContract.CreateNewOtpToken` (Purpose=`signContract`) | `UserContract` | `/register` (`RegisterWizard`) | ارسال OTP برای امضای قرارداد اصلی | +| 1.6 | `UserContract.AcceptContract` | `UserContract` | `/register` (`RegisterWizard`) | ثبت امضای قرارداد اصلی + دریافت توکن به‌روز | +| 1.7 | `UserContract.GetUserForCustomer` | `UserContract` | `/register`, `/profile`, `/profile/personal`, `/profile/settings` | بارگذاری پروفایل موجود کاربر | +| 1.8 | `UserContract.UpdateCustomerProfile` | `UserContract` | `/register`, `/profile`, `/profile/personal` | ذخیره نام، نام‌خانوادگی، کدملی و… | +| 1.9 | `AuthDialogService.ShowAuthDialogAsync` | — (UI) | فروشگاه، سبد، checkout | نمایش دیالوگ ورود برای مهمان | +| 1.10 | `GuestActionGate` | — (wrapper روی Auth) | `/`, `/products`, `/product/{id}`, Discount Store | جلوگیری از افزودن به سبد بدون لاگین | + +--- + +## ۲. پروفایل و آدرس + +| # | سرویس / متد | gRPC Contract | صفحه / کامپوننت | کاربرد | +|---|-------------|---------------|-----------------|--------| +| 2.1 | `UserContract.GetUserForCustomer` | `UserContract` | `/profile`, `/profile/personal`, `/profile/settings` | نمایش و ویرایش اطلاعات شخصی | +| 2.2 | `UserContract.GetUser` | `UserContract` | `/profile/hub`, `Club/ActivationSection` | اطلاعات کامل کاربر (هاب پروفایل / پس از فعال‌سازی باشگاه) | +| 2.3 | `UserContract.UpdateUser` | `UserContract` | `/profile/settings` | به‌روزرسانی تنظیمات حساب | +| 2.4 | `UserAddressContract.GetCustomerAddresses` | `UserAddressContract` | `/profile`, `/profile/addresses`, `/checkout`, Store/Discount checkout | لیست آدرس‌های تحویل | +| 2.5 | `UserAddressContract.CreateCustomerAddress` | `UserAddressContract` | `Profile/Components/AddAddressDialog` | ثبت آدرس جدید | +| 2.6 | `UserAddressContract.UpdateCustomerAddress` | `UserAddressContract` | `Profile/Components/EditAddressDialog` | ویرایش آدرس | +| 2.7 | `UserAddressContract.DeleteCustomerAddress` / `DeleteUserAddress` | `UserAddressContract` | `/profile/addresses`, `/profile` | حذف آدرس | +| 2.8 | `UserAddressContract.SetCustomerDefaultAddress` / `SetAddressAsDefault` | `UserAddressContract` | `/profile/addresses`, `/profile`, `/checkout` | تنظیم آدرس پیش‌فرض | +| 2.9 | `CityContract.GetAllCitiesByFilter` | `CityContract` | `AddAddressDialog`, `EditAddressDialog` | جستجو و انتخاب شهر/استان | + +--- + +## ۳. پکیج و خرید عضویت + +| # | سرویس / متد | gRPC Contract | صفحه / کامپوننت | کاربرد | +|---|-------------|---------------|-----------------|--------| +| 3.1 | `PackageService.GetAllPackagesAsync` | `PackageContract.GetCustomerPackages` | `/packages`, `/my-packages`, `/`, `/checkout`, `PackagePurchaseDialog`, `ClubMembershipContractDialog`, Commission pages | لیست پکیج‌های قابل خرید | +| 3.2 | `PackageService.GetPackageByIdAsync` | `PackageContract.GetCustomerPackageDetails` | (از طریق wrapper؛ صفحه جزئیات مستقیم RPC دارد) | جزئیات یک پکیج | +| 3.3 | `PackageContract.GetCustomerPackageDetails` | `PackageContract` | `/package/{id}` (`PackageDetail`) | جزئیات، ویژگی‌ها و مشخصات پکیج | +| 3.4 | `PackageService.GetUserPackageStatusAsync` | `PackageContract.GetUserPackageStatus` | `/packages`, `/my-packages`, `/profile` | وضعیت خرید پکیج، باشگاه، موجودی کیف پول | +| 3.5 | `PackageContract.CustomerPurchasePackage` | `PackageContract` | `/profile` (`ProcessDirectPayment`), `/checkout` | شروع پرداخت درگاهی (Zarinpal) برای خرید پکیج | +| 3.6 | `PackageContract.CustomerVerifyPackagePurchase` | `PackageContract` | `/profile/payment-callback?type=package` | تأیید پرداخت پکیج پس از بازگشت از درگاه | +| 3.7 | `PackagePurchaseDialog` | — (UI + `PackageService`) | `/profile`, `/my-packages` | انتخاب پکیج و روش پرداخت (درگاه / Daya) | +| 3.8 | Daya Loan (external URL) | — | `/profile` | هدایت به `dayadiamond.ir` برای خرید اقساطی (بدون RPC) | + +--- + +## ۴. کیف پول، شارژ و برداشت + +| # | سرویس / متد | gRPC Contract | صفحه / کامپوننت | کاربرد | +|---|-------------|---------------|-----------------|--------| +| 4.1 | `WalletService.GetBalancesAsync` | `UserWalletContract.GetCustomerWallet` | `/profile`, `/profile/wallet`, Store checkout, PaymentCallback | موجودی اصلی، تخفیفی و شبکه | +| 4.2 | `WalletService.GetTransactionsAsync` | `UserWalletContract.GetCustomerWalletHistory` | `/profile/wallet` | تاریخچه تراکنش‌های کیف پول | +| 4.3 | `WalletService.GetMagicWalletStatusAsync` | `UserWalletContract.GetMagicWalletStatus` | `/profile`, `/profile/magic-wallet`, `/my-packages` | وضعیت کیف پول جادویی (Magic) | +| 4.4 | `WalletService.InitiateMagicChargeAsync` | `UserWalletContract.InitiateMagicCharge` | `/profile/magic-wallet` | شروع شارژ کیف پول جادویی → درگاه | +| 4.5 | `WalletService.VerifyMagicChargeAsync` | `UserWalletContract.VerifyMagicCharge` | `/profile/payment-callback?type=magic-wallet` | تأیید شارژ Magic پس از درگاه | +| 4.6 | `WalletService.InitiateDiscountChargeAsync` | `UserWalletContract.InitiateDiscountCharge` | `/profile/charge-discount-wallet` | شروع شارژ کیف پول تخفیفی → درگاه | +| 4.7 | `WalletService.VerifyDiscountChargeAsync` | `UserWalletContract.VerifyDiscountCharge` | `/profile/payment-callback?type=discount-wallet` | تأیید شارژ کیف تخفیفی | +| 4.8 | `WalletService.GetWithdrawalsAsync` | `UserWalletContract.GetCustomerWithdrawals` | `/profile/withdrawal-requests` | لیست درخواست‌های برداشت | +| 4.9 | `WalletService.GetWithdrawalSettingsAsync` | `UserWalletContract.GetCustomerWithdrawalSettings` | `/profile/withdrawal-requests` | حداقل مبلغ برداشت | +| 4.10 | `WalletService.RequestWithdrawalAsync` | `UserWalletContract.CustomerWithdrawBalance` | `/profile/withdrawal-requests` | ثبت درخواست برداشت پاداش (با payoutId کمیسیون) | +| 4.11 | `CommissionService.GetWithdrawablePayoutsAsync` | `CommissionContract.GetMyCommissionPayouts` | `/profile/withdrawal-requests` | پاداش‌های قابل برداشت برای انتخاب | + +--- + +## ۵. Callback پرداخت (مشترک) + +| # | سرویس / متد | gRPC Contract | صفحه / کامپوننت | کاربرد | +|---|-------------|---------------|-----------------|--------| +| 5.1 | `PackageContract.CustomerVerifyPackagePurchase` | `PackageContract` | `/profile/payment-callback` (type=package) | تأیید خرید پکیج | +| 5.2 | `WalletService.VerifyMagicChargeAsync` | `UserWalletContract` | `/profile/payment-callback` (type=magic-wallet) | تأیید شارژ Magic | +| 5.3 | `WalletService.VerifyDiscountChargeAsync` | `UserWalletContract` | `/profile/payment-callback` (type=discount-wallet) | تأیید شارژ تخفیفی | +| 5.4 | `DiscountOrderService.VerifyDiscountOrderPaymentAsync` | `DiscountOrderContract.CustomerVerifyDiscountOrderPayment` | `/profile/payment-callback` (type=discount-order) | تأیید پرداخت سفارش فروشگاه تخفیفی | +| 5.5 | `UserContract.GetUserForCustomer` + `AuthService.InitUserAuthInfo` | `UserContract` | `/profile/payment-callback` | به‌روزرسانی claims کاربر پس از پرداخت موفق | + +--- + +## ۶. فروشگاه اصلی (Store) + +| # | سرویس / متد | gRPC Contract | صفحه / کامپوننت | کاربرد | +|---|-------------|---------------|-----------------|--------| +| 6.1 | `ProductService.GetProductsPagedAsync` | `ProductsContract.GetProductsForCustomer` | `/products` | لیست محصولات با فیلتر/صفحه‌بندی | +| 6.2 | `ProductService.GetTopSellingAsync` | `ProductsContract` | `/` (صفحه اصلی) | پرفروش‌ترین محصولات | +| 6.3 | `ProductService.GetByIdAsync` | `ProductsContract.GetProductByIdForCustomer` | `/product/{id}` | جزئیات محصول + گالری | +| 6.4 | `CategoryService.GetAllAsync` / `GetByIdAsync` | `CategoryContract.GetAllCategoriesForCustomer` | `/categories`, `/products` | درخت دسته‌بندی محصولات | +| 6.5 | `CartService` — Add/Update/Remove/Get | `UserCartsContract.*ForCustomer` | `/`, `/products`, `/product/{id}`, `/cart` | مدیریت سبد خرید (AddNew, Update, Remove, GetCustomerCart) | +| 6.6 | `UserOrderContract.SubmitShopBuyOrder` | `UserOrderContract` | `/checkout-summary` | ثبت سفارش و پرداخت از کیف پول | +| 6.7 | `OrderService.GetOrdersAsync` | `UserOrderContract.GetCustomerOrders` | `/orders` | لیست سفارش‌های کاربر | +| 6.8 | `OrderService.GetOrderAsync` | `UserOrderContract.GetCustomerOrder` | `/order/{id}`, `/order-tracking/{id}` | جزئیات یک سفارش | +| 6.9 | `OrderService.CalculateOrderPVAsync` | `UserOrderContract.CalculateOrderPV` | `/order/{id}` | محاسبه PV سفارش | +| 6.10 | `VATService.GetRateAsync` | `UserOrderContract` (via scope) | Store/Discount صفحات قیمت | نرخ مالیات بر ارزش افزوده (کش روزانه) | +| 6.11 | `WalletService.GetBalancesAsync` | `UserWalletContract` | `/checkout-summary` | بررسی موجودی برای پرداخت سفارش | + +--- + +## ۷. فروشگاه تخفیفی (Discount Store) + +| # | سرویس / متد | gRPC Contract | صفحه / کامپوننت | کاربرد | +|---|-------------|---------------|-----------------|--------| +| 7.1 | `DiscountProductService.GetProductsAsync` | `DiscountProductContract.GetDiscountProducts` | `/discount-store` | لیست محصولات تخفیفی | +| 7.2 | `DiscountProductService.GetTopSellingAsync` | `DiscountProductContract` | `/` | پرفروش‌های فروشگاه تخفیفی | +| 7.3 | `DiscountProductService.GetByIdAsync` | `DiscountProductContract.GetDiscountProductById` + Images | `/discount-store/product/{id}` | جزئیات محصول تخفیفی | +| 7.4 | `DiscountProductService.GetCategoriesAsync` | `DiscountCategoryContract.GetDiscountCategories` | `/discount-store` | دسته‌بندی‌های فروشگاه تخفیفی | +| 7.5 | `DiscountCartService` — Add/Update/Remove/Get | `DiscountShoppingCartContract.*` | `/discount-store`, `/discount-store/cart` | سبد خرید تخفیفی | +| 7.6 | `DiscountOrderService.PlaceOrderAsync` | `DiscountOrderContract.PlaceOrder` | `/discount-store/checkout` | ثبت سفارش (کیف تخفیفی + درگاه) | +| 7.7 | `DiscountOrderService.GetUserOrdersAsync` | `DiscountOrderContract.GetUserOrders` | `/discount-store/orders` | لیست سفارش‌های تخفیفی | +| 7.8 | `DiscountOrderService.GetOrderByIdAsync` | `DiscountOrderContract.GetOrderById` | `/discount-store/order/{id}` | جزئیات سفارش تخفیفی | +| 7.9 | `UserAddressContract.GetCustomerAddresses` | `UserAddressContract` | `/discount-store/checkout` | انتخاب آدرس تحویل | + +--- + +## ۸. باشگاه مشتریان (Club) + +| # | سرویس / متد | gRPC Contract | صفحه / کامپوننت | کاربرد | +|---|-------------|---------------|-----------------|--------| +| 8.1 | `ClubMembershipService.GetMyMembershipAsync` | `ClubMembershipContract.GetClubMembership` | `/club/membership` | وضعیت عضویت باشگاه | +| 8.2 | `ClubConfigurationService.GetClubConfigurationAsync` | `ConfigurationContract.GetClubConfiguration` | `/club/membership` | هزینه فعال‌سازی و هدیه عضویت | +| 8.3 | `ClubConfigurationService.GetClubFeaturesAsync` | `ConfigurationContract.GetClubFeatures` | `/club/features` | لیست امکانات باشگاه | +| 8.4 | `ClubMembershipService.ActivateMembershipAsync` | `ClubMembershipContract.ActivateClubMembership` | `Club/ActivationSection` | فعال‌سازی/تمدید عضویت باشگاه | +| 8.5 | `OtpTokenContract.CreateNewOtpToken` | `OtpTokenContract` | `ClubMembershipContractDialog` | OTP برای امضای قرارداد باشگاه | +| 8.6 | `ClubMembershipContract.AcceptClubMembershipContract` | `ClubMembershipContract` | `ClubMembershipContractDialog` | ثبت امضای قرارداد باشگاه | + +--- + +## ۹. شبکه فروش (Network / MLM) + +| # | سرویس / متد | gRPC Contract | صفحه / کامپوننت | کاربرد | +|---|-------------|---------------|-----------------|--------| +| 9.1 | `NetworkMembershipService.GetMyNetworkTreeAsync` | `NetworkMembershipContract.GetMyNetworkTree` | `/profile/tree` (`OrganizationChart`) | درخت سازمان فروش کاربر | +| 9.2 | `NetworkMembershipService.GetSubordinateTreeAsync` | `NetworkMembershipContract.GetSubordinateTree` | `/profile/tree` | drill-down به زیرمجموعه | +| 9.3 | `NetworkMembershipService.GetMyNetworkStatisticsAsync` | `NetworkMembershipContract.GetMyNetworkStatistics` | `/profile/tree`, `/network/statistics` | آمار پا چپ/راست، تعداد اعضا | + +--- + +## ۱۰. کمیسیون و پاداش + +| # | سرویس / متد | gRPC Contract | صفحه / کامپوننت | کاربرد | +|---|-------------|---------------|-----------------|--------| +| 10.1 | `CommissionService.GetWeekDefinitionsAsync` | `CommissionContract.GetWeekDefinitions` | `Shared/WeekSelector`, Commission pages | لیست هفته‌های محاسبه پاداش | +| 10.2 | `CommissionService.GetMyCommissionPayoutsAsync` | `CommissionContract.GetMyCommissionPayouts` | `/commission/dashboard` | تاریخچه پرداخت پاداش‌ها | +| 10.3 | `CommissionService.GetMyWeeklyBalanceAsync` | `CommissionContract.GetMyWeeklyBalances` | `/commission/weekly-balance` | جزئیات بالانس هفتگی (چپ/راست) | +| 10.4 | `PackageService.GetAllPackagesAsync` | `PackageContract` | Commission pages | فیلتر پاداش بر اساس پکیج | + +--- + +## ۱۱. محتوای سایت، بلاگ و صفحات ثابت + +| # | سرویس / متد | gRPC Contract | صفحه / کامپوننت | کاربرد | +|---|-------------|---------------|-----------------|--------| +| 11.1 | `SitePageSettingsService.GetPageAsync` | `SitePageSettingsContract.GetPageSettings` | `/` (landing), `/about`, `/contact`, `/licenses` | محتوای داینامیک صفحات (hero، تصاویر، JSON تنظیمات) | +| 11.2 | `BlogPostService.GetFeaturedPostsAsync` | `BlogPostContract.GetFeaturedBlogPosts` | `/`, `/profile` | پست‌های ویژه | +| 11.3 | `BlogPostService.GetPublishedPostsAsync` | `BlogPostContract.GetPublishedBlogPosts` | `/`, `/blog` | لیست پست‌های منتشرشده | +| 11.4 | `BlogPostService.GetBySlugAsync` | `BlogPostContract.GetBlogPostBySlug` | `/blog/{slug}` | محتوای کامل یک پست | +| 11.5 | `BlogPostService.IncrementViewCountAsync` | `BlogPostContract.IncrementViewCount` | `/blog/{slug}` | افزایش شمارنده بازدید | +| 11.6 | `BlogCategoryService.GetActiveCategoriesAsync` | `BlogCategoryContract` | `/blog` | فیلتر دسته‌بندی بلاگ | +| 11.7 | FAQ | — (hardcoded) | `/faq` | سوالات متداول — **بدون فراخوانی API** | + +--- + +## ۱۲. زیرساخت مشترک (Infrastructure) + +| # | سرویس / متد | gRPC Contract | صفحه / کامپوننت | کاربرد | +|---|-------------|---------------|-----------------|--------| +| 12.1 | `ImageCacheService.ResolveAsync` | `ImageResolverContract` | `Shared/AppImage` (سراسری) | resolve مسیر تصویر CMS به data-URI | +| 12.2 | `AppVersionService.CheckVersionAsync` | `AppVersionContract` | `App.razor`, `MainLayout` | بررسی نسخه جدید اپ | +| 12.3 | `AppVersionService.ApplyUpdateAsync` / `SkipVersionAsync` | — (localStorage + reload) | `App.razor`, `MainLayout` | اعمال یا رد آپدیت | +| 12.4 | `MainService.OnChangeHandler` | — (in-memory) | `/`, `AuthDialog` | اطلاع‌رسانی تغییر state سراسری (مثلاً پس از login) | +| 12.5 | `IChromiumPdfService` | — (local endpoint `/contract/generate`) | `/register` | تولید PDF قرارداد (Chromium headless) | + +--- + +## ۱۳. Gateway / انتخاب‌گر + +| صفحه | سرویس | کاربرد | +|------|--------|--------| +| `/stores` | — | انتخاب بین فروشگاه اصلی و تخفیفی | +| `/my-orders` | — | انتخاب لیست سفارش‌ها | +| `/my-cart` | — | انتخاب سبد خرید | + +این صفحات فقط مسیریابی UI هستند و مستقیماً gRPC صدا نمی‌زنند. + +--- + +## ۱۴. سرویس‌های ثبت‌شده ولی بدون استفاده در UI + +| سرویس / Contract | وضعیت | +|------------------|--------| +| `SitePageService` (`SitePageContract`) | ثبت در DI؛ **هیچ صفحه‌ای inject نمی‌کند** (جایگزین: `SitePageSettingsService`) | +| `TransactionsContract` | ثبت در DI؛ **استفاده نشده** | +| `UserWalletHistoryContract` | ثبت در DI؛ **استفاده نشده** (تاریخچه از `UserWalletContract.GetCustomerWalletHistory` می‌آید) | +| `TokenNotificationService` | ثبت در DI؛ **هنوز به Layout وصل نشده** (SignalR برای invalidation توکن) | + +--- + +## نمودار جریان پرداخت + +```mermaid +flowchart LR + subgraph initiate [شروع پرداخت] + A1[Profile / Checkout] + A2[MagicWallet / ChargeDiscount] + A3[Discount Checkout] + end + + subgraph gateway [Zarinpal] + G[درگاه پرداخت] + end + + subgraph callback [PaymentCallback] + C1[Verify Package] + C2[Verify Magic] + C3[Verify Discount Wallet] + C4[Verify Discount Order] + end + + A1 --> G + A2 --> G + A3 --> G + G --> callback +``` + +--- + +## فهرست gRPC Contractهای فعال + +| Contract | Wrapper اصلی | +|----------|----------------| +| `UserContract` | `AuthService`, صفحات Profile/Register | +| `UserAddressContract` | Profile, Checkout pages | +| `CityContract` | Address dialogs | +| `PackageContract` | `PackageService`, PaymentCallback, Checkout | +| `UserWalletContract` | `WalletService` | +| `UserOrderContract` | `OrderService`, CheckoutSummary | +| `UserCartsContract` | `CartService` | +| `ProductsContract` | `ProductService` | +| `CategoryContract` | `CategoryService` | +| `DiscountProductContract` / `DiscountCategoryContract` | `DiscountProductService` | +| `DiscountShoppingCartContract` | `DiscountCartService` | +| `DiscountOrderContract` | `DiscountOrderService` | +| `ClubMembershipContract` | `ClubMembershipService`, Dialog | +| `OtpTokenContract` | Club contract dialog | +| `ConfigurationContract` | `ClubConfigurationService` | +| `NetworkMembershipContract` | `NetworkMembershipService` | +| `CommissionContract` | `CommissionService` | +| `BlogPostContract` | `BlogPostService` | +| `BlogCategoryContract` | `BlogCategoryService` | +| `SitePageSettingsContract` | `SitePageSettingsService` | +| `AppVersionContract` | `AppVersionService` | +| `ImageResolverContract` | `ImageCacheService` | diff --git a/src/FrontOffice.Main/FrontOffice.Main.csproj b/src/FrontOffice.Main/FrontOffice.Main.csproj index 0f7d095..a2e702d 100644 --- a/src/FrontOffice.Main/FrontOffice.Main.csproj +++ b/src/FrontOffice.Main/FrontOffice.Main.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/FrontOffice.Main/Utilities/NetworkMembershipDtos.cs b/src/FrontOffice.Main/Utilities/NetworkMembershipDtos.cs index 3b81991..8bbdb37 100644 --- a/src/FrontOffice.Main/Utilities/NetworkMembershipDtos.cs +++ b/src/FrontOffice.Main/Utilities/NetworkMembershipDtos.cs @@ -21,6 +21,11 @@ public class NetworkNodeDto /// کد معرف کاربر /// public string? ReferralCode { get; set; } + + /// + /// نام پکیج موثر (مثلاً پکیج طلایی / نقره‌ای) + /// + public string? PackageName { get; set; } } /// @@ -43,6 +48,11 @@ public class FlatNetworkNodeDto /// کد معرف کاربر - فقط برای کاربران فعال در باشگاه نمایش داده شود /// public string? ReferralCode { get; set; } + + /// + /// نام پکیج موثر (مثلاً پکیج طلایی / نقره‌ای) + /// + public string? PackageName { get; set; } } /// @@ -81,7 +91,8 @@ public class NetworkTreeDto IsClubActive = node.IsClubActive, ActivationWeekNumber = node.ActivationWeekNumber, JoinedAt = node.JoinedAt, - ReferralCode = node.ReferralCode + ReferralCode = node.ReferralCode, + PackageName = node.PackageName }; result.Add(flatNode); diff --git a/src/FrontOffice.Main/Utilities/NetworkMembershipService.cs b/src/FrontOffice.Main/Utilities/NetworkMembershipService.cs index f34c501..4983855 100644 --- a/src/FrontOffice.Main/Utilities/NetworkMembershipService.cs +++ b/src/FrontOffice.Main/Utilities/NetworkMembershipService.cs @@ -137,6 +137,7 @@ public class NetworkMembershipService IsActive = node.IsActive, IsClubActive = node.IsClubActive, ReferralCode = node.ReferralCode, + PackageName = string.IsNullOrWhiteSpace(node.PackageName) ? null : node.PackageName, ActivationWeekNumber = node.ActivationWeekDefinitionId?.ToString(), JoinedAt = node.JoinedAt?.ToDateTime(), LeftChild = MapNodeFromProto(node.LeftChild), diff --git a/src/FrontOffice.Main/wwwroot/css/org-chart.css b/src/FrontOffice.Main/wwwroot/css/org-chart.css index c361e0c..4ac39ab 100644 --- a/src/FrontOffice.Main/wwwroot/css/org-chart.css +++ b/src/FrontOffice.Main/wwwroot/css/org-chart.css @@ -124,6 +124,23 @@ margin-top: 1px; } +.org-node-card .package-name-badge { + display: inline-flex; + align-items: center; + height: 14px; + padding: 0 6px; + margin-top: 2px; + border-radius: 7px; + font-size: 9px; + color: #546e7a; + background: #eceff1; + border: 1px solid #b0bec5; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 120px; +} + /* Referral Code - only for club active members */ .node-referral { display: flex; diff --git a/src/FrontOffice.Main/wwwroot/js/org-chart.js b/src/FrontOffice.Main/wwwroot/js/org-chart.js index 454862b..0de2b93 100644 --- a/src/FrontOffice.Main/wwwroot/js/org-chart.js +++ b/src/FrontOffice.Main/wwwroot/js/org-chart.js @@ -38,7 +38,7 @@ window.OrgChart = { .container('#' + containerId) .data(data) .nodeWidth((d) => 140) - .nodeHeight((d) => 70) + .nodeHeight((d) => 85) .childrenMargin((d) => 50) .compactMarginBetween((d) => 15) .compactMarginPair((d) => 15) @@ -66,6 +66,11 @@ window.OrgChart = { // Avatar - first letter of name const firstChar = data.fullName ? data.fullName.charAt(0) : '?'; + + const packageName = data.packageName || data.PackageName || ''; + const packageBadge = packageName + ? `
${packageName}
` + : ''; // نمایش کد معرف فقط برای کاربران فعال در باشگاه const referralCodeHtml = data.isClubActive && data.referralCode @@ -82,6 +87,7 @@ window.OrgChart = {
${data.fullName || 'بدون نام'}
L${data.level || 0}${!isRoot ? ' • ' + (data.position === 'Left' ? 'چپ' : 'راست') : ''}
+ ${packageBadge} ${referralCodeHtml}
From 8080b75f0599018602646b5bb035ec9133f85f8d Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Sun, 14 Jun 2026 00:08:23 +0330 Subject: [PATCH 2/4] fix(k8s): change imagePullPolicy to IfNotPresent in frontoffice-deployment.yaml Updated the imagePullPolicy for the frontoffice container to IfNotPresent to optimize image pulling behavior, ensuring that images are only pulled when not already present on the node. --- k8s/staging/frontoffice-deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/k8s/staging/frontoffice-deployment.yaml b/k8s/staging/frontoffice-deployment.yaml index 989e9a2..cc82fd4 100644 --- a/k8s/staging/frontoffice-deployment.yaml +++ b/k8s/staging/frontoffice-deployment.yaml @@ -21,7 +21,7 @@ spec: containers: - name: frontoffice image: 194.5.195.53:30080/admin/frontoffice:latest - imagePullPolicy: Always + imagePullPolicy: IfNotPresent ports: - containerPort: 80 name: http From 8766c29a5a5c6d64c7619877e887174b8b7db28d Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Fri, 19 Jun 2026 00:13:02 +0330 Subject: [PATCH 3/4] fix(k8s): update imagePullPolicy to Always in frontoffice-deployment.yaml Changed the imagePullPolicy for the frontoffice container to Always to ensure that the latest image is always pulled from the registry during deployment, improving the consistency of the application updates. Additionally, added a cleanup step in the kub-deploy workflow to remove the latest image from the local cache after deployment. --- .gitea/workflows/kub-deploy.yml | 1 + k8s/staging/frontoffice-deployment.yaml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/kub-deploy.yml b/.gitea/workflows/kub-deploy.yml index 4f58900..7084740 100644 --- a/.gitea/workflows/kub-deploy.yml +++ b/.gitea/workflows/kub-deploy.yml @@ -74,6 +74,7 @@ jobs: # Apply manifests and restart sshpass -e ssh -o StrictHostKeyChecking=no root@${{ env.K8S_SERVER }} " kubectl apply -f /tmp/frontoffice-deployment.yaml && + crictl rmi ${REGISTRY}/${IMAGE_NAME}:latest 2>/dev/null || true && kubectl rollout restart deployment/frontoffice && kubectl rollout status deployment/frontoffice --timeout=180s && rm -f /tmp/frontoffice-deployment.yaml diff --git a/k8s/staging/frontoffice-deployment.yaml b/k8s/staging/frontoffice-deployment.yaml index cc82fd4..989e9a2 100644 --- a/k8s/staging/frontoffice-deployment.yaml +++ b/k8s/staging/frontoffice-deployment.yaml @@ -21,7 +21,7 @@ spec: containers: - name: frontoffice image: 194.5.195.53:30080/admin/frontoffice:latest - imagePullPolicy: IfNotPresent + imagePullPolicy: Always ports: - containerPort: 80 name: http From 7f8f99d4eb949d7d97f7e86997cb930a30ad0906 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Fri, 19 Jun 2026 01:56:54 +0330 Subject: [PATCH 4/4] feat: enhance organization chart data mapping for improved clarity Updated the organization chart component to explicitly map network node properties to a flat array with camelCase keys. This change aligns the data structure with the BackOffice admin chart, enhancing consistency and clarity in the displayed information. --- .../Components/OrganizationChart.razor.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/FrontOffice.Main/Pages/Profile/Components/OrganizationChart.razor.cs b/src/FrontOffice.Main/Pages/Profile/Components/OrganizationChart.razor.cs index a7ab481..2603f3f 100644 --- a/src/FrontOffice.Main/Pages/Profile/Components/OrganizationChart.razor.cs +++ b/src/FrontOffice.Main/Pages/Profile/Components/OrganizationChart.razor.cs @@ -95,7 +95,23 @@ public partial class OrganizationChart : IAsyncDisposable try { _dotNetHelper = DotNetObjectReference.Create(this); - var flatData = _networkTree.ToFlatArray(); + // Explicit camelCase mapping (same pattern as BackOffice admin chart) + var flatData = _networkTree.ToFlatArray().Select(n => new + { + id = n.Id, + parentId = n.ParentId, + fullName = n.FullName, + mobile = n.Mobile, + avatar = n.Avatar, + position = n.Position, + level = n.Level, + isActive = n.IsActive, + isClubActive = n.IsClubActive, + activationWeekNumber = n.ActivationWeekNumber, + joinedAt = n.JoinedAt, + referralCode = n.ReferralCode, + packageName = n.PackageName ?? string.Empty + }).ToArray(); await JSRuntime.InvokeVoidAsync("OrgChart.init", "org-chart-container", flatData, _dotNetHelper); }