From 34c5c508e0e0a85c705a5a86f9461df647e87585 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Thu, 11 Jun 2026 23:33:40 +0330 Subject: [PATCH] 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}