feat: add manual subscription finalization functionality and support for expired plan notifications
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
"use client";
|
||||
import MetricGraph from "@components/MetricGraph/MetricGraph";
|
||||
import AnimatedContainer from "@core/app/components/AnimatedConainer/AnimatedContainer";
|
||||
import Button from "@core/app/components/Button/Button";
|
||||
import { useNavigation } from "@core/app/hooks/goto";
|
||||
@@ -36,7 +35,6 @@ import { blurElementsOnLoad } from "@core/helpers/blur";
|
||||
import HeaderConfProvider from "@core/app/components/HeaderConfProvider/HeaderConfProvider";
|
||||
import classNames from "classnames";
|
||||
import { ScrollToTop } from "@core/app/components/ScrollTop";
|
||||
import { isNull } from "@core/app/helpers/IsNull";
|
||||
|
||||
import StorefrontOutlinedIcon from "@mui/icons-material/StorefrontOutlined";
|
||||
import NotificationsNoneOutlinedIcon from "@mui/icons-material/NotificationsNoneOutlined";
|
||||
@@ -56,16 +54,8 @@ function DashboardContent() {
|
||||
const eventHandler = useEventHandlerStore();
|
||||
const alert = useAlert();
|
||||
const confirm = useConfirmStore();
|
||||
const infoEmail = process.env.NEXT_PUBLIC_INFO_EMAIL || "info@turnosxpress.com.ar";
|
||||
|
||||
const [metrics, setMetrics] = useState({
|
||||
organizationsCount: 0,
|
||||
employeesCount: 0,
|
||||
clientsCount: 0,
|
||||
appointmentsCount: 0,
|
||||
servicesCount: 0,
|
||||
repeatsCount: 0,
|
||||
});
|
||||
|
||||
const [showOnlyMine, setShowOnlyMine] = useState(false);
|
||||
const [isAgendaCollapsed, setIsAgendaCollapsed] = useState(true);
|
||||
|
||||
@@ -164,6 +154,7 @@ function DashboardContent() {
|
||||
const loadCompanyMetrics = async (companyId: string) => {
|
||||
setCompanySubscription(null);
|
||||
setCompanyMetrics(null);
|
||||
setIsCompanyOwner(false);
|
||||
try {
|
||||
const res = await getCompanyMetrics({ sessionUser: SessionInfo.userId, companyId });
|
||||
setCompanyMetrics(res.metrics);
|
||||
@@ -315,6 +306,7 @@ function DashboardContent() {
|
||||
};
|
||||
|
||||
const isUsingSessionSubscriptionFallback = !companySubscription && Boolean(subscription.plan.id);
|
||||
const selectedOrganization = organizations.find((organization) => organization.id === selectedOrgId);
|
||||
const displayedSubscription = companySubscription ?? (subscription.plan.id ? subscription : null);
|
||||
const displayedPlan = displayedSubscription?.plan;
|
||||
const displayedPlanStatusText = displayedPlan?.price === 0 ? "ACTIVO" : getSubStatusText(displayedSubscription?.mpStatus);
|
||||
@@ -325,11 +317,30 @@ function DashboardContent() {
|
||||
displayedSubscription.lastPaymentAt &&
|
||||
dayjs().diff(dayjs(displayedSubscription.lastPaymentAt), "day") <= 14
|
||||
);
|
||||
const showPaymentAction = Boolean(
|
||||
(displayedSubscription?.mpStatus === MP_SUBS_STATUS.PENDING || hasPendingPaymentMetadata) &&
|
||||
(isCompanyOwner || isUsingSessionSubscriptionFallback)
|
||||
const selectedCompanyHasPendingPayment = Boolean(
|
||||
companySubscription &&
|
||||
(companySubscription.mpStatus === MP_SUBS_STATUS.PENDING || companySubscription.pendingPaymentPreferenceId)
|
||||
);
|
||||
const showPaymentAction = selectedOrgId
|
||||
? Boolean(selectedCompanyHasPendingPayment && isCompanyOwner)
|
||||
: Boolean(
|
||||
(displayedSubscription?.mpStatus === MP_SUBS_STATUS.PENDING || hasPendingPaymentMetadata) &&
|
||||
isUsingSessionSubscriptionFallback
|
||||
);
|
||||
const showFailedPaymentCard = Boolean(hasRecentFailedPayment && !showPaymentAction);
|
||||
const showExpiredDowngradeCard = Boolean(
|
||||
displayedSubscription?.downgradeReason === "expired" &&
|
||||
displayedSubscription.downgradedAt &&
|
||||
isCompanyOwner
|
||||
);
|
||||
const selectedCompanyPlanSupportsRepeats = Boolean(
|
||||
companySubscription?.plan &&
|
||||
(companySubscription.plan.limitRepeats === -1 || companySubscription.plan.limitRepeats > 0)
|
||||
);
|
||||
const canLoadPendingRepeats = Boolean(
|
||||
selectedCompanyPlanSupportsRepeats &&
|
||||
(isCompanyOwner || selectedOrganization?.isAdmin)
|
||||
);
|
||||
const showFreePlanStarterContent = Boolean(displayedPlan && displayedPlan.price === 0 && organizations.length === 0);
|
||||
const agendaItems = dashboardData?.personalAgenda ?? [];
|
||||
const filteredAgendaItems = agendaItems.filter(item => !showOnlyMine || item.collaboratorId === SessionInfo.userId);
|
||||
@@ -365,7 +376,12 @@ function DashboardContent() {
|
||||
<div style={{ position: "absolute", top: "20px", right: "20px", display: "flex", alignItems: "center", gap: "10px" }}>
|
||||
<select
|
||||
value={selectedOrgId}
|
||||
onChange={e => setSelectedOrgId(e.target.value)}
|
||||
onChange={e => {
|
||||
setCompanySubscription(null);
|
||||
setCompanyMetrics(null);
|
||||
setIsCompanyOwner(false);
|
||||
setSelectedOrgId(e.target.value);
|
||||
}}
|
||||
style={{ padding: "8px 12px", borderRadius: "8px", border: "1px solid #e5e7eb", fontSize: "14px", fontWeight: "500", backgroundColor: "#f9fafb", cursor: "pointer", outline: "none" }}
|
||||
>
|
||||
{organizations.map(org => (
|
||||
@@ -435,6 +451,7 @@ function DashboardContent() {
|
||||
<p>
|
||||
Si ya pagaste, puede tardar unos minutos en actualizarse porque dependemos de la notificación de MercadoPago.
|
||||
No te preocupes: podés volver al checkout si quedó incompleto o pedirnos que verifiquemos el pago ahora mismo.
|
||||
{" "}Si el problema continúa, escribinos a <a className={style.pendingPaymentLink} href={`mailto:${infoEmail}`}>{infoEmail}</a> y te ayudamos a revisarlo.
|
||||
</p>
|
||||
</div>
|
||||
<div className={style.pendingPaymentActions}>
|
||||
@@ -482,6 +499,25 @@ function DashboardContent() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showExpiredDowngradeCard && (
|
||||
<div className={style.expiredDowngradeCard}>
|
||||
<div className={style.pendingPaymentContent}>
|
||||
<span className={style.expiredDowngradeEyebrow}>Plan vencido</span>
|
||||
<h2>Tu plan pago venció y pasaste al plan básico</h2>
|
||||
<p>
|
||||
No borramos tu organización ni tus datos. Desde ahora las nuevas acciones usan los límites del plan básico.
|
||||
{displayedSubscription?.downgradedFromPlanName && ` Tu plan anterior era ${displayedSubscription.downgradedFromPlanName}.`}
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
className={style.expiredDowngradeButton}
|
||||
onClick={() => goTo(selectedOrgId ? `/landing/upgrade-plan?org=${selectedOrgId}` : "/landing/pricing")}
|
||||
>
|
||||
Volver a contratar un plan
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showFreePlanStarterContent && (
|
||||
<div className={style.starterCard}>
|
||||
<div className={style.starterContent}>
|
||||
@@ -649,7 +685,7 @@ function DashboardContent() {
|
||||
)}
|
||||
|
||||
{/* Repeats Pending Card */}
|
||||
{dashboardData && selectedOrgId && (
|
||||
{dashboardData && selectedOrgId && canLoadPendingRepeats && (
|
||||
<PendingRepeatsCard
|
||||
companyId={selectedOrgId}
|
||||
allowEmployeeFilter={true}
|
||||
|
||||
Reference in New Issue
Block a user