From da3736e13176629b587f0e431a12f57ec0bd26c7 Mon Sep 17 00:00:00 2001 From: Dev Server Date: Mon, 9 Mar 2026 17:48:54 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20nav=20sidebar=20user=20card=20=E2=80=94?= =?UTF-8?q?=20real=20data=20+=20subscription=20info?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Show real avatar, full name, email from useAuthContext - Fetch GET /subscriptions/subscriptions/active/ on mount - Display subscription plan name (label: success=active, warning=trial, default=none) - Show end date + days left text - LinearProgress bar showing days remaining (red <20%, yellow <50%, green otherwise) - Trial subscription displayed as 'Пробный: ' Co-Authored-By: Claude Sonnet 4.6 --- .../src/layouts/components/nav-upgrade.jsx | 232 ++++++++++-------- 1 file changed, 129 insertions(+), 103 deletions(-) diff --git a/front_minimal/src/layouts/components/nav-upgrade.jsx b/front_minimal/src/layouts/components/nav-upgrade.jsx index f4ce454..30f7d49 100644 --- a/front_minimal/src/layouts/components/nav-upgrade.jsx +++ b/front_minimal/src/layouts/components/nav-upgrade.jsx @@ -1,141 +1,167 @@ -import { m } from 'framer-motion'; +import { useState, useEffect } from 'react'; import Box from '@mui/material/Box'; import Stack from '@mui/material/Stack'; -import Button from '@mui/material/Button'; import Avatar from '@mui/material/Avatar'; +import Tooltip from '@mui/material/Tooltip'; import Typography from '@mui/material/Typography'; -import { alpha as hexAlpha } from '@mui/material/styles'; - -import { paths } from 'src/routes/paths'; +import LinearProgress from '@mui/material/LinearProgress'; import { CONFIG } from 'src/config-global'; -import { varAlpha, bgGradient } from 'src/theme/styles'; +import { useAuthContext } from 'src/auth/hooks'; import { Label } from 'src/components/label'; -import { useMockedUser } from 'src/auth/hooks'; +// ---------------------------------------------------------------------- + +async function fetchActiveSubscription() { + try { + const token = + localStorage.getItem('jwt_access_token') || localStorage.getItem('access_token') || ''; + const base = (CONFIG.site.serverUrl || '').replace(/\/+$/, ''); + const res = await fetch(`${base}/subscriptions/subscriptions/active/`, { + headers: { Authorization: `Bearer ${token}` }, + }); + if (!res.ok) return null; + return await res.json(); + } catch { + return null; + } +} // ---------------------------------------------------------------------- export function NavUpgrade({ sx, ...other }) { - const { user } = useMockedUser(); + const { user } = useAuthContext(); + const [sub, setSub] = useState(undefined); // undefined = loading, null = no sub + + useEffect(() => { + if (!user) return; + fetchActiveSubscription().then(setSub); + }, [user]); + + const displayName = user + ? `${user.first_name || ''} ${user.last_name || ''}`.trim() || user.email + : ''; + + const initials = user + ? [user.first_name?.[0], user.last_name?.[0]].filter(Boolean).join('').toUpperCase() || + (user.email?.[0] || '?').toUpperCase() + : '?'; + + const avatarSrc = user?.avatar + ? user.avatar.startsWith('http') + ? user.avatar + : `${(CONFIG.site.serverUrl || '').replace(/\/api\/?$/, '')}${user.avatar}` + : null; + + // Subscription label + let labelColor = 'default'; + let labelText = 'Нет подписки'; + + if (sub === undefined) { + labelText = '…'; + } else if (sub && sub.is_active_now) { + const planName = sub.plan?.name || 'Подписка'; + const status = sub.status; + labelText = status === 'trial' ? `Пробный: ${planName}` : planName; + labelColor = status === 'trial' ? 'warning' : 'success'; + } + + // End date display + let endDateText = null; + if (sub && sub.is_active_now) { + const endField = sub.status === 'trial' ? sub.trial_end_date : sub.end_date; + if (endField) { + const date = new Date(endField); + endDateText = `до ${date.toLocaleDateString('ru-RU', { day: 'numeric', month: 'short', year: 'numeric' })}`; + } + if (sub.days_left !== undefined && sub.days_left !== null) { + endDateText = endDateText ? `${endDateText} (${sub.days_left} дн.)` : `${sub.days_left} дн.`; + } + } + + // Progress bar for days left (out of 30) + const daysProgress = + sub?.days_left != null && sub?.is_active_now + ? Math.min(100, Math.round((sub.days_left / 30) * 100)) + : null; return ( - - - - - {user?.displayName?.charAt(0).toUpperCase()} - - - + {initials} + - + - {user?.displayName} + {displayName || '—'} - - {user?.email} + {user?.email || ''} + + + + {/* Subscription badge */} + + + + {endDateText && ( + + {endDateText} + + )} - + {daysProgress !== null && ( + + + + )} ); } // ---------------------------------------------------------------------- - +// UpgradeBlock — оставляем для совместимости, больше не используется в платформе export function UpgradeBlock({ sx, ...other }) { - return ( - - `solid 3px ${varAlpha(theme.vars.palette.common.whiteChannel, 0.16)}`, - }} - /> - - - - - - 35% OFF - - - - Power up Productivity! - - - - - - ); + return ; }