diff --git a/txclient/src/app/landing/current-plan/page.module.css b/txclient/src/app/landing/current-plan/page.module.css index 73ea6fb..ad0d6eb 100644 --- a/txclient/src/app/landing/current-plan/page.module.css +++ b/txclient/src/app/landing/current-plan/page.module.css @@ -128,8 +128,7 @@ box-shadow: 0 18px 34px color-mix(in srgb, var(--black-dark) 14%, transparent); } -.summaryGrid, -.limitsGrid { +.summaryGrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 14px; @@ -199,8 +198,7 @@ white-space: nowrap; } -.summaryItem, -.limitItem { +.summaryItem { position: relative; overflow: hidden; background: var(--white); @@ -211,15 +209,13 @@ transition: transform 180ms ease, box-shadow 180ms ease, border-color 180ms ease; } -.summaryItem:hover, -.limitItem:hover { +.summaryItem:hover { transform: translateY(-2px); border-color: var(--wine-lighter); box-shadow: 0 18px 34px color-mix(in srgb, var(--wine-darkest) 12%, transparent); } -.summaryItem::before, -.limitItem::before { +.summaryItem::before { content: ""; position: absolute; inset: 0 auto 0 0; @@ -227,8 +223,7 @@ background: linear-gradient(180deg, var(--wine-red), var(--wine-dark)); } -.summaryItem span, -.limitItem span { +.summaryItem span { display: block; margin-bottom: 9px; color: var(--gray-dark); @@ -238,16 +233,14 @@ letter-spacing: 0.08em; } -.summaryItem strong, -.limitItem strong { +.summaryItem strong { display: block; color: var(--black); font-size: 24px; line-height: 1.1; } -.summaryItem small, -.limitItem small { +.summaryItem small { display: block; margin-top: 9px; color: var(--gray-darkest); @@ -306,10 +299,31 @@ letter-spacing: -0.03em; } -.features { +.featuresPanel { display: grid; - grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); - gap: 12px; + grid-template-columns: minmax(180px, 0.45fr) minmax(0, 1fr); + gap: clamp(16px, 3vw, 28px); + align-items: start; + padding: clamp(18px, 3vw, 24px); + border: 1px solid var(--wine-lighterX2); + border-radius: 22px; + background: + radial-gradient(circle at 0% 0%, var(--wine-lighterX2), transparent 30%), + linear-gradient(135deg, var(--white) 0%, var(--white-dark) 100%); +} + +.featuresPanel p { + margin: 0; + color: var(--gray-dark); + font-size: 15px; + font-weight: 700; + line-height: 1.55; +} + +.features { + display: flex; + flex-wrap: wrap; + gap: 10px; margin: 0; padding: 0; list-style: none; @@ -317,57 +331,87 @@ .features li { position: relative; - overflow: hidden; display: flex; align-items: center; - gap: 12px; - min-height: 68px; - padding: 14px 16px 14px 54px; - border: 1px solid var(--wine-lighterX2); - border-radius: 18px; - background: - radial-gradient(circle at 100% 0%, var(--wine-lighterX2), transparent 34%), - linear-gradient(135deg, var(--white) 0%, var(--white-dark) 100%); + gap: 8px; + padding: 9px 12px; + border: 1px solid var(--white-darkest); + border-radius: 999px; + background: color-mix(in srgb, var(--white) 78%, var(--wine-lighterX2)); color: var(--black); - font-size: 14px; + font-size: 13px; font-weight: 800; line-height: 1.25; - box-shadow: 0 12px 28px color-mix(in srgb, var(--wine-darkest) 8%, transparent); - transition: transform 180ms ease, box-shadow 180ms ease, border-color 180ms ease; } .features li::before { content: "✓"; - position: absolute; - left: 16px; - top: 50%; - transform: translateY(-50%); display: grid; place-items: center; - width: 26px; - height: 26px; + flex: 0 0 auto; + width: 18px; + height: 18px; border-radius: 999px; - background: linear-gradient(135deg, var(--wine-red), var(--wine-dark)); - color: var(--white); + background: var(--wine-lighterX2); + color: var(--wine-red); + font-size: 12px; + font-weight: 900; +} + +.limitsPanel { + overflow: hidden; + border: 1px solid var(--white-darkest); + border-radius: 22px; + background: var(--white); + box-shadow: 0 14px 36px color-mix(in srgb, var(--wine-darkest) 8%, transparent); +} + +.limitRow { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 16px; + align-items: center; + padding: 16px 18px; + border-bottom: 1px solid var(--white-darkest); +} + +.limitRow:last-child { + border-bottom: 0; +} + +.limitRow span { + display: block; + color: var(--black); font-size: 15px; font-weight: 900; - box-shadow: 0 8px 18px color-mix(in srgb, var(--wine-darkest) 18%, transparent); } -.features li::after { - content: ""; - position: absolute; - inset: auto 14px 10px 54px; - height: 3px; - border-radius: 999px; - background: linear-gradient(90deg, var(--wine-red), var(--wine-lighter)); - opacity: 0.45; +.limitRow small { + display: block; + margin-top: 4px; + color: var(--gray-dark); + font-size: 13px; + font-weight: 700; } -.features li:hover { - transform: translateY(-2px); - border-color: var(--wine-lighter); - box-shadow: 0 18px 34px color-mix(in srgb, var(--wine-darkest) 12%, transparent); +.limitValues { + min-width: 116px; + padding: 10px 12px; + border-radius: 16px; + background: var(--white-dark); + text-align: right; +} + +.limitValues strong { + display: block; + color: var(--wine-red); + font-size: 24px; + line-height: 1; +} + +.limitValues small { + margin-top: 6px; + color: var(--gray-darkest); } .message { @@ -380,6 +424,7 @@ position: relative; overflow: hidden; display: grid; + width: 100%; grid-template-columns: minmax(190px, 0.8fr) minmax(0, 1.2fr); gap: 18px; align-items: stretch; @@ -390,6 +435,15 @@ radial-gradient(circle at 8% 20%, var(--yellow-light), transparent 30%), linear-gradient(135deg, var(--wine-superdark) 0%, var(--wine-darkest) 45%, var(--wine-dark) 100%); box-shadow: 0 18px 42px color-mix(in srgb, var(--wine-darkest) 16%, transparent); + color: inherit; + font: inherit; + text-align: left; + cursor: pointer; +} + +.usageShowcase:focus-visible { + outline: 3px solid var(--yellow); + outline-offset: 3px; } .usageShowcase::after { @@ -434,6 +488,17 @@ letter-spacing: -0.04em; } +.usageIntro small { + width: fit-content; + margin-top: 4px; + padding: 7px 11px; + border-radius: 999px; + background: color-mix(in srgb, var(--white) 14%, transparent); + color: var(--white); + font-size: 13px; + font-weight: 900; +} + .usageStats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); @@ -521,10 +586,20 @@ } .usageShowcase, - .usageStats { + .usageStats, + .featuresPanel { grid-template-columns: 1fr; } + .limitRow { + grid-template-columns: 1fr; + } + + .limitValues { + width: 100%; + text-align: left; + } + .usageStat { min-height: 104px; } diff --git a/txclient/src/app/landing/current-plan/page.tsx b/txclient/src/app/landing/current-plan/page.tsx index a437eff..5464768 100644 --- a/txclient/src/app/landing/current-plan/page.tsx +++ b/txclient/src/app/landing/current-plan/page.tsx @@ -23,6 +23,21 @@ import styles from "./page.module.css"; const formatLimit = (value: number) => (value === -1 ? "Ilimitado" : value.toString()); +const getLimitDetail = (limit: number, current?: number) => { + if (limit === -1) return "Sin tope definido"; + if (typeof current !== "number") return "Tope disponible"; + + const available = Math.max(limit - current, 0); + return `${available} disponibles`; +}; + +const getLimitValue = (limit: number, current?: number) => (typeof current === "number" ? current.toString() : formatLimit(limit)); + +const getLimitCaption = (limit: number, current?: number) => { + if (typeof current !== "number") return limit === -1 ? "sin tope" : "límite total"; + return `de ${formatLimit(limit)}`; +}; + const formatDate = (date?: Date) => (date ? dayjs(date).format("DD/MM/YYYY") : "No disponible"); const getLimitCards = (plan: ISubscriptionInfo["plan"], metrics: DashboardMetrics | null) => [ @@ -45,6 +60,7 @@ export default function CurrentPlanPage() { const [isOwner, setIsOwner] = useState(false); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); + const [isCapacityExpanded, setIsCapacityExpanded] = useState(false); useEffect(() => { if (!SessionInfo.userId) { @@ -212,9 +228,12 @@ export default function CurrentPlanPage() {
Un resumen rápido de los beneficios incluidos para operar tu organización.
+Este plan no tiene características cargadas.
)} @@ -223,22 +242,21 @@ export default function CurrentPlanPage() {