From f1d58e16044af54f87f477829752ea5aa65afe69 Mon Sep 17 00:00:00 2001 From: hamed <15238-genius.ha@users.noreply.drupalcode.org> Date: Sat, 18 Jul 2026 11:05:47 +0330 Subject: [PATCH] feat(subscription): display jalali expiry date and handle no expiry case in current plan card --- assets/admin/pages/SubscriptionPage.test.tsx | 23 +++++++++++++++++++- assets/admin/pages/SubscriptionPage.tsx | 20 +++++++++++++++-- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/assets/admin/pages/SubscriptionPage.test.tsx b/assets/admin/pages/SubscriptionPage.test.tsx index 5e56849d..b0dd02ce 100644 --- a/assets/admin/pages/SubscriptionPage.test.tsx +++ b/assets/admin/pages/SubscriptionPage.test.tsx @@ -1,7 +1,7 @@ import { describe, it, expect, beforeEach, vi } from 'vitest'; import { screen, fireEvent, within } from '@testing-library/react'; import { renderWithProviders } from '../test/utils'; -import { formatRial } from '../lib/utils'; +import { formatRial, formatDate } from '../lib/utils'; vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn() } })); vi.mock('../lib/api', () => ({ @@ -67,6 +67,27 @@ describe('SubscriptionPage', () => { expect(await screen.findByText(/روز تا پایان اشتراک/)).toBeInTheDocument(); }); + it('shows the jalali expiry date on the current-plan card', async () => { + // 1767225600 = 2026-01-01T00:00:00Z → ۱۴۰۴/۱۰/۱۱ in Tehran + mockApi({ my: { ...DEFAULT_MY, subscription: { ...DEFAULT_MY.subscription, expires_at: 1767225600 } } }); + renderWithProviders(, { route: '/admin/subscription' }); + + expect(await screen.findByText('زمان پایان اشتراک:')).toBeInTheDocument(); + expect(screen.getByText(formatDate(1767225600))).toBeInTheDocument(); + expect(screen.getByText(/روز مانده/)).toBeInTheDocument(); + }); + + it('falls back to «بدون تاریخ انقضا» when the subscription has no expiry', async () => { + renderWithProviders(, { route: '/admin/subscription' }); + expect(await screen.findByText('بدون تاریخ انقضا')).toBeInTheDocument(); + }); + + it('renders the current-plan card right-to-left', async () => { + renderWithProviders(, { route: '/admin/subscription' }); + const label = await screen.findByText('پلن فعلی شما:'); + expect(label.closest('[dir]')).toHaveAttribute('dir', 'rtl'); + }); + it('shows the expired message when no days remain', async () => { mockApi({ my: { ...DEFAULT_MY, subscription: { ...DEFAULT_MY.subscription, days_remaining: 0 } } }); renderWithProviders(, { route: '/admin/subscription' }); diff --git a/assets/admin/pages/SubscriptionPage.tsx b/assets/admin/pages/SubscriptionPage.tsx index 4ba11c44..b9ae8104 100644 --- a/assets/admin/pages/SubscriptionPage.tsx +++ b/assets/admin/pages/SubscriptionPage.tsx @@ -7,7 +7,7 @@ import { api } from '../lib/api'; import type { ApiResponse } from '../lib/api'; import type { SubscriptionPlan, MySubscriptionData, SubscriptionPeriod } from '../types'; import { usePaymentConfig } from '../hooks/usePaymentConfig'; -import { formatRial, formatNumber } from '../lib/utils'; +import { formatRial, formatNumber, formatDate } from '../lib/utils'; import Modal from '../components/ui/Modal'; import SettingsLayout from '../components/layout/SettingsLayout'; import { @@ -270,9 +270,10 @@ export default function SubscriptionPage() { function CurrentPlanCard({ my, onRenew }: { my: MySubscriptionData['subscription']; onRenew: () => void }) { const daysLeft = my?.days_remaining ?? 0; + const expiresAt = my?.expires_at ?? null; return (
پلن فعلی شما: {planMetaOf(my.plan.name).label}
+ {expiresAt ? ( +
+ زمان پایان اشتراک: + {formatDate(expiresAt)} + {daysLeft > 0 && ( + + ({formatNumber(daysLeft)} روز مانده) + + )} +
+ ) : ( +
+ بدون تاریخ انقضا +
+ )} {daysLeft < 3 && (