diff --git a/src/App.tsx b/src/App.tsx index 26e0dad..404dc99 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -37,6 +37,8 @@ const Info = lazy(() => import('./pages/Info')); const Wheel = lazy(() => import('./pages/Wheel')); const Connection = lazy(() => import('./pages/Connection')); const ConnectionQR = lazy(() => import('./pages/ConnectionQR')); +const QuickPurchase = lazy(() => import('./pages/QuickPurchase')); +const PurchaseSuccess = lazy(() => import('./pages/PurchaseSuccess')); const TopUpMethodSelect = lazy(() => import('./pages/TopUpMethodSelect')); const TopUpAmount = lazy(() => import('./pages/TopUpAmount')); const ConnectedAccounts = lazy(() => import('./pages/ConnectedAccounts')); @@ -104,6 +106,8 @@ const AdminRoleAssign = lazy(() => import('./pages/AdminRoleAssign')); const AdminPolicies = lazy(() => import('./pages/AdminPolicies')); const AdminPolicyEdit = lazy(() => import('./pages/AdminPolicyEdit')); const AdminAuditLog = lazy(() => import('./pages/AdminAuditLog')); +const AdminLandings = lazy(() => import('./pages/AdminLandings')); +const AdminLandingEditor = lazy(() => import('./pages/AdminLandingEditor')); function ProtectedRoute({ children }: { children: React.ReactNode }) { const isAuthenticated = useAuthStore((state) => state.isAuthenticated); @@ -194,6 +198,22 @@ function App() { } /> + + + + } + /> + + + + } + /> {/* Protected routes */} } /> + + + + + + } + /> + + + + + + } + /> + + + + + + } + /> ; + payment_methods: LandingPaymentMethod[]; + gift_enabled: boolean; + custom_css: string | null; + meta_title: string | null; + meta_description: string | null; + display_order: number; + created_at: string | null; + updated_at: string | null; +} + +export interface LandingCreateRequest { + slug: string; + title: string; + subtitle?: string; + is_active?: boolean; + features?: LandingFeature[]; + footer_text?: string; + allowed_tariff_ids?: number[]; + allowed_periods?: Record; + payment_methods?: LandingPaymentMethod[]; + gift_enabled?: boolean; + custom_css?: string; + meta_title?: string; + meta_description?: string; +} + +export type LandingUpdateRequest = Partial; + +// ============================================================ +// Public API +// ============================================================ + +export const landingApi = { + getConfig: async (slug: string): Promise => { + const response = await apiClient.get(`/cabinet/landing/${slug}`); + return response.data; + }, + + createPurchase: async (slug: string, data: PurchaseRequest): Promise => { + const response = await apiClient.post(`/cabinet/landing/${slug}/purchase`, data); + return response.data; + }, + + getPurchaseStatus: async (token: string): Promise => { + const response = await apiClient.get(`/cabinet/landing/purchase/${token}`); + return response.data; + }, +}; + +// ============================================================ +// Admin API +// ============================================================ + +export const adminLandingsApi = { + list: async (): Promise => { + const response = await apiClient.get('/cabinet/admin/landings'); + return response.data; + }, + + get: async (id: number): Promise => { + const response = await apiClient.get(`/cabinet/admin/landings/${id}`); + return response.data; + }, + + create: async (data: LandingCreateRequest): Promise => { + const response = await apiClient.post('/cabinet/admin/landings', data); + return response.data; + }, + + update: async (id: number, data: LandingUpdateRequest): Promise => { + const response = await apiClient.put(`/cabinet/admin/landings/${id}`, data); + return response.data; + }, + + delete: async (id: number): Promise<{ message: string }> => { + const response = await apiClient.delete(`/cabinet/admin/landings/${id}`); + return response.data; + }, + + toggle: async (id: number): Promise<{ id: number; is_active: boolean; message: string }> => { + const response = await apiClient.post(`/cabinet/admin/landings/${id}/toggle`); + return response.data; + }, + + reorder: async (landingIds: number[]): Promise => { + await apiClient.put('/cabinet/admin/landings/order', { landing_ids: landingIds }); + }, +}; diff --git a/src/components/dashboard/SubscriptionCardActive.tsx b/src/components/dashboard/SubscriptionCardActive.tsx index e290930..64b487e 100644 --- a/src/components/dashboard/SubscriptionCardActive.tsx +++ b/src/components/dashboard/SubscriptionCardActive.tsx @@ -236,15 +236,24 @@ export default function SubscriptionCardActive({ {t('dashboard.connectDevice')}
- {t('dashboard.devicesOfMax', { - used: connectedDevices, - max: subscription.device_limit, - })} + {subscription.device_limit === 0 + ? t('dashboard.devicesConnectedUnlimited', { used: connectedDevices }) + : t('dashboard.devicesOfMax', { + used: connectedDevices, + max: subscription.device_limit, + })}
{/* Device indicator */} - {subscription.device_limit <= 10 ? ( + {subscription.device_limit === 0 ? ( + + ) : subscription.device_limit <= 10 ? (