first commit
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
"use client";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import classNames from "classnames";
|
||||
import styles from "./PlanMetricsWidget.module.css";
|
||||
import { ISubscriptionInfo } from "@core/Models/Subscription.Model";
|
||||
import StorefrontOutlinedIcon from "@mui/icons-material/StorefrontOutlined";
|
||||
import PeopleOutlineOutlinedIcon from "@mui/icons-material/PeopleOutlineOutlined";
|
||||
import CalendarTodayOutlinedIcon from "@mui/icons-material/CalendarTodayOutlined";
|
||||
import AssignmentIndOutlinedIcon from "@mui/icons-material/AssignmentIndOutlined";
|
||||
import RepeatOutlinedIcon from "@mui/icons-material/RepeatOutlined";
|
||||
import Button from "@core/app/components/Button/Button";
|
||||
import { MP_SUBS_STATUS } from "@core/Models/Subscription.Model";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
export interface PlanMetricsWidgetProps {
|
||||
subscription: ISubscriptionInfo;
|
||||
metrics: {
|
||||
organizationsCount: number;
|
||||
employeesCount: number;
|
||||
clientsCount: number;
|
||||
appointmentsCount: number;
|
||||
servicesCount: number;
|
||||
repeatsCount: number;
|
||||
};
|
||||
onUpgrade: () => void;
|
||||
onRenew?: () => void;
|
||||
onCancel: () => void;
|
||||
isOwner?: boolean;
|
||||
}
|
||||
|
||||
const MetricRow = ({
|
||||
icon,
|
||||
title,
|
||||
value,
|
||||
maxValue,
|
||||
}: {
|
||||
icon: React.ReactNode;
|
||||
title: string;
|
||||
value: number;
|
||||
maxValue: number;
|
||||
}) => {
|
||||
const [animatedWidth, setAnimatedWidth] = useState(0);
|
||||
|
||||
const isInfinite = maxValue === -1;
|
||||
const formattedMax = isInfinite ? "∞" : maxValue;
|
||||
const percentage = isInfinite ? 100 : Math.min(100, (value / maxValue) * 100);
|
||||
|
||||
let statusClass = styles.safe;
|
||||
if (isInfinite) {
|
||||
statusClass = styles.infinite;
|
||||
} else {
|
||||
if (percentage >= 100) {
|
||||
statusClass = styles.danger;
|
||||
} else if (percentage >= 80) {
|
||||
statusClass = styles.warning;
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setAnimatedWidth(percentage);
|
||||
}, 100);
|
||||
return () => clearTimeout(timer);
|
||||
}, [percentage]);
|
||||
|
||||
return (
|
||||
<div className={styles.metricRow}>
|
||||
<div className={styles.metricHeader}>
|
||||
<div className={styles.metricTitleWrap}>
|
||||
<span className={styles.metricIcon}>{icon}</span>
|
||||
<span className={styles.metricTitle}>{title}</span>
|
||||
</div>
|
||||
<div className={styles.metricValue}>
|
||||
<span className={styles.currentValue}>{value}</span>
|
||||
<span className={styles.maxValue}>/ {formattedMax}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.progressContainer}>
|
||||
<div
|
||||
className={classNames(styles.progressBar, statusClass)}
|
||||
style={{ width: `${animatedWidth}%` }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default function PlanMetricsWidget({
|
||||
subscription,
|
||||
metrics,
|
||||
onUpgrade,
|
||||
onCancel,
|
||||
isOwner = true,
|
||||
}: PlanMetricsWidgetProps) {
|
||||
const isCancelled = subscription.mpStatus === MP_SUBS_STATUS.CANCELLED;
|
||||
|
||||
return (
|
||||
<div className={styles.widgetContainer}>
|
||||
<div className={styles.widgetHeader}>
|
||||
<h3 className={styles.title}>Métricas del Plan {subscription.plan.name}</h3>
|
||||
<span className={styles.subtitle}>Uso actual de tu suscripción</span>
|
||||
</div>
|
||||
|
||||
<div className={styles.metricsList}>
|
||||
<MetricRow
|
||||
icon={<StorefrontOutlinedIcon fontSize="small" />}
|
||||
title="Organizaciones"
|
||||
value={metrics.organizationsCount}
|
||||
maxValue={subscription.plan.limitOrganizations}
|
||||
/>
|
||||
<MetricRow
|
||||
icon={<PeopleOutlineOutlinedIcon fontSize="small" />}
|
||||
title="Clientes"
|
||||
value={metrics.clientsCount}
|
||||
maxValue={subscription.plan.limitClients}
|
||||
/>
|
||||
<MetricRow
|
||||
icon={<CalendarTodayOutlinedIcon fontSize="small" />}
|
||||
title="Turnos"
|
||||
value={metrics.appointmentsCount}
|
||||
maxValue={subscription.plan.limitAppointments}
|
||||
/>
|
||||
<MetricRow
|
||||
icon={<AssignmentIndOutlinedIcon fontSize="small" />}
|
||||
title="Colaboradores"
|
||||
value={metrics.employeesCount}
|
||||
maxValue={subscription.plan.limitEmployees}
|
||||
/>
|
||||
<MetricRow
|
||||
icon={<RepeatOutlinedIcon fontSize="small" />}
|
||||
title="Repeticiones"
|
||||
value={metrics.repeatsCount || 0}
|
||||
maxValue={subscription.plan.limitRepeats}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{isOwner && (
|
||||
<div className={styles.actionsContainer}>
|
||||
<Button
|
||||
color="primary"
|
||||
text="Mejorar mi plan"
|
||||
width="custom"
|
||||
style={{ width: "100%", padding: "12px 0", borderRadius: "8px", fontWeight: "600" }}
|
||||
onClick={onUpgrade}
|
||||
/>
|
||||
<div className={styles.statusFooter}>
|
||||
{isCancelled ? (
|
||||
<div className={styles.cancelledInfo}>
|
||||
<p className={styles.cancelledText}>La suscripción ha sido cancelada</p>
|
||||
<p className={styles.validUntilText}>
|
||||
Vigente hasta el {dayjs(subscription.endDate).format("DD/MM/YYYY")}
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<Button
|
||||
color="link"
|
||||
text="Cancelar subscripción"
|
||||
onClick={onCancel}
|
||||
width="custom"
|
||||
style={{ margin: 0, padding: 0, fontSize: "13px", color: "#6b7280", minHeight: "auto" }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user