@@ -142,4 +142,12 @@ export const accountApi = { return null } }, + + revokeRecurringPayment(token: string) { + return axios.post(getApiUrl() + '/payments/revoke-recurring-payment', {}, { + headers: { + Authorization: `Bearer ${token}`, + }, + }) + }, } @@ -1,6 +1,7 @@ import { FC, ReactNode } from 'react' import { Box } from '@mui/material' import Dialog from '@mui/material/Dialog' +import type { SxProps, Theme } from '@mui/material/styles' import Image from 'next/image' import styles from './modal.module.scss' @@ -8,21 +9,29 @@ export interface ModalProps { open: boolean onClose: (e?: any) => void children?: ReactNode + /** Доп. стили для Paper — например minWidth на десктопе */ + paperSx?: SxProps } -export const Modal: FC = ({ open, onClose, children }) => { +export const Modal: FC = ({ open, onClose, children, paperSx }) => { + const isWide = Boolean(paperSx) return ( { - const [isModalOpen, setIsModalOpen] = useState(false) - - const handleOpenModal = () => { - setIsModalOpen(true) - } - - const handleCloseModal = () => { - setIsModalOpen(false) - } - - const handleCancelSubscription = () => { - // Здесь будет логика отмены подписки - handleCloseModal() - } - - return ( - <> - - - - - - - Отмена подписки - - - - Внимание! Вы отменяете подписку на тариф 10 000 токенов. Следующее списание будет отменено, вы можете продолжать пользоваться возможностями тарифа до истечения его срока. - - - - - - - - - ) -} \ No newline at end of file @@ -1,6 +1,7 @@ import { Box, LinearProgress, linearProgressClasses, Stack, styled, Typography } from '@mui/material' import { commaSeparated } from '#/shared' +import { formatDate } from '#/shared/lib/helpers/date-helper' import { formatPlanPrice } from '#/shared/lib/helpers/format-plan-price' import { declineToken } from '#/shared/lib/helpers/get-token' @@ -23,10 +24,25 @@ interface CurrentPlanAndBalanceProps { planTokenLimit: string planPrice: string isIndividual: boolean + nextPaymentAt?: string | null } -export const CurrentPlanAndBalance = ({ balance, planTokenLimit, planPrice, isIndividual }: CurrentPlanAndBalanceProps) => { +function formatNextPaymentLabel(iso: string | null | undefined): string | null { + if (!iso?.trim()) return null + const d = new Date(iso) + if (Number.isNaN(d.getTime())) return null + return formatDate(d, { day: '2-digit', month: '2-digit', year: 'numeric' }) +} + +export const CurrentPlanAndBalance = ({ + balance, + planTokenLimit, + planPrice, + isIndividual, + nextPaymentAt, +}: CurrentPlanAndBalanceProps) => { const formatterdPlanPrice = formatPlanPrice(planPrice, isIndividual) + const nextPaymentFormatted = formatNextPaymentLabel(nextPaymentAt) const planTokenLimitNumber = Number(planTokenLimit) const percentage = planTokenLimitNumber > 0 ? Math.min(100, Math.max(0, (balance / planTokenLimitNumber) * 100)) : 0 @@ -45,6 +61,11 @@ export const CurrentPlanAndBalance = ({ balance, planTokenLimit, planPrice, isIn {formatterdPlanPrice} + {nextPaymentFormatted ? ( + + Следующее списание: {nextPaymentFormatted} + + ) : null} @@ -18,7 +18,7 @@ export const FeaturesSection = ({ currentTokenLimitUID, onCurrentTokenLimitUIDCh return ( - + Возможности с подпиской