feat: integrate bottom toolbar store in various organization profile pages
- Added bottom toolbar functionality to the Schedules, Services, Templates, and WAP pages. - Ensured the bottom toolbar is cleared on component unmount. - Improved code formatting and consistency across components. - Minor adjustments to state management and event handling for better clarity and performance.
This commit is contained in:
+316
-147
@@ -23,6 +23,7 @@ import { CLIENT_ACCOUNT_MOVEMENT_TYPES } from "@core/Models/ClientAccountMovemen
|
||||
import { getPaymentIcon } from "@core/app/components/PaymentIcons/PaymentIcons";
|
||||
import SecureByPlan, { SECURE_CONTENTS } from "@core/app/components/SecureByPlan/SecureByPlan";
|
||||
import { motion } from "motion/react";
|
||||
import { useBottomToolbarStore } from "@core/Store/BottomToolbar.Store";
|
||||
|
||||
type UrlData = {
|
||||
oid: string;
|
||||
@@ -36,6 +37,7 @@ export default function ClientAccount() {
|
||||
const alert = useAlert();
|
||||
const SessionInfo = useSessionStore();
|
||||
const location = useLocationStore();
|
||||
const bottomToolbar = useBottomToolbarStore();
|
||||
const eventHandler = useEventHandlerStore();
|
||||
const { goTo } = useNavigation();
|
||||
|
||||
@@ -68,6 +70,8 @@ export default function ClientAccount() {
|
||||
useEffect(() => {
|
||||
location.clear();
|
||||
|
||||
bottomToolbar.set(<></>);
|
||||
|
||||
location.add({
|
||||
url: "/admin/org/profile/" + id + "/clients",
|
||||
title: "Clientes",
|
||||
@@ -85,6 +89,10 @@ export default function ClientAccount() {
|
||||
title: "Cuenta Corriente",
|
||||
icon: <AccountBalanceOutlinedIcon sx={{ fontSize: "32px", mr: "10px" }} />,
|
||||
});
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -127,149 +135,273 @@ export default function ClientAccount() {
|
||||
|
||||
<SecureByPlan content={SECURE_CONTENTS.PAYMENTS} companyId={id}>
|
||||
<div style={{ maxWidth: "800px", margin: "0 auto", paddingBottom: "100px" }}>
|
||||
|
||||
{/* Top Status Card */}
|
||||
<div style={{ position: "sticky", top: "70px", zIndex: 100, display: "flex", flexDirection: "column", background: "white", paddingBottom: "20px", paddingTop: "5px", margin: "0 -10px 30px -10px", paddingLeft: "10px", paddingRight: "10px" }}>
|
||||
{view && (
|
||||
<motion.div
|
||||
layout
|
||||
initial={{ opacity: 0, y: -20 }}
|
||||
animate={{
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
padding: isMinimized ? "25px 50px" : "40px 20px",
|
||||
borderRadius: isMinimized ? "15px" : "20px"
|
||||
}}
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: isMinimized ? "row" : "column",
|
||||
alignItems: "center",
|
||||
justifyContent: isMinimized ? "space-between" : "center",
|
||||
background: view.amount >= 0
|
||||
? "linear-gradient(135deg, #1d976c 0%, #93f9b9 100%)"
|
||||
: "linear-gradient(135deg, #cb2d3e 0%, #ef473a 100%)",
|
||||
color: "white",
|
||||
boxShadow: isMinimized ? "0 4px 15px rgba(0,0,0,0.3)" : "0 10px 30px rgba(0,0,0,0.15)",
|
||||
position: "relative",
|
||||
overflow: "hidden",
|
||||
transition: "box-shadow 0.3s ease"
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
onClick={() => setForceMinimized(!forceMinimized)}
|
||||
style={{ position: "absolute", top: "10px", left: "10px", color: "rgba(255,255,255,0.7)", zIndex: 10 }}
|
||||
size="small"
|
||||
title={forceMinimized ? "Maximizar" : "Minimizar"}
|
||||
>
|
||||
{forceMinimized ? <UnfoldMoreIcon /> : <UnfoldLessIcon />}
|
||||
</IconButton>
|
||||
|
||||
{/* Decorative background circles */}
|
||||
<div style={{ position: "absolute", top: "-50px", right: "-50px", width: "150px", height: "150px", borderRadius: "50%", background: "rgba(255,255,255,0.1)" }}></div>
|
||||
<div style={{ position: "absolute", bottom: "-30px", left: "-30px", width: "100px", height: "100px", borderRadius: "50%", background: "rgba(255,255,255,0.1)" }}></div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
position: "sticky",
|
||||
top: "70px",
|
||||
zIndex: 100,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
background: "white",
|
||||
paddingBottom: "20px",
|
||||
paddingTop: "5px",
|
||||
margin: "0 -10px 30px -10px",
|
||||
paddingLeft: "10px",
|
||||
paddingRight: "10px",
|
||||
}}
|
||||
>
|
||||
{view && (
|
||||
<motion.div
|
||||
layout
|
||||
initial={{ opacity: 0, y: -20 }}
|
||||
animate={{
|
||||
fontSize: isMinimized ? "14px" : "16px",
|
||||
marginBottom: isMinimized ? "0px" : "0px",
|
||||
marginLeft: isMinimized ? "30px" : "0px"
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
padding: isMinimized ? "25px 50px" : "40px 20px",
|
||||
borderRadius: isMinimized ? "15px" : "20px",
|
||||
}}
|
||||
style={{ fontWeight: "bold", opacity: 0.9, textTransform: "uppercase", letterSpacing: "1px" }}
|
||||
>
|
||||
Saldo Actual
|
||||
</motion.div>
|
||||
<motion.div
|
||||
animate={{
|
||||
fontSize: isMinimized ? "24px" : "56px",
|
||||
margin: isMinimized ? "0px" : "10px 0 30px 0"
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: isMinimized ? "row" : "column",
|
||||
alignItems: "center",
|
||||
justifyContent: isMinimized ? "space-between" : "center",
|
||||
background:
|
||||
view.amount >= 0
|
||||
? "linear-gradient(135deg, #1d976c 0%, #93f9b9 100%)"
|
||||
: "linear-gradient(135deg, #cb2d3e 0%, #ef473a 100%)",
|
||||
color: "white",
|
||||
boxShadow: isMinimized
|
||||
? "0 4px 15px rgba(0,0,0,0.3)"
|
||||
: "0 10px 30px rgba(0,0,0,0.15)",
|
||||
position: "relative",
|
||||
overflow: "hidden",
|
||||
transition: "box-shadow 0.3s ease",
|
||||
}}
|
||||
style={{ fontWeight: "900", textShadow: "0 2px 10px rgba(0,0,0,0.1)" }}
|
||||
>
|
||||
{formatPrice(view.amount)}
|
||||
</motion.div>
|
||||
|
||||
|
||||
{!isMinimized && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
style={{ display: "flex", gap: "15px", flexDirection: "row", zIndex: 1 }}
|
||||
<IconButton
|
||||
onClick={() => setForceMinimized(!forceMinimized)}
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "10px",
|
||||
left: "10px",
|
||||
color: "rgba(255,255,255,0.7)",
|
||||
zIndex: 10,
|
||||
}}
|
||||
size="small"
|
||||
title={forceMinimized ? "Maximizar" : "Minimizar"}
|
||||
>
|
||||
<motion.div whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }}>
|
||||
<IconButton
|
||||
sx={{
|
||||
backgroundColor: "rgba(255,255,255,0.2)",
|
||||
color: "white",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
width: "110px",
|
||||
height: "90px",
|
||||
borderRadius: "15px",
|
||||
"&:hover": { backgroundColor: "rgba(255,255,255,0.3)" }
|
||||
}}
|
||||
onClick={() => add(CLIENT_ACCOUNT_MOVEMENT_TYPES.DEPOSIT)}
|
||||
>
|
||||
<DepositarIcon sx={{ fontSize: "32px", marginBottom: "5px" }} />
|
||||
<span style={{ fontSize: "14px", fontWeight: "bold" }}>Ingresar</span>
|
||||
</IconButton>
|
||||
</motion.div>
|
||||
{forceMinimized ? <UnfoldMoreIcon /> : <UnfoldLessIcon />}
|
||||
</IconButton>
|
||||
|
||||
<motion.div whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }}>
|
||||
<IconButton
|
||||
sx={{
|
||||
backgroundColor: "rgba(255,255,255,0.2)",
|
||||
color: "white",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
width: "110px",
|
||||
height: "90px",
|
||||
borderRadius: "15px",
|
||||
"&:hover": { backgroundColor: "rgba(255,255,255,0.3)" }
|
||||
}}
|
||||
onClick={() => add(CLIENT_ACCOUNT_MOVEMENT_TYPES.WITHDRAWAL)}
|
||||
>
|
||||
<RetirarIcon sx={{ fontSize: "32px", marginBottom: "5px" }} />
|
||||
<span style={{ fontSize: "14px", fontWeight: "bold" }}>Retirar</span>
|
||||
</IconButton>
|
||||
</motion.div>
|
||||
{/* Decorative background circles */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "-50px",
|
||||
right: "-50px",
|
||||
width: "150px",
|
||||
height: "150px",
|
||||
borderRadius: "50%",
|
||||
background: "rgba(255,255,255,0.1)",
|
||||
}}
|
||||
></div>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
bottom: "-30px",
|
||||
left: "-30px",
|
||||
width: "100px",
|
||||
height: "100px",
|
||||
borderRadius: "50%",
|
||||
background: "rgba(255,255,255,0.1)",
|
||||
}}
|
||||
></div>
|
||||
|
||||
<motion.div whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }}>
|
||||
<IconButton
|
||||
sx={{
|
||||
backgroundColor: "white",
|
||||
color: view.amount >= 0 ? "#1d976c" : "#cb2d3e",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
width: "110px",
|
||||
height: "90px",
|
||||
borderRadius: "15px",
|
||||
boxShadow: "0 4px 15px rgba(0,0,0,0.1)",
|
||||
"&:hover": { backgroundColor: "#f8f9fa" }
|
||||
}}
|
||||
onClick={() => goTo("/admin/org/" + id + "/client/" + clientId + "/account/movements")}
|
||||
>
|
||||
<MovimientosIcon sx={{ fontSize: "32px", marginBottom: "5px" }} />
|
||||
<span style={{ fontSize: "14px", fontWeight: "bold" }}>Historial</span>
|
||||
</IconButton>
|
||||
</motion.div>
|
||||
<motion.div
|
||||
animate={{
|
||||
fontSize: isMinimized ? "14px" : "16px",
|
||||
marginBottom: isMinimized ? "0px" : "0px",
|
||||
marginLeft: isMinimized ? "30px" : "0px",
|
||||
}}
|
||||
style={{
|
||||
fontWeight: "bold",
|
||||
opacity: 0.9,
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: "1px",
|
||||
}}
|
||||
>
|
||||
Saldo Actual
|
||||
</motion.div>
|
||||
)}
|
||||
</motion.div>
|
||||
)}
|
||||
<motion.div
|
||||
animate={{
|
||||
fontSize: isMinimized ? "24px" : "56px",
|
||||
margin: isMinimized ? "0px" : "10px 0 30px 0",
|
||||
}}
|
||||
style={{
|
||||
fontWeight: "900",
|
||||
textShadow: "0 2px 10px rgba(0,0,0,0.1)",
|
||||
}}
|
||||
>
|
||||
{formatPrice(view.amount)}
|
||||
</motion.div>
|
||||
|
||||
{!isMinimized && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: "15px",
|
||||
flexDirection: "row",
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
<motion.div
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
>
|
||||
<IconButton
|
||||
sx={{
|
||||
backgroundColor: "rgba(255,255,255,0.2)",
|
||||
color: "white",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
width: "110px",
|
||||
height: "90px",
|
||||
borderRadius: "15px",
|
||||
"&:hover": {
|
||||
backgroundColor: "rgba(255,255,255,0.3)",
|
||||
},
|
||||
}}
|
||||
onClick={() =>
|
||||
add(CLIENT_ACCOUNT_MOVEMENT_TYPES.DEPOSIT)
|
||||
}
|
||||
>
|
||||
<DepositarIcon
|
||||
sx={{ fontSize: "32px", marginBottom: "5px" }}
|
||||
/>
|
||||
<span
|
||||
style={{ fontSize: "14px", fontWeight: "bold" }}
|
||||
>
|
||||
Ingresar
|
||||
</span>
|
||||
</IconButton>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
>
|
||||
<IconButton
|
||||
sx={{
|
||||
backgroundColor: "rgba(255,255,255,0.2)",
|
||||
color: "white",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
width: "110px",
|
||||
height: "90px",
|
||||
borderRadius: "15px",
|
||||
"&:hover": {
|
||||
backgroundColor: "rgba(255,255,255,0.3)",
|
||||
},
|
||||
}}
|
||||
onClick={() =>
|
||||
add(CLIENT_ACCOUNT_MOVEMENT_TYPES.WITHDRAWAL)
|
||||
}
|
||||
>
|
||||
<RetirarIcon
|
||||
sx={{ fontSize: "32px", marginBottom: "5px" }}
|
||||
/>
|
||||
<span
|
||||
style={{ fontSize: "14px", fontWeight: "bold" }}
|
||||
>
|
||||
Retirar
|
||||
</span>
|
||||
</IconButton>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
>
|
||||
<IconButton
|
||||
sx={{
|
||||
backgroundColor: "white",
|
||||
color: view.amount >= 0 ? "#1d976c" : "#cb2d3e",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
width: "110px",
|
||||
height: "90px",
|
||||
borderRadius: "15px",
|
||||
boxShadow: "0 4px 15px rgba(0,0,0,0.1)",
|
||||
"&:hover": { backgroundColor: "#f8f9fa" },
|
||||
}}
|
||||
onClick={() =>
|
||||
goTo(
|
||||
"/admin/org/" +
|
||||
id +
|
||||
"/client/" +
|
||||
clientId +
|
||||
"/account/movements",
|
||||
)
|
||||
}
|
||||
>
|
||||
<MovimientosIcon
|
||||
sx={{ fontSize: "32px", marginBottom: "5px" }}
|
||||
/>
|
||||
<span
|
||||
style={{ fontSize: "14px", fontWeight: "bold" }}
|
||||
>
|
||||
Historial
|
||||
</span>
|
||||
</IconButton>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
)}
|
||||
</motion.div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: "10px" }}>
|
||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "15px", padding: "0 10px" }}>
|
||||
<div style={{ fontSize: "20px", fontWeight: "bold", color: "var(--black-light)" }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: "15px",
|
||||
padding: "0 10px",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "20px",
|
||||
fontWeight: "bold",
|
||||
color: "var(--black-light)",
|
||||
}}
|
||||
>
|
||||
Últimos Movimientos
|
||||
</div>
|
||||
<div
|
||||
style={{ fontSize: "14px", color: "var(--wine-dark)", cursor: "pointer", fontWeight: "bold" }}
|
||||
onClick={() => goTo("/admin/org/" + id + "/client/" + clientId + "/account/movements")}
|
||||
style={{
|
||||
fontSize: "14px",
|
||||
color: "var(--wine-dark)",
|
||||
cursor: "pointer",
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
onClick={() =>
|
||||
goTo(
|
||||
"/admin/org/" +
|
||||
id +
|
||||
"/client/" +
|
||||
clientId +
|
||||
"/account/movements",
|
||||
)
|
||||
}
|
||||
>
|
||||
Ver todos
|
||||
</div>
|
||||
@@ -294,42 +426,79 @@ export default function ClientAccount() {
|
||||
boxShadow: "0 2px 8px rgba(0,0,0,0.05)",
|
||||
}}
|
||||
>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "15px" }}>
|
||||
<div style={{
|
||||
width: "45px",
|
||||
height: "45px",
|
||||
borderRadius: "12px",
|
||||
backgroundColor: movement.amount > 0 ? "rgba(40, 167, 69, 0.1)" : "rgba(220, 53, 69, 0.1)",
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
color: movement.amount > 0 ? "#28a745" : "#dc3545"
|
||||
}}>
|
||||
gap: "15px",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: "45px",
|
||||
height: "45px",
|
||||
borderRadius: "12px",
|
||||
backgroundColor:
|
||||
movement.amount > 0
|
||||
? "rgba(40, 167, 69, 0.1)"
|
||||
: "rgba(220, 53, 69, 0.1)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
color:
|
||||
movement.amount > 0 ? "#28a745" : "#dc3545",
|
||||
}}
|
||||
>
|
||||
{getPaymentIcon(movement.paymentMethod)}
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ fontSize: "16px", fontWeight: "bold", color: "#333", marginBottom: "3px" }}>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "16px",
|
||||
fontWeight: "bold",
|
||||
color: "#333",
|
||||
marginBottom: "3px",
|
||||
}}
|
||||
>
|
||||
{movement.description}
|
||||
</div>
|
||||
<div style={{ fontSize: "13px", color: "#888" }}>
|
||||
{dayjs(movement.createdAt).format("DD MMMM YYYY • HH:mm")}
|
||||
{dayjs(movement.createdAt).format(
|
||||
"DD MMMM YYYY • HH:mm",
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{
|
||||
fontSize: "18px",
|
||||
fontWeight: "900",
|
||||
color: movement.amount > 0 ? "#28a745" : "#dc3545",
|
||||
}}>
|
||||
{movement.amount > 0 ? "+" : ""}{formatPrice(movement.amount)}
|
||||
<div
|
||||
style={{
|
||||
fontSize: "18px",
|
||||
fontWeight: "900",
|
||||
color: movement.amount > 0 ? "#28a745" : "#dc3545",
|
||||
}}
|
||||
>
|
||||
{movement.amount > 0 ? "+" : ""}
|
||||
{formatPrice(movement.amount)}
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ textAlign: "center", padding: "40px", backgroundColor: "#fff", borderRadius: "15px", color: "#888", border: "1px dashed #ccc" }}>
|
||||
<AccountBalanceOutlinedIcon sx={{ fontSize: "48px", color: "#ddd", marginBottom: "10px" }} />
|
||||
<div style={{ fontSize: "16px", fontWeight: "bold", color: "#666" }}>
|
||||
<div
|
||||
style={{
|
||||
textAlign: "center",
|
||||
padding: "40px",
|
||||
backgroundColor: "#fff",
|
||||
borderRadius: "15px",
|
||||
color: "#888",
|
||||
border: "1px dashed #ccc",
|
||||
}}
|
||||
>
|
||||
<AccountBalanceOutlinedIcon
|
||||
sx={{ fontSize: "48px", color: "#ddd", marginBottom: "10px" }}
|
||||
/>
|
||||
<div
|
||||
style={{ fontSize: "16px", fontWeight: "bold", color: "#666" }}
|
||||
>
|
||||
Aún no hay movimientos
|
||||
</div>
|
||||
<div style={{ fontSize: "14px" }}>
|
||||
|
||||
+24
-18
@@ -1,9 +1,6 @@
|
||||
"use client";
|
||||
import { useAlert } from "@core/Store/Alert.Store";
|
||||
import {
|
||||
useEventHandlerStore,
|
||||
EVENT_TYPES,
|
||||
} from "@core/Store/EventHandler.Store";
|
||||
import { useEventHandlerStore, EVENT_TYPES } from "@core/Store/EventHandler.Store";
|
||||
import { useLocationStore } from "@core/Store/Location.Store";
|
||||
import { useParams } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
@@ -14,6 +11,7 @@ import ServiceItem from "@core/app/components/ServiceItem/ServiceItem";
|
||||
import Location from "@core/app/components/Location/Location";
|
||||
import { useNavigation } from "@core/app/hooks/goto";
|
||||
import { useMenuStore } from "@core/Store/Menu.Store";
|
||||
import { useBottomToolbarStore } from "@core/Store/BottomToolbar.Store";
|
||||
|
||||
type UrlData = {
|
||||
oid: string;
|
||||
@@ -26,14 +24,14 @@ export default function ClientAppointments() {
|
||||
const clientId = data.clientId;
|
||||
const alert = useAlert();
|
||||
const location = useLocationStore();
|
||||
const bottomToolbar = useBottomToolbarStore();
|
||||
const eventHandler = useEventHandlerStore();
|
||||
const menu = useMenuStore();
|
||||
const { goTo } = useNavigation();
|
||||
|
||||
const [appintments, setAppointments] =
|
||||
useState<AppointmentAdminByClientView>({
|
||||
events: [],
|
||||
});
|
||||
const [appintments, setAppointments] = useState<AppointmentAdminByClientView>({
|
||||
events: [],
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
eventHandler.setEventType(EVENT_TYPES.SLEEP);
|
||||
@@ -44,6 +42,8 @@ export default function ClientAppointments() {
|
||||
useEffect(() => {
|
||||
location.clear();
|
||||
|
||||
bottomToolbar.set(<></>);
|
||||
|
||||
location.add({
|
||||
url: "/admin/org/profile/" + id + "/clients",
|
||||
title: "Clientes",
|
||||
@@ -61,6 +61,10 @@ export default function ClientAppointments() {
|
||||
title: "Turnos reservados",
|
||||
icon: <ClientsIcon sx={{ fontSize: "32px", mr: "10px" }} />,
|
||||
});
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -89,15 +93,17 @@ export default function ClientAppointments() {
|
||||
}}
|
||||
>
|
||||
{appintments.events.length === 0 ? (
|
||||
<div style={{
|
||||
gridColumn: "1 / -1",
|
||||
textAlign: "center",
|
||||
padding: "40px 20px",
|
||||
background: "#fff",
|
||||
borderRadius: "12px",
|
||||
boxShadow: "0 4px 15px rgba(0,0,0,0.02)",
|
||||
color: "#7f8c8d"
|
||||
}}>
|
||||
<div
|
||||
style={{
|
||||
gridColumn: "1 / -1",
|
||||
textAlign: "center",
|
||||
padding: "40px 20px",
|
||||
background: "#fff",
|
||||
borderRadius: "12px",
|
||||
boxShadow: "0 4px 15px rgba(0,0,0,0.02)",
|
||||
color: "#7f8c8d",
|
||||
}}
|
||||
>
|
||||
No hay turnos registrados para este cliente.
|
||||
</div>
|
||||
) : (
|
||||
@@ -113,7 +119,7 @@ export default function ClientAppointments() {
|
||||
"/client/" +
|
||||
clientId +
|
||||
"/appointments/" +
|
||||
event.id
|
||||
event.id,
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -15,6 +15,7 @@ import { validatePhone } from "@core/helpers/validatePhone";
|
||||
import { useConfirmStore } from "@core/Store/Confirm.Store";
|
||||
import Switch from "@core/app/components/Switch/Switch";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { useBottomToolbarStore } from "@core/Store/BottomToolbar.Store";
|
||||
|
||||
type UrlData = {
|
||||
oid: string;
|
||||
@@ -29,6 +30,7 @@ export default function ClientCreate() {
|
||||
const confirm = useConfirmStore();
|
||||
const SessionInfo = useSessionStore();
|
||||
const location = useLocationStore();
|
||||
const bottomToolbar = useBottomToolbarStore();
|
||||
const eventHandler = useEventHandlerStore();
|
||||
const [firstName, setFirstName] = useState("");
|
||||
const [lastName, setLastName] = useState("");
|
||||
@@ -46,6 +48,8 @@ export default function ClientCreate() {
|
||||
useEffect(() => {
|
||||
location.clear();
|
||||
|
||||
bottomToolbar.set(<></>);
|
||||
|
||||
location.add({
|
||||
url: "/admin/org/profile/" + id + "/clients",
|
||||
title: "Clientes",
|
||||
@@ -63,6 +67,10 @@ export default function ClientCreate() {
|
||||
title: "Editar",
|
||||
icon: <ClientsIcon sx={{ fontSize: "32px", mr: "10px" }} />,
|
||||
});
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -92,7 +100,7 @@ export default function ClientCreate() {
|
||||
confirm.show(
|
||||
validationPhoneResult.message,
|
||||
() => {},
|
||||
() => {}
|
||||
() => {},
|
||||
);
|
||||
eventHandler.setEventType(EVENT_TYPES.SLEEP);
|
||||
return;
|
||||
@@ -112,7 +120,7 @@ export default function ClientCreate() {
|
||||
})
|
||||
.then(() => {
|
||||
alert.showSuccess(
|
||||
`Información del cliente ${firstName} ${lastName} actualizada`
|
||||
`Información del cliente ${firstName} ${lastName} actualizada`,
|
||||
);
|
||||
setTimeout(() => {
|
||||
goTo("/admin/org/" + id + "/client/" + clientId + "/profile");
|
||||
@@ -180,7 +188,9 @@ export default function ClientCreate() {
|
||||
/>
|
||||
<div style={{ marginTop: "15px" }}></div>
|
||||
<Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
|
||||
<Typography variant="body1" sx={{ fontWeight: "bold", paddingLeft: "10px" }}>Baneado (No puede reservar)</Typography>
|
||||
<Typography variant="body1" sx={{ fontWeight: "bold", paddingLeft: "10px" }}>
|
||||
Baneado (No puede reservar)
|
||||
</Typography>
|
||||
<Switch
|
||||
checked={banned}
|
||||
onChange={(checked) => {
|
||||
|
||||
@@ -18,6 +18,7 @@ import { ClientMergeParams, OrganizationClientView } from "@core/Models/Clients.
|
||||
import Button from "@core/app/components/Button/Button";
|
||||
import MaterialAlert from "@mui/material/Alert";
|
||||
import { useConfirmStore } from "@core/Store/Confirm.Store";
|
||||
import { useBottomToolbarStore } from "@core/Store/BottomToolbar.Store";
|
||||
|
||||
type UrlData = {
|
||||
oid: string;
|
||||
@@ -32,6 +33,7 @@ export default function ClientCreate() {
|
||||
const confirm = useConfirmStore();
|
||||
const SessionInfo = useSessionStore();
|
||||
const location = useLocationStore();
|
||||
const bottomToolbar = useBottomToolbarStore();
|
||||
const eventHandler = useEventHandlerStore();
|
||||
const { goTo } = useNavigation();
|
||||
|
||||
@@ -53,7 +55,7 @@ export default function ClientCreate() {
|
||||
});
|
||||
|
||||
const [clientMergeFilterData, setClientMergeFilterData] = useState<TextObjectFilterResult[]>(
|
||||
[]
|
||||
[],
|
||||
);
|
||||
const [clientMergeId, setClientMergeId] = useState<string>("");
|
||||
|
||||
@@ -94,7 +96,7 @@ export default function ClientCreate() {
|
||||
() => {
|
||||
mergeClients();
|
||||
},
|
||||
() => {}
|
||||
() => {},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -105,6 +107,8 @@ export default function ClientCreate() {
|
||||
useEffect(() => {
|
||||
location.clear();
|
||||
|
||||
bottomToolbar.set(<></>);
|
||||
|
||||
location.add({
|
||||
url: "/admin/org/profile/" + id + "/clients",
|
||||
title: "Clientes",
|
||||
@@ -122,6 +126,10 @@ export default function ClientCreate() {
|
||||
title: "Fusionar clientes",
|
||||
icon: <ClientsIcon sx={{ fontSize: "32px", mr: "10px" }} />,
|
||||
});
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
+31
-13
@@ -11,6 +11,7 @@ import ClientsIcon from "@mui/icons-material/AccountBoxOutlined";
|
||||
import NotificationsIcon from "@mui/icons-material/NotificationsOutlined";
|
||||
import MaterialAlert from "@mui/material/Alert";
|
||||
import styles from "./NotificationsPage.module.css";
|
||||
import { useBottomToolbarStore } from "@core/Store/BottomToolbar.Store";
|
||||
|
||||
type UrlData = {
|
||||
oid: string;
|
||||
@@ -20,7 +21,7 @@ type UrlData = {
|
||||
const CHANNELS: { key: NotificationChannel; label: string }[] = [
|
||||
{ key: "whatsapp", label: "WhatsApp" },
|
||||
{ key: "email", label: "Email" },
|
||||
{ key: "system", label: "Sistema" }
|
||||
{ key: "system", label: "Sistema" },
|
||||
];
|
||||
|
||||
type ChannelPreference = "default" | "preferred" | "muted";
|
||||
@@ -30,34 +31,41 @@ export default function NotificationsPage() {
|
||||
const oid = data.oid;
|
||||
const clientId = data.clientId;
|
||||
const location = useLocationStore();
|
||||
const bottomToolbar = useBottomToolbarStore();
|
||||
const store = useNotificationPreferencesStore();
|
||||
|
||||
useEffect(() => {
|
||||
location.clear();
|
||||
|
||||
bottomToolbar.set(<></>);
|
||||
|
||||
location.add({
|
||||
url: "/admin/org",
|
||||
title: "Organizaciones",
|
||||
icon: null
|
||||
icon: null,
|
||||
});
|
||||
|
||||
location.add({
|
||||
url: "/admin/org/profile/" + oid,
|
||||
title: "Organización",
|
||||
icon: <StorefrontOutlinedIcon sx={{ mr: 0.5 }} fontSize="inherit" />
|
||||
icon: <StorefrontOutlinedIcon sx={{ mr: 0.5 }} fontSize="inherit" />,
|
||||
});
|
||||
|
||||
location.add({
|
||||
url: "/admin/org/" + oid + "/client/" + clientId + "/profile",
|
||||
title: "Cliente",
|
||||
icon: <ClientsIcon sx={{ fontSize: "32px", mr: "10px" }} />
|
||||
icon: <ClientsIcon sx={{ fontSize: "32px", mr: "10px" }} />,
|
||||
});
|
||||
|
||||
location.add({
|
||||
url: "",
|
||||
title: "Notificaciones",
|
||||
icon: <NotificationsIcon sx={{ fontSize: "32px", mr: "10px" }} />
|
||||
icon: <NotificationsIcon sx={{ fontSize: "32px", mr: "10px" }} />,
|
||||
});
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, [oid, clientId]);
|
||||
|
||||
const getChannelPreference = (channel: NotificationChannel): ChannelPreference => {
|
||||
@@ -81,7 +89,7 @@ export default function NotificationsPage() {
|
||||
mutedChannels:
|
||||
preference === "muted"
|
||||
? [...store.formData.mutedChannels.filter((c) => c !== channel), channel]
|
||||
: store.formData.mutedChannels.filter((c) => c !== channel)
|
||||
: store.formData.mutedChannels.filter((c) => c !== channel),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -91,7 +99,9 @@ export default function NotificationsPage() {
|
||||
|
||||
<div className={styles.container}>
|
||||
<MaterialAlert severity="info" sx={{ marginBottom: "0" }}>
|
||||
<b>Preferencias del cliente:</b> Configure cómo esta organización debe comunicarse con este cliente. Si deja un canal en estándar, se usará la política general de la organización.
|
||||
<b>Preferencias del cliente:</b> Configure cómo esta organización debe
|
||||
comunicarse con este cliente. Si deja un canal en estándar, se usará la política
|
||||
general de la organización.
|
||||
</MaterialAlert>
|
||||
|
||||
<div className={styles.channels}>
|
||||
@@ -102,24 +112,32 @@ export default function NotificationsPage() {
|
||||
<div>
|
||||
<div className={styles.channelTitle}>{channel.label}</div>
|
||||
<div className={styles.channelDescription}>
|
||||
{selectedPreference === "preferred" && "Priorizar este canal para el cliente."}
|
||||
{selectedPreference === "muted" && "No enviar notificaciones por este canal."}
|
||||
{selectedPreference === "default" && "Usar la configuración general de la organización."}
|
||||
{selectedPreference === "preferred" &&
|
||||
"Priorizar este canal para el cliente."}
|
||||
{selectedPreference === "muted" &&
|
||||
"No enviar notificaciones por este canal."}
|
||||
{selectedPreference === "default" &&
|
||||
"Usar la configuración general de la organización."}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.options}>
|
||||
{[
|
||||
{ key: "default" as ChannelPreference, label: "Estándar" },
|
||||
{ key: "preferred" as ChannelPreference, label: "Preferido" },
|
||||
{ key: "muted" as ChannelPreference, label: "Silenciado" }
|
||||
{
|
||||
key: "preferred" as ChannelPreference,
|
||||
label: "Preferido",
|
||||
},
|
||||
{ key: "muted" as ChannelPreference, label: "Silenciado" },
|
||||
].map((option) => {
|
||||
const isSelected = selectedPreference === option.key;
|
||||
return (
|
||||
<button
|
||||
key={option.key}
|
||||
type="button"
|
||||
onClick={() => selectPreference(channel.key, option.key)}
|
||||
onClick={() =>
|
||||
selectPreference(channel.key, option.key)
|
||||
}
|
||||
className={`${styles.optionButton} ${isSelected ? styles.optionButtonActive : ""}`}
|
||||
>
|
||||
{option.label}
|
||||
|
||||
+15
-53
@@ -8,6 +8,7 @@ import { useLocationStore } from "@store/Location.Store";
|
||||
import { useNavigation } from "@hooks/goto";
|
||||
import { useParams } from "next/navigation";
|
||||
import { useEffect } from "react";
|
||||
import { useBottomToolbarStore } from "@core/Store/BottomToolbar.Store";
|
||||
|
||||
type UrlData = {
|
||||
oid: string;
|
||||
@@ -19,11 +20,14 @@ export default function ClientProfile() {
|
||||
const clientId = data.clientId;
|
||||
|
||||
const location = useLocationStore();
|
||||
const bottomToolbar = useBottomToolbarStore();
|
||||
const { goTo } = useNavigation();
|
||||
|
||||
useEffect(() => {
|
||||
location.clear();
|
||||
|
||||
bottomToolbar.set(<></>);
|
||||
|
||||
location.add({
|
||||
url: "/admin/org",
|
||||
title: "Mis organizaciones",
|
||||
@@ -33,9 +37,7 @@ export default function ClientProfile() {
|
||||
location.add({
|
||||
url: "/admin/org/profile/" + oid,
|
||||
title: "Organizacion",
|
||||
icon: (
|
||||
<StorefrontOutlinedIcon sx={{ mr: 0.5 }} fontSize="inherit" />
|
||||
),
|
||||
icon: <StorefrontOutlinedIcon sx={{ mr: 0.5 }} fontSize="inherit" />,
|
||||
});
|
||||
|
||||
location.add({
|
||||
@@ -43,6 +45,10 @@ export default function ClientProfile() {
|
||||
title: "Perfil del cliente",
|
||||
icon: <ClientsIcon sx={{ fontSize: "32px", mr: "10px" }} />,
|
||||
});
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
@@ -59,79 +65,35 @@ export default function ClientProfile() {
|
||||
<ButtonOption
|
||||
text="Editar"
|
||||
icon="/profile-icon.svg"
|
||||
onClick={() =>
|
||||
goTo(
|
||||
"/admin/org/" +
|
||||
oid +
|
||||
"/client/" +
|
||||
clientId +
|
||||
"/edit"
|
||||
)
|
||||
}
|
||||
onClick={() => goTo("/admin/org/" + oid + "/client/" + clientId + "/edit")}
|
||||
/>
|
||||
<ButtonOption
|
||||
text="Turnos"
|
||||
icon="/profile-icon.svg"
|
||||
onClick={() =>
|
||||
goTo(
|
||||
"/admin/org/" +
|
||||
oid +
|
||||
"/client/" +
|
||||
clientId +
|
||||
"/appointments"
|
||||
)
|
||||
goTo("/admin/org/" + oid + "/client/" + clientId + "/appointments")
|
||||
}
|
||||
/>
|
||||
<ButtonOption
|
||||
text="Fusionar Duplicados"
|
||||
icon="/client-merge-icon.svg"
|
||||
onClick={() =>
|
||||
goTo(
|
||||
"/admin/org/" +
|
||||
oid +
|
||||
"/client/" +
|
||||
clientId +
|
||||
"/merge"
|
||||
)
|
||||
}
|
||||
onClick={() => goTo("/admin/org/" + oid + "/client/" + clientId + "/merge")}
|
||||
/>
|
||||
<ButtonOption
|
||||
text="Repeticiones"
|
||||
icon="/repeat-icon.svg"
|
||||
onClick={() =>
|
||||
goTo(
|
||||
"/admin/org/" +
|
||||
oid +
|
||||
"/client/" +
|
||||
clientId +
|
||||
"/repeats"
|
||||
)
|
||||
}
|
||||
onClick={() => goTo("/admin/org/" + oid + "/client/" + clientId + "/repeats")}
|
||||
/>
|
||||
<ButtonOption
|
||||
text="Cuenta"
|
||||
icon="/account-icon.svg"
|
||||
onClick={() =>
|
||||
goTo(
|
||||
"/admin/org/" +
|
||||
oid +
|
||||
"/client/" +
|
||||
clientId +
|
||||
"/account"
|
||||
)
|
||||
}
|
||||
onClick={() => goTo("/admin/org/" + oid + "/client/" + clientId + "/account")}
|
||||
/>
|
||||
<ButtonOption
|
||||
text="Notificaciones"
|
||||
icon="/notifications-icon.svg"
|
||||
onClick={() =>
|
||||
goTo(
|
||||
"/admin/org/" +
|
||||
oid +
|
||||
"/client/" +
|
||||
clientId +
|
||||
"/notifications"
|
||||
)
|
||||
goTo("/admin/org/" + oid + "/client/" + clientId + "/notifications")
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
+9
-1
@@ -17,6 +17,7 @@ import { deleteRepeat, getRepeatsByClient } from "../Client.Service";
|
||||
import { DeleteRepeatsParams, FindRepeatsParams, RepeatView } from "@core/Models/Repeats.model";
|
||||
|
||||
import style from "./repeats.module.css";
|
||||
import { useBottomToolbarStore } from "@core/Store/BottomToolbar.Store";
|
||||
|
||||
type UrlData = {
|
||||
oid: string;
|
||||
@@ -31,6 +32,7 @@ export default function ClientCreate() {
|
||||
const confirm = useConfirmStore();
|
||||
const SessionInfo = useSessionStore();
|
||||
const location = useLocationStore();
|
||||
const bottomToolbar = useBottomToolbarStore();
|
||||
const eventHandler = useEventHandlerStore();
|
||||
|
||||
const [repeats, setRepeats] = useState<RepeatView[]>([]);
|
||||
@@ -52,6 +54,8 @@ export default function ClientCreate() {
|
||||
useEffect(() => {
|
||||
location.clear();
|
||||
|
||||
bottomToolbar.set(<></>);
|
||||
|
||||
location.add({
|
||||
url: "/admin/org/profile/" + id + "/clients",
|
||||
title: "Clientes",
|
||||
@@ -69,6 +73,10 @@ export default function ClientCreate() {
|
||||
title: "Repeticiones",
|
||||
icon: <ClientsIcon sx={{ fontSize: "32px", mr: "10px" }} />,
|
||||
});
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -162,7 +170,7 @@ export default function ClientCreate() {
|
||||
() => {
|
||||
handleDelete(repeat.id);
|
||||
},
|
||||
() => {}
|
||||
() => {},
|
||||
);
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -27,6 +27,7 @@ import TextObjectFilter from "@components/TextObjectFilter/TextObjectFilter";
|
||||
import SelectLocationMap, {
|
||||
LocationCoordinates,
|
||||
} from "@core/app/components/SelectLocationMap/SelectLocationMap";
|
||||
import { useBottomToolbarStore } from "@core/Store/BottomToolbar.Store";
|
||||
|
||||
type UrlData = {
|
||||
id: string;
|
||||
@@ -36,6 +37,7 @@ export default function OrganizationEdit() {
|
||||
const data = useParams<UrlData>();
|
||||
const id = data.id;
|
||||
const location = useLocationStore();
|
||||
const bottomToolbar = useBottomToolbarStore();
|
||||
const eventHandler = useEventHandlerStore();
|
||||
const SessionInfo = useSessionStore();
|
||||
const alert = useAlert();
|
||||
@@ -140,7 +142,7 @@ export default function OrganizationEdit() {
|
||||
});
|
||||
|
||||
const [localidadesFilterData, setLocalidadesFilterData] = useState<TextObjectFilterResult[]>(
|
||||
[]
|
||||
[],
|
||||
);
|
||||
const [selectedLocalidad, setSelectedLocalidad] = useState<string>("");
|
||||
|
||||
@@ -188,6 +190,8 @@ export default function OrganizationEdit() {
|
||||
useEffect(() => {
|
||||
location.clear();
|
||||
|
||||
bottomToolbar.set(<></>);
|
||||
|
||||
location.add({
|
||||
url: "/admin/org",
|
||||
title: "Organizaciones",
|
||||
@@ -205,6 +209,10 @@ export default function OrganizationEdit() {
|
||||
title: "Ubicación",
|
||||
icon: <OrgConfigIcon sx={{ fontSize: "32px", mr: "10px" }} />,
|
||||
});
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -14,6 +14,7 @@ import Button from "@core/app/components/Button/Button";
|
||||
import { useConfirmStore } from "@core/Store/Confirm.Store";
|
||||
import { deleteOrganization } from "./advanced.Service";
|
||||
import { useNavigation } from "@core/app/hooks/goto";
|
||||
import { useBottomToolbarStore } from "@core/Store/BottomToolbar.Store";
|
||||
|
||||
type UrlData = {
|
||||
id: string;
|
||||
@@ -23,6 +24,7 @@ export default function OrganizationAdvancedEdit() {
|
||||
const data = useParams<UrlData>();
|
||||
const id = data.id;
|
||||
const location = useLocationStore();
|
||||
const bottomToolbar = useBottomToolbarStore();
|
||||
const eventHandler = useEventHandlerStore();
|
||||
const SessionInfo = useSessionStore();
|
||||
const alert = useAlert();
|
||||
@@ -33,6 +35,8 @@ export default function OrganizationAdvancedEdit() {
|
||||
useEffect(() => {
|
||||
location.clear();
|
||||
|
||||
bottomToolbar.set(<></>);
|
||||
|
||||
location.add({
|
||||
url: "/admin/org",
|
||||
title: "Organizaciones",
|
||||
@@ -50,6 +54,10 @@ export default function OrganizationAdvancedEdit() {
|
||||
title: "Avanzado",
|
||||
icon: <OrgConfigIcon sx={{ fontSize: "32px", mr: "10px" }} />,
|
||||
});
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const eliminarHandler = () => {
|
||||
@@ -73,7 +81,7 @@ export default function OrganizationAdvancedEdit() {
|
||||
},
|
||||
() => {
|
||||
eventHandler.setEventType(EVENT_TYPES.SLEEP);
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
alert.showError("La confirmación no es correcta");
|
||||
|
||||
@@ -12,6 +12,7 @@ import { UserAssistanceInfo } from "@core/Models/User.model";
|
||||
import Link from "next/link";
|
||||
import { getAssistanceUserInfo } from "./Assistance.Service";
|
||||
import AssistanceIcon from "@mui/icons-material/HeadsetMicOutlined";
|
||||
import { useBottomToolbarStore } from "@core/Store/BottomToolbar.Store";
|
||||
|
||||
type UrlData = {
|
||||
id: string;
|
||||
@@ -23,6 +24,7 @@ export default function CollaboratorsAdd() {
|
||||
const alert = useAlert();
|
||||
const eventHandler = useEventHandlerStore();
|
||||
const location = useLocationStore();
|
||||
const bottomToolbar = useBottomToolbarStore();
|
||||
const SessionInfo = useSessionStore();
|
||||
const [user, setUser] = useState<UserAssistanceInfo | null>(null);
|
||||
const [findEmail, setFindEmail] = useState<string>("");
|
||||
@@ -34,6 +36,8 @@ export default function CollaboratorsAdd() {
|
||||
useEffect(() => {
|
||||
location.clear();
|
||||
|
||||
bottomToolbar.set(<></>);
|
||||
|
||||
location.add({
|
||||
url: "/admin/org/profile/" + id,
|
||||
title: "Organizacion",
|
||||
@@ -45,6 +49,10 @@ export default function CollaboratorsAdd() {
|
||||
title: "Asistencia",
|
||||
icon: <AssistanceIcon sx={{ fontSize: "32px", mr: "10px" }} />,
|
||||
});
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const findUser = async () => {
|
||||
|
||||
@@ -10,6 +10,7 @@ import { CompanyEmployeesView } from "@models/Collaborators.model";
|
||||
import { loadCollaboratorsByCompanyId } from "./Collaborators.Service";
|
||||
import { useAlert } from "@store/Alert.Store";
|
||||
import CollaboratorItem from "@core/app/components/CollaboratorItem/CollaboratorItem";
|
||||
import { useBottomToolbarStore } from "@core/Store/BottomToolbar.Store";
|
||||
|
||||
type UrlData = {
|
||||
id: string;
|
||||
@@ -19,6 +20,7 @@ export default function OrganizationProfile() {
|
||||
const data = useParams<UrlData>();
|
||||
const id = data.id;
|
||||
const location = useLocationStore();
|
||||
const bottomToolbar = useBottomToolbarStore();
|
||||
const eventHandler = useEventHandlerStore();
|
||||
const alert = useAlert();
|
||||
const { goTo } = useNavigation();
|
||||
@@ -31,6 +33,8 @@ export default function OrganizationProfile() {
|
||||
useEffect(() => {
|
||||
location.clear();
|
||||
|
||||
bottomToolbar.set(<></>);
|
||||
|
||||
location.add({
|
||||
url: "/admin/org",
|
||||
title: "Mis organizaciones",
|
||||
@@ -60,6 +64,10 @@ export default function OrganizationProfile() {
|
||||
.finally(() => {
|
||||
eventHandler.setEventType(EVENT_TYPES.NEED_ADD);
|
||||
});
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleCollaboratorClick = (collaboratorId: string) => {
|
||||
|
||||
+17
-5
@@ -35,6 +35,7 @@ import TextObjectFilterItem from "@core/app/components/TextObjectFilterItem/Text
|
||||
import TextObjectFilter from "@core/app/components/TextObjectFilter/TextObjectFilter";
|
||||
import { useFilterStore } from "@core/Store/Filter.Store";
|
||||
import filterObjects from "@components/TextObjectFilter/Filter.Service";
|
||||
import { useBottomToolbarStore } from "@core/Store/BottomToolbar.Store";
|
||||
|
||||
type UrlData = {
|
||||
id: string;
|
||||
@@ -112,6 +113,7 @@ export default function DiscountsEmailGrid() {
|
||||
const data = useParams<UrlData>();
|
||||
const oid = data.id;
|
||||
const location = useLocationStore();
|
||||
const bottomToolbar = useBottomToolbarStore();
|
||||
const SessionInfo = useSessionStore();
|
||||
const eventHandler = useEventHandlerStore();
|
||||
const alert = useAlert();
|
||||
@@ -151,7 +153,9 @@ export default function DiscountsEmailGrid() {
|
||||
render: (value: DiscountEmailRow) => (
|
||||
<div style={{ paddingBottom: "10px" }}>
|
||||
<div>
|
||||
<div style={{ paddingLeft: "10px", paddingTop: "10px", fontWeight: "bold" }}>
|
||||
<div
|
||||
style={{ paddingLeft: "10px", paddingTop: "10px", fontWeight: "bold" }}
|
||||
>
|
||||
{value.discountName + " (" + value.discountCode + ")"}
|
||||
</div>
|
||||
<div style={{ paddingLeft: "10px", paddingTop: "0px", fontWeight: "bold" }}>
|
||||
@@ -206,8 +210,10 @@ export default function DiscountsEmailGrid() {
|
||||
|
||||
const [pageSize] = useState<number>(
|
||||
parseInt(
|
||||
process.env.NEXT_PUBLIC_DATAGRID_PAGE_SIZE ? process.env.NEXT_PUBLIC_DATAGRID_PAGE_SIZE : "10"
|
||||
)
|
||||
process.env.NEXT_PUBLIC_DATAGRID_PAGE_SIZE
|
||||
? process.env.NEXT_PUBLIC_DATAGRID_PAGE_SIZE
|
||||
: "10",
|
||||
),
|
||||
);
|
||||
const [discounts, setDiscounts] = useState<PaginateDiscountsEmailViewResults>();
|
||||
const discountsRef = useRef(discounts);
|
||||
@@ -219,6 +225,8 @@ export default function DiscountsEmailGrid() {
|
||||
useEffect(() => {
|
||||
location.clear();
|
||||
|
||||
bottomToolbar.set(<></>);
|
||||
|
||||
location.add({
|
||||
url: "/admin/org",
|
||||
title: "Mis organizaciones",
|
||||
@@ -238,6 +246,10 @@ export default function DiscountsEmailGrid() {
|
||||
});
|
||||
|
||||
loadDiscountsEmail(1, pageSize);
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -267,7 +279,7 @@ export default function DiscountsEmailGrid() {
|
||||
setDiscountId={setDiscountId}
|
||||
filterEmail={filterEmail}
|
||||
setFilterEmail={setFilterEmail}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
filter.setOnFilter(() => {
|
||||
setSearchByFilters(true);
|
||||
@@ -327,7 +339,7 @@ export default function DiscountsEmailGrid() {
|
||||
alert.showError(err.format());
|
||||
});
|
||||
},
|
||||
() => {}
|
||||
() => {},
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import turnosXpressTheme from "@core/app/theme/turnosXpress";
|
||||
import { ButtonGroup } from "@mui/material";
|
||||
import ButtonMaterial from "@mui/material/Button";
|
||||
import { useNavigation } from "@core/app/hooks/goto";
|
||||
import { useBottomToolbarStore } from "@core/Store/BottomToolbar.Store";
|
||||
|
||||
type UrlData = {
|
||||
id: string;
|
||||
@@ -33,6 +34,7 @@ export default function DiscountsGrid() {
|
||||
const data = useParams<UrlData>();
|
||||
const oid = data.id;
|
||||
const location = useLocationStore();
|
||||
const bottomToolbar = useBottomToolbarStore();
|
||||
const eventHandler = useEventHandlerStore();
|
||||
|
||||
const { goTo } = useNavigation();
|
||||
@@ -67,7 +69,9 @@ export default function DiscountsGrid() {
|
||||
color: "var(--green-darkestX2)",
|
||||
}}
|
||||
>
|
||||
{value.type === DiscountType.FIXED ? formatPrice(value.value) : value.value + "%"}
|
||||
{value.type === DiscountType.FIXED
|
||||
? formatPrice(value.value)
|
||||
: value.value + "%"}
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
@@ -76,8 +80,10 @@ export default function DiscountsGrid() {
|
||||
|
||||
const [pageSize] = useState<number>(
|
||||
parseInt(
|
||||
process.env.NEXT_PUBLIC_DATAGRID_PAGE_SIZE ? process.env.NEXT_PUBLIC_DATAGRID_PAGE_SIZE : "10"
|
||||
)
|
||||
process.env.NEXT_PUBLIC_DATAGRID_PAGE_SIZE
|
||||
? process.env.NEXT_PUBLIC_DATAGRID_PAGE_SIZE
|
||||
: "10",
|
||||
),
|
||||
);
|
||||
const [discounts, setDiscounts] = useState<PaginateDiscountsResults>();
|
||||
|
||||
@@ -88,6 +94,8 @@ export default function DiscountsGrid() {
|
||||
useEffect(() => {
|
||||
location.clear();
|
||||
|
||||
bottomToolbar.set(<></>);
|
||||
|
||||
location.add({
|
||||
url: "/admin/org",
|
||||
title: "Mis organizaciones",
|
||||
@@ -107,6 +115,10 @@ export default function DiscountsGrid() {
|
||||
});
|
||||
|
||||
loadDiscounts(1, pageSize);
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const loadDiscounts = (page: number = 1, pageSize: number = 30) => {
|
||||
|
||||
@@ -38,6 +38,7 @@ import Switch from "@core/app/components/Switch/Switch";
|
||||
import { FindTemplatesParams } from "@core/Models/Templates.model";
|
||||
import filterObjects from "@core/app/components/TextObjectFilter/Filter.Service";
|
||||
import { CompanyServiceView } from "@models/Service.model";
|
||||
import { useBottomToolbarStore } from "@core/Store/BottomToolbar.Store";
|
||||
|
||||
type UrlData = {
|
||||
id: string;
|
||||
@@ -47,6 +48,7 @@ export default function OrganizationEdit() {
|
||||
const data = useParams<UrlData>();
|
||||
const id = data.id;
|
||||
const location = useLocationStore();
|
||||
const bottomToolbar = useBottomToolbarStore();
|
||||
const eventHandler = useEventHandlerStore();
|
||||
const SessionInfo = useSessionStore();
|
||||
const alert = useAlert();
|
||||
@@ -66,11 +68,12 @@ export default function OrganizationEdit() {
|
||||
const [servicesShowPublicScores, setServicesShowPublicScores] = useState(true);
|
||||
const [servicesShowPublicOpinions, setServicesShowPublicOpinions] = useState(true);
|
||||
const [originalServicesShowPublicScores, setOriginalServicesShowPublicScores] = useState(true);
|
||||
const [originalServicesShowPublicOpinions, setOriginalServicesShowPublicOpinions] = useState(true);
|
||||
const [originalServicesShowPublicOpinions, setOriginalServicesShowPublicOpinions] =
|
||||
useState(true);
|
||||
const [services, setServices] = useState<CompanyServiceView[]>([]);
|
||||
|
||||
const [orgPublished, setOrgPublished] = useState<COMPANY_PUBLISHED_STATUS | undefined>(
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
|
||||
const [savePublishedStatusAvailable, setSavePublishedStatusAvailable] = useState(false);
|
||||
@@ -199,6 +202,8 @@ export default function OrganizationEdit() {
|
||||
useEffect(() => {
|
||||
location.clear();
|
||||
|
||||
bottomToolbar.set(<></>);
|
||||
|
||||
location.add({
|
||||
url: "/admin/org",
|
||||
title: "Organizaciones",
|
||||
@@ -218,6 +223,10 @@ export default function OrganizationEdit() {
|
||||
});
|
||||
|
||||
loadCategories();
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -241,25 +250,33 @@ export default function OrganizationEdit() {
|
||||
setCategoryId(organization.categoryId.toString());
|
||||
setOrgSlug(getSlug(organization.name));
|
||||
setOrgPublished(organization.published);
|
||||
setShowPublicScores(organization.showPublicScores !== undefined ? organization.showPublicScores : true);
|
||||
setShowPublicOpinions(organization.showPublicOpinions !== undefined ? organization.showPublicOpinions : true);
|
||||
setShowPublicScores(
|
||||
organization.showPublicScores !== undefined
|
||||
? organization.showPublicScores
|
||||
: true,
|
||||
);
|
||||
setShowPublicOpinions(
|
||||
organization.showPublicOpinions !== undefined
|
||||
? organization.showPublicOpinions
|
||||
: true,
|
||||
);
|
||||
setShowPublicProfessionals(
|
||||
organization.showPublicProfessionals !== undefined
|
||||
? organization.showPublicProfessionals
|
||||
: true
|
||||
: true,
|
||||
);
|
||||
setServices(loadedServices);
|
||||
setServicesShowPublicScores(
|
||||
loadedServices.every((service) => service.showPublicScores !== false)
|
||||
loadedServices.every((service) => service.showPublicScores !== false),
|
||||
);
|
||||
setServicesShowPublicOpinions(
|
||||
loadedServices.every((service) => service.showPublicOpinions !== false)
|
||||
loadedServices.every((service) => service.showPublicOpinions !== false),
|
||||
);
|
||||
setOriginalServicesShowPublicScores(
|
||||
loadedServices.every((service) => service.showPublicScores !== false)
|
||||
loadedServices.every((service) => service.showPublicScores !== false),
|
||||
);
|
||||
setOriginalServicesShowPublicOpinions(
|
||||
loadedServices.every((service) => service.showPublicOpinions !== false)
|
||||
loadedServices.every((service) => service.showPublicOpinions !== false),
|
||||
);
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
@@ -287,7 +304,7 @@ export default function OrganizationEdit() {
|
||||
confirm.show(
|
||||
validationPhoneResult.message,
|
||||
() => {},
|
||||
() => {}
|
||||
() => {},
|
||||
);
|
||||
eventHandler.setEventType(EVENT_TYPES.SLEEP);
|
||||
return;
|
||||
@@ -307,7 +324,8 @@ export default function OrganizationEdit() {
|
||||
phoneNumber: phone,
|
||||
templateWapNotifId: templateWapNotifId === "" ? undefined : templateWapNotifId,
|
||||
templateWapAltaId: templateWapAltaId === "" ? undefined : templateWapAltaId,
|
||||
templateWapCancellationId: templateWapCancellationId === "" ? undefined : templateWapCancellationId,
|
||||
templateWapCancellationId:
|
||||
templateWapCancellationId === "" ? undefined : templateWapCancellationId,
|
||||
...(canEditPublicVisibilityFlags
|
||||
? {
|
||||
showPublicScores,
|
||||
@@ -321,31 +339,31 @@ export default function OrganizationEdit() {
|
||||
id: Yup.string().required("En este momento no es posible procesar su solicitud."),
|
||||
name: Yup.string().required("Debe introducir el nombre de la organización."),
|
||||
description: Yup.string().required(
|
||||
"Debe introducir la descripción de la organización."
|
||||
"Debe introducir la descripción de la organización.",
|
||||
),
|
||||
categoryId: Yup.number().required(
|
||||
"Debe seleccionar una categoría para la organización."
|
||||
"Debe seleccionar una categoría para la organización.",
|
||||
),
|
||||
phoneAreaCode: Yup.number()
|
||||
.typeError("Código de área debe ser un número.")
|
||||
.transform((value, originalValue) =>
|
||||
originalValue.toString().trim() === "" ? null : value
|
||||
originalValue.toString().trim() === "" ? null : value,
|
||||
)
|
||||
.nullable(),
|
||||
phoneNumber: Yup.number()
|
||||
.typeError("El teléfono debe ser un número.")
|
||||
.transform((value, originalValue) =>
|
||||
originalValue.toString().trim() === "" ? null : value
|
||||
originalValue.toString().trim() === "" ? null : value,
|
||||
)
|
||||
.nullable(),
|
||||
appointmentAlert: Yup.string().optional().default(""),
|
||||
sessionUser: Yup.string().required(
|
||||
"Para crear una organización debe iniciar sesión."
|
||||
"Para crear una organización debe iniciar sesión.",
|
||||
),
|
||||
heatMapFraction: Yup.number()
|
||||
.typeError("Fracción de tiempo debe ser un número.")
|
||||
.transform((value, originalValue) =>
|
||||
originalValue.toString().trim() === "" ? null : value
|
||||
originalValue.toString().trim() === "" ? null : value,
|
||||
)
|
||||
.nullable()
|
||||
.integer("Fracción de tiempo debe ser un número entero en minutos.")
|
||||
@@ -354,7 +372,7 @@ export default function OrganizationEdit() {
|
||||
appointmentTime: Yup.number()
|
||||
.typeError("El Plazo Mínimo de Reserva debe ser un número.")
|
||||
.transform((value, originalValue) =>
|
||||
originalValue.toString().trim() === "" ? null : value
|
||||
originalValue.toString().trim() === "" ? null : value,
|
||||
)
|
||||
.nullable()
|
||||
.integer("El Plazo Mínimo de Reserva debe ser un número entero en horas.")
|
||||
@@ -362,7 +380,7 @@ export default function OrganizationEdit() {
|
||||
cancellationTime: Yup.number()
|
||||
.typeError("El Plazo Mínimo de Cancelación debe ser un número.")
|
||||
.transform((value, originalValue) =>
|
||||
originalValue.toString().trim() === "" ? null : value
|
||||
originalValue.toString().trim() === "" ? null : value,
|
||||
)
|
||||
.nullable()
|
||||
.integer("El Plazo Mínimo de Cancelación debe ser un número entero en horas.")
|
||||
@@ -386,7 +404,8 @@ export default function OrganizationEdit() {
|
||||
originalServicesShowPublicOpinions !== servicesShowPublicOpinions;
|
||||
const changedServices =
|
||||
canEditPublicVisibilityFlags &&
|
||||
(servicesShowPublicScoresChanged || servicesShowPublicOpinionsChanged)
|
||||
(servicesShowPublicScoresChanged ||
|
||||
servicesShowPublicOpinionsChanged)
|
||||
? services
|
||||
: [];
|
||||
|
||||
@@ -414,8 +433,8 @@ export default function OrganizationEdit() {
|
||||
: service.showPublicOpinions !== undefined
|
||||
? service.showPublicOpinions
|
||||
: true,
|
||||
})
|
||||
)
|
||||
}),
|
||||
),
|
||||
).then(() => {
|
||||
const updatedServices = services.map((service) => ({
|
||||
...service,
|
||||
@@ -434,7 +453,9 @@ export default function OrganizationEdit() {
|
||||
});
|
||||
})
|
||||
.catch((error: ApiError | Error) => {
|
||||
alert.showError(error instanceof ApiError ? error.format() : error.message);
|
||||
alert.showError(
|
||||
error instanceof ApiError ? error.format() : error.message,
|
||||
);
|
||||
})
|
||||
.finally(() => {
|
||||
eventHandler.setEventType(EVENT_TYPES.SLEEP);
|
||||
@@ -453,7 +474,7 @@ export default function OrganizationEdit() {
|
||||
id: category.id.toString(),
|
||||
name: category.name,
|
||||
description: category.description,
|
||||
}))
|
||||
})),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -533,7 +554,7 @@ export default function OrganizationEdit() {
|
||||
setOrgPublished(
|
||||
checked
|
||||
? COMPANY_PUBLISHED_STATUS.PUBLISHED
|
||||
: COMPANY_PUBLISHED_STATUS.PRIVATE
|
||||
: COMPANY_PUBLISHED_STATUS.PRIVATE,
|
||||
);
|
||||
}}
|
||||
/>
|
||||
@@ -581,15 +602,23 @@ export default function OrganizationEdit() {
|
||||
/>
|
||||
|
||||
<MaterialAlert severity="info" sx={{ marginTop: "20px" }}>
|
||||
<b>Visibilidad pública:</b> Elegí si querés mostrar puntuaciones, opiniones y profesionales en el perfil público y las páginas de reserva. Disponible para planes pagos.
|
||||
<b>Visibilidad pública:</b> Elegí si querés mostrar puntuaciones, opiniones y
|
||||
profesionales en el perfil público y las páginas de reserva. Disponible para planes
|
||||
pagos.
|
||||
</MaterialAlert>
|
||||
{!canEditPublicVisibilityFlags && (
|
||||
<MaterialAlert severity="warning" sx={{ marginTop: "10px" }}>
|
||||
Para modificar las opciones de visibilidad pública de opiniones, puntuaciones y profesionales de esta organización y sus servicios, el propietario de la organización necesita un plan pago.
|
||||
Para modificar las opciones de visibilidad pública de opiniones, puntuaciones y
|
||||
profesionales de esta organización y sus servicios, el propietario de la
|
||||
organización necesita un plan pago.
|
||||
</MaterialAlert>
|
||||
)}
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: "10px", marginTop: "10px" }}>
|
||||
<label style={{ display: "flex", alignItems: "center", gap: "10px", fontWeight: 600 }}>
|
||||
<div
|
||||
style={{ display: "flex", flexDirection: "column", gap: "10px", marginTop: "10px" }}
|
||||
>
|
||||
<label
|
||||
style={{ display: "flex", alignItems: "center", gap: "10px", fontWeight: 600 }}
|
||||
>
|
||||
<Checkbox
|
||||
checked={showPublicScores}
|
||||
disabled={!canEditPublicVisibilityFlags}
|
||||
@@ -600,7 +629,9 @@ export default function OrganizationEdit() {
|
||||
/>
|
||||
Mostrar puntuaciones públicas
|
||||
</label>
|
||||
<label style={{ display: "flex", alignItems: "center", gap: "10px", fontWeight: 600 }}>
|
||||
<label
|
||||
style={{ display: "flex", alignItems: "center", gap: "10px", fontWeight: 600 }}
|
||||
>
|
||||
<Checkbox
|
||||
checked={showPublicOpinions}
|
||||
disabled={!canEditPublicVisibilityFlags}
|
||||
@@ -611,7 +642,9 @@ export default function OrganizationEdit() {
|
||||
/>
|
||||
Mostrar opiniones públicas
|
||||
</label>
|
||||
<label style={{ display: "flex", alignItems: "center", gap: "10px", fontWeight: 600 }}>
|
||||
<label
|
||||
style={{ display: "flex", alignItems: "center", gap: "10px", fontWeight: 600 }}
|
||||
>
|
||||
<Checkbox
|
||||
checked={showPublicProfessionals}
|
||||
disabled={!canEditPublicVisibilityFlags}
|
||||
@@ -632,7 +665,9 @@ export default function OrganizationEdit() {
|
||||
{services.length > 0 && (
|
||||
<>
|
||||
<MaterialAlert severity="info" sx={{ marginTop: "20px" }}>
|
||||
<b>Visibilidad pública de servicios:</b> Configurá si se muestran puntuaciones y opiniones en todos los servicios. Disponible para planes pagos.
|
||||
<b>Visibilidad pública de servicios:</b> Configurá si se muestran
|
||||
puntuaciones y opiniones en todos los servicios. Disponible para planes
|
||||
pagos.
|
||||
</MaterialAlert>
|
||||
<div
|
||||
style={{
|
||||
@@ -642,7 +677,14 @@ export default function OrganizationEdit() {
|
||||
marginTop: "10px",
|
||||
}}
|
||||
>
|
||||
<label style={{ display: "flex", alignItems: "center", gap: "10px", fontWeight: 600 }}>
|
||||
<label
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "10px",
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
<Checkbox
|
||||
checked={servicesShowPublicScores}
|
||||
disabled={!canEditPublicVisibilityFlags}
|
||||
@@ -653,7 +695,14 @@ export default function OrganizationEdit() {
|
||||
/>
|
||||
Mostrar puntuaciones públicas de los servicios
|
||||
</label>
|
||||
<label style={{ display: "flex", alignItems: "center", gap: "10px", fontWeight: 600 }}>
|
||||
<label
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "10px",
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
<Checkbox
|
||||
checked={servicesShowPublicOpinions}
|
||||
disabled={!canEditPublicVisibilityFlags}
|
||||
@@ -666,7 +715,8 @@ export default function OrganizationEdit() {
|
||||
</label>
|
||||
{!canEditPublicVisibilityFlags && (
|
||||
<span style={{ color: "var(--gray-darkest)", fontSize: "13px" }}>
|
||||
Para cambiar la visibilidad pública de los servicios necesitás un plan pago.
|
||||
Para cambiar la visibilidad pública de los servicios necesitás un
|
||||
plan pago.
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
OrganizationFiscalProfileTaxCondition,
|
||||
upsertOrganizationFiscalProfile,
|
||||
} from "./Fiscal.Service";
|
||||
import { useBottomToolbarStore } from "@core/Store/BottomToolbar.Store";
|
||||
|
||||
type UrlData = {
|
||||
id: string;
|
||||
@@ -33,13 +34,15 @@ export default function OrganizationFiscalProfileEdit() {
|
||||
const data = useParams<UrlData>();
|
||||
const id = data.id;
|
||||
const location = useLocationStore();
|
||||
const bottomToolbar = useBottomToolbarStore();
|
||||
const eventHandler = useEventHandlerStore();
|
||||
const SessionInfo = useSessionStore();
|
||||
const alert = useAlert();
|
||||
|
||||
const [cuit, setCuit] = useState("");
|
||||
const [legalName, setLegalName] = useState("");
|
||||
const [taxCondition, setTaxCondition] = useState<OrganizationFiscalProfileTaxCondition>("MONOTRIBUTO");
|
||||
const [taxCondition, setTaxCondition] =
|
||||
useState<OrganizationFiscalProfileTaxCondition>("MONOTRIBUTO");
|
||||
const [pointOfSale, setPointOfSale] = useState("1");
|
||||
const [activityCode, setActivityCode] = useState("");
|
||||
const [activityDescription, setActivityDescription] = useState("");
|
||||
@@ -80,6 +83,8 @@ export default function OrganizationFiscalProfileEdit() {
|
||||
useEffect(() => {
|
||||
location.clear();
|
||||
|
||||
bottomToolbar.clear();
|
||||
|
||||
location.add({
|
||||
url: "/admin/org",
|
||||
title: "Organizaciones",
|
||||
@@ -97,6 +102,10 @@ export default function OrganizationFiscalProfileEdit() {
|
||||
title: "Datos fiscales",
|
||||
icon: <ReceiptLongOutlinedIcon sx={{ fontSize: "32px", mr: "10px" }} />,
|
||||
});
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -118,7 +127,9 @@ export default function OrganizationFiscalProfileEdit() {
|
||||
setLegalName(profile.legalName || "");
|
||||
setTaxCondition(profile.taxCondition || "MONOTRIBUTO");
|
||||
setPointOfSale(profile.pointOfSale ? String(profile.pointOfSale) : "1");
|
||||
const profileActivity = activities.find((activity) => activity.id === profile.activityCode);
|
||||
const profileActivity = activities.find(
|
||||
(activity) => activity.id === profile.activityCode,
|
||||
);
|
||||
setActivityCode(profile.activityCode || "");
|
||||
setActivityDescription(profile.activityDescription || profileActivity?.name || "");
|
||||
})
|
||||
@@ -152,7 +163,10 @@ export default function OrganizationFiscalProfileEdit() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (activityCode.trim() && !arcaActivities.some((activity) => activity.id === activityCode.trim())) {
|
||||
if (
|
||||
activityCode.trim() &&
|
||||
!arcaActivities.some((activity) => activity.id === activityCode.trim())
|
||||
) {
|
||||
alert.showError("Seleccioná una actividad ARCA/CLAE válida.");
|
||||
eventHandler.setEventType(EVENT_TYPES.NEED_SAVE);
|
||||
return;
|
||||
@@ -160,7 +174,9 @@ export default function OrganizationFiscalProfileEdit() {
|
||||
|
||||
eventHandler.setEventType(EVENT_TYPES.LOADING);
|
||||
|
||||
const selectedActivity = arcaActivities.find((activity) => activity.id === activityCode.trim());
|
||||
const selectedActivity = arcaActivities.find(
|
||||
(activity) => activity.id === activityCode.trim(),
|
||||
);
|
||||
|
||||
upsertOrganizationFiscalProfile({
|
||||
companyId: id,
|
||||
@@ -173,7 +189,9 @@ export default function OrganizationFiscalProfileEdit() {
|
||||
sessionUser: SessionInfo.userId,
|
||||
})
|
||||
.then((profile) => {
|
||||
const savedActivity = arcaActivities.find((activity) => activity.id === profile.activityCode);
|
||||
const savedActivity = arcaActivities.find(
|
||||
(activity) => activity.id === profile.activityCode,
|
||||
);
|
||||
setActivityCode(profile.activityCode || "");
|
||||
setActivityDescription(profile.activityDescription || savedActivity?.name || "");
|
||||
alert.showSuccess("Datos fiscales actualizados.");
|
||||
@@ -198,7 +216,8 @@ export default function OrganizationFiscalProfileEdit() {
|
||||
<div>
|
||||
<h2>Configuración fiscal</h2>
|
||||
<p>
|
||||
Estos datos se usan para emitir Factura C desde los movimientos de caja y para precargar el asistente ARCA.
|
||||
Estos datos se usan para emitir Factura C desde los movimientos de
|
||||
caja y para precargar el asistente ARCA.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
@@ -206,32 +225,32 @@ export default function OrganizationFiscalProfileEdit() {
|
||||
<section className={style.formSection}>
|
||||
<h3>Datos del emisor</h3>
|
||||
<Grid2 container spacing={2}>
|
||||
<Grid2 size={{ xs: 12, sm: 6 }}>
|
||||
<Textbox
|
||||
name="cuit"
|
||||
placeholder="CUIT"
|
||||
type="text"
|
||||
value={cuit}
|
||||
width="100%"
|
||||
onChange={(event) => {
|
||||
setCuit(event.target.value.replace(/\D/g, ""));
|
||||
markNeedsSave();
|
||||
}}
|
||||
/>
|
||||
</Grid2>
|
||||
<Grid2 size={{ xs: 12, sm: 6 }}>
|
||||
<Textbox
|
||||
name="legalName"
|
||||
placeholder="Razón social"
|
||||
type="text"
|
||||
value={legalName}
|
||||
width="100%"
|
||||
onChange={(event) => {
|
||||
setLegalName(event.target.value);
|
||||
markNeedsSave();
|
||||
}}
|
||||
/>
|
||||
</Grid2>
|
||||
<Grid2 size={{ xs: 12, sm: 6 }}>
|
||||
<Textbox
|
||||
name="cuit"
|
||||
placeholder="CUIT"
|
||||
type="text"
|
||||
value={cuit}
|
||||
width="100%"
|
||||
onChange={(event) => {
|
||||
setCuit(event.target.value.replace(/\D/g, ""));
|
||||
markNeedsSave();
|
||||
}}
|
||||
/>
|
||||
</Grid2>
|
||||
<Grid2 size={{ xs: 12, sm: 6 }}>
|
||||
<Textbox
|
||||
name="legalName"
|
||||
placeholder="Razón social"
|
||||
type="text"
|
||||
value={legalName}
|
||||
width="100%"
|
||||
onChange={(event) => {
|
||||
setLegalName(event.target.value);
|
||||
markNeedsSave();
|
||||
}}
|
||||
/>
|
||||
</Grid2>
|
||||
</Grid2>
|
||||
</section>
|
||||
|
||||
@@ -240,7 +259,11 @@ export default function OrganizationFiscalProfileEdit() {
|
||||
<h3>Condición fiscal</h3>
|
||||
<p>Seleccioná la condición declarada para esta organización.</p>
|
||||
</div>
|
||||
<div className={style.optionGroup} role="radiogroup" aria-label="Condición fiscal">
|
||||
<div
|
||||
className={style.optionGroup}
|
||||
role="radiogroup"
|
||||
aria-label="Condición fiscal"
|
||||
>
|
||||
{fiscalConditionOptions.map((option) => {
|
||||
const selected = taxCondition === option.id;
|
||||
|
||||
@@ -256,7 +279,9 @@ export default function OrganizationFiscalProfileEdit() {
|
||||
aria-pressed={selected}
|
||||
>
|
||||
<span className={style.optionTitle}>{option.title}</span>
|
||||
<span className={style.optionDescription}>{option.description}</span>
|
||||
<span className={style.optionDescription}>
|
||||
{option.description}
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
@@ -266,19 +291,19 @@ export default function OrganizationFiscalProfileEdit() {
|
||||
<section className={style.formSection}>
|
||||
<h3>Facturación ARCA</h3>
|
||||
<Grid2 container spacing={2}>
|
||||
<Grid2 size={{ xs: 12, sm: 6 }}>
|
||||
<Textbox
|
||||
name="pointOfSale"
|
||||
placeholder="Punto de venta"
|
||||
type="text"
|
||||
value={pointOfSale}
|
||||
width="100%"
|
||||
onChange={(event) => {
|
||||
setPointOfSale(event.target.value.replace(/\D/g, ""));
|
||||
markNeedsSave();
|
||||
}}
|
||||
/>
|
||||
</Grid2>
|
||||
<Grid2 size={{ xs: 12, sm: 6 }}>
|
||||
<Textbox
|
||||
name="pointOfSale"
|
||||
placeholder="Punto de venta"
|
||||
type="text"
|
||||
value={pointOfSale}
|
||||
width="100%"
|
||||
onChange={(event) => {
|
||||
setPointOfSale(event.target.value.replace(/\D/g, ""));
|
||||
markNeedsSave();
|
||||
}}
|
||||
/>
|
||||
</Grid2>
|
||||
</Grid2>
|
||||
|
||||
{fiscalDataLoaded && (
|
||||
@@ -290,7 +315,7 @@ export default function OrganizationFiscalProfileEdit() {
|
||||
selectedId={activityCode}
|
||||
onChange={(selectedActivityCode) => {
|
||||
const selectedActivity = arcaActivities.find(
|
||||
(activity) => activity.id === selectedActivityCode
|
||||
(activity) => activity.id === selectedActivityCode,
|
||||
);
|
||||
|
||||
setActivityCode(selectedActivity?.id || "");
|
||||
|
||||
+64
-22
@@ -13,6 +13,7 @@ import StorefrontOutlinedIcon from "@mui/icons-material/StorefrontOutlined";
|
||||
import NotificationsIcon from "@mui/icons-material/NotificationsOutlined";
|
||||
import MaterialAlert from "@mui/material/Alert";
|
||||
import dayjs from "dayjs";
|
||||
import { useBottomToolbarStore } from "@core/Store/BottomToolbar.Store";
|
||||
|
||||
type UrlData = {
|
||||
id: string;
|
||||
@@ -21,7 +22,7 @@ type UrlData = {
|
||||
const CHANNELS: { key: NotificationChannel; label: string }[] = [
|
||||
{ key: "whatsapp", label: "WhatsApp" },
|
||||
{ key: "email", label: "Email" },
|
||||
{ key: "system", label: "Sistema" }
|
||||
{ key: "system", label: "Sistema" },
|
||||
];
|
||||
|
||||
const REMINDER_PRESETS: { minutes: number; label: string }[] = [
|
||||
@@ -30,36 +31,43 @@ const REMINDER_PRESETS: { minutes: number; label: string }[] = [
|
||||
{ minutes: 360, label: "6 horas antes" },
|
||||
{ minutes: 720, label: "12 horas antes" },
|
||||
{ minutes: 1440, label: "1 día antes" },
|
||||
{ minutes: 2880, label: "2 días antes" }
|
||||
{ minutes: 2880, label: "2 días antes" },
|
||||
];
|
||||
|
||||
export default function NotificationsPage() {
|
||||
const data = useParams<UrlData>();
|
||||
const id = data.id;
|
||||
const location = useLocationStore();
|
||||
const bottomToolbar = useBottomToolbarStore();
|
||||
const store = useNotificationPreferencesStore();
|
||||
const eventHandler = useEventHandlerStore();
|
||||
|
||||
useEffect(() => {
|
||||
location.clear();
|
||||
|
||||
bottomToolbar.set(<></>);
|
||||
|
||||
location.add({
|
||||
url: "/admin/org",
|
||||
title: "Organizaciones",
|
||||
icon: null
|
||||
icon: null,
|
||||
});
|
||||
|
||||
location.add({
|
||||
url: "/admin/org/profile/" + id,
|
||||
title: "Perfil",
|
||||
icon: <StorefrontOutlinedIcon sx={{ mr: 0.5 }} fontSize="inherit" />
|
||||
icon: <StorefrontOutlinedIcon sx={{ mr: 0.5 }} fontSize="inherit" />,
|
||||
});
|
||||
|
||||
location.add({
|
||||
url: "/admin/org/profile/" + id + "/notifications",
|
||||
title: "Notificaciones",
|
||||
icon: <NotificationsIcon sx={{ fontSize: "32px", mr: "10px" }} />
|
||||
icon: <NotificationsIcon sx={{ fontSize: "32px", mr: "10px" }} />,
|
||||
});
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, [id]);
|
||||
|
||||
const toggleChannel = (channel: NotificationChannel) => {
|
||||
@@ -73,18 +81,22 @@ export default function NotificationsPage() {
|
||||
const updateQuietHours = (field: "from" | "to", value: string) => {
|
||||
const current = store.formData.quietHours || { from: "00:00", to: "00:00" };
|
||||
store.updateFormData({
|
||||
quietHours: { ...current, [field]: value }
|
||||
quietHours: { ...current, [field]: value },
|
||||
});
|
||||
};
|
||||
|
||||
const quietHourValue = (value: string | undefined, fallback: string) => {
|
||||
const [hour, minute] = (value || fallback).split(":").map(Number);
|
||||
return dayjs(new Date()).hour(hour).minute(minute || 0).second(0).millisecond(0);
|
||||
return dayjs(new Date())
|
||||
.hour(hour)
|
||||
.minute(minute || 0)
|
||||
.second(0)
|
||||
.millisecond(0);
|
||||
};
|
||||
|
||||
const toggleQuietHours = () => {
|
||||
store.updateFormData({
|
||||
quietHours: store.formData.quietHours ? null : { from: "22:00", to: "08:00" }
|
||||
quietHours: store.formData.quietHours ? null : { from: "22:00", to: "08:00" },
|
||||
});
|
||||
};
|
||||
|
||||
@@ -95,7 +107,10 @@ export default function NotificationsPage() {
|
||||
store.updateFormData({ reminderRules: updated });
|
||||
} else {
|
||||
store.updateFormData({
|
||||
reminderRules: [...store.formData.reminderRules, { offset: minutes, enabled: true }]
|
||||
reminderRules: [
|
||||
...store.formData.reminderRules,
|
||||
{ offset: minutes, enabled: true },
|
||||
],
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -107,10 +122,18 @@ export default function NotificationsPage() {
|
||||
<div style={{ marginTop: "20px" }}>
|
||||
{/* Channel Toggles Section */}
|
||||
<MaterialAlert severity="info" sx={{ marginBottom: "20px" }}>
|
||||
<b>Canales de notificación:</b> Seleccione los canales por los cuales se enviarán las notificaciones automáticas.
|
||||
<b>Canales de notificación:</b> Seleccione los canales por los cuales se
|
||||
enviarán las notificaciones automáticas.
|
||||
</MaterialAlert>
|
||||
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: "8px", marginBottom: "30px" }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "8px",
|
||||
marginBottom: "30px",
|
||||
}}
|
||||
>
|
||||
{CHANNELS.map((channel) => (
|
||||
<div
|
||||
key={channel.key}
|
||||
@@ -121,10 +144,12 @@ export default function NotificationsPage() {
|
||||
padding: "12px 16px",
|
||||
borderRadius: "4px",
|
||||
border: "1px solid var(--border-color)",
|
||||
backgroundColor: "var(--bg-primary)"
|
||||
backgroundColor: "var(--bg-primary)",
|
||||
}}
|
||||
>
|
||||
<span style={{ color: "var(--text-primary)", fontWeight: "500" }}>{channel.label}</span>
|
||||
<span style={{ color: "var(--text-primary)", fontWeight: "500" }}>
|
||||
{channel.label}
|
||||
</span>
|
||||
<Switch
|
||||
checked={store.formData.defaultChannels.includes(channel.key)}
|
||||
onChange={() => toggleChannel(channel.key)}
|
||||
@@ -135,7 +160,8 @@ export default function NotificationsPage() {
|
||||
|
||||
{/* Quiet Hours Section */}
|
||||
<MaterialAlert severity="info" sx={{ marginBottom: "20px" }}>
|
||||
<b>Horario silencioso:</b> Las notificaciones no se enviarán durante este rango horario.
|
||||
<b>Horario silencioso:</b> Las notificaciones no se enviarán durante este rango
|
||||
horario.
|
||||
</MaterialAlert>
|
||||
|
||||
<div
|
||||
@@ -147,7 +173,7 @@ export default function NotificationsPage() {
|
||||
borderRadius: "8px",
|
||||
border: "1px solid var(--border-color)",
|
||||
backgroundColor: "var(--bg-primary)",
|
||||
marginBottom: "16px"
|
||||
marginBottom: "16px",
|
||||
}}
|
||||
>
|
||||
<span style={{ color: "var(--text-primary)", fontWeight: "500" }}>
|
||||
@@ -160,13 +186,22 @@ export default function NotificationsPage() {
|
||||
</div>
|
||||
|
||||
{store.formData.quietHours && (
|
||||
<div style={{ display: "flex", gap: "16px", alignItems: "flex-end", marginBottom: "30px" }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: "16px",
|
||||
alignItems: "flex-end",
|
||||
marginBottom: "30px",
|
||||
}}
|
||||
>
|
||||
<div style={{ flex: 1 }}>
|
||||
<TextTime
|
||||
placeholder="Desde"
|
||||
width="100%"
|
||||
value={quietHourValue(store.formData.quietHours.from, "22:00")}
|
||||
onChange={(value) => updateQuietHours("from", value.format("HH:mm"))}
|
||||
onChange={(value) =>
|
||||
updateQuietHours("from", value.format("HH:mm"))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
@@ -182,12 +217,15 @@ export default function NotificationsPage() {
|
||||
|
||||
{/* Reminder Rules Section */}
|
||||
<MaterialAlert severity="info" sx={{ marginBottom: "20px" }}>
|
||||
<b>Reglas de recordatorio:</b> Active los momentos en los que desea enviar recordatorios antes del turno.
|
||||
<b>Reglas de recordatorio:</b> Active los momentos en los que desea enviar
|
||||
recordatorios antes del turno.
|
||||
</MaterialAlert>
|
||||
|
||||
<div style={{ display: "flex", flexWrap: "wrap", gap: "10px" }}>
|
||||
{REMINDER_PRESETS.map((preset) => {
|
||||
const isActive = store.formData.reminderRules.some((r) => r.offset === preset.minutes);
|
||||
const isActive = store.formData.reminderRules.some(
|
||||
(r) => r.offset === preset.minutes,
|
||||
);
|
||||
return (
|
||||
<button
|
||||
key={preset.minutes}
|
||||
@@ -198,11 +236,15 @@ export default function NotificationsPage() {
|
||||
padding: "10px 16px",
|
||||
borderRadius: "999px",
|
||||
border: `1px solid ${isActive ? "var(--primary-color)" : "var(--border-color)"}`,
|
||||
backgroundColor: isActive ? "rgba(25, 118, 210, 0.12)" : "var(--bg-primary)",
|
||||
color: isActive ? "var(--primary-color)" : "var(--text-secondary)",
|
||||
backgroundColor: isActive
|
||||
? "rgba(25, 118, 210, 0.12)"
|
||||
: "var(--bg-primary)",
|
||||
color: isActive
|
||||
? "var(--primary-color)"
|
||||
: "var(--text-secondary)",
|
||||
fontWeight: isActive ? "600" : "500",
|
||||
fontSize: "14px",
|
||||
transition: "all 0.2s ease"
|
||||
transition: "all 0.2s ease",
|
||||
}}
|
||||
>
|
||||
{preset.label}
|
||||
|
||||
+304
-109
@@ -248,7 +248,7 @@ export default function OrganizationNotPayedAppointments() {
|
||||
const [dialogPayVisible, setDialogPayVisible] = useState<boolean>(false);
|
||||
const [dialogPayOneVisible, setDialogPayOneVisible] = useState<boolean>(false);
|
||||
const [createPaymentData, setCreatePaymentData] = useState<PaginatePaymentsView | undefined>(
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
|
||||
const [paymentMethodFilterContent] = useState<TextObjectModalContent>({
|
||||
@@ -284,7 +284,7 @@ export default function OrganizationNotPayedAppointments() {
|
||||
TextObjectFilterResult[]
|
||||
>([]);
|
||||
const [paymentMethodId, setPaymentMethodId] = useState<CLIENT_ACCOUNT_PAYMENT_METHODS>(
|
||||
CLIENT_ACCOUNT_PAYMENT_METHODS.CASH
|
||||
CLIENT_ACCOUNT_PAYMENT_METHODS.CASH,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -326,7 +326,7 @@ export default function OrganizationNotPayedAppointments() {
|
||||
TextObjectFilterResult[]
|
||||
>([]);
|
||||
const [paymentProcessDateId, setPaymentProcessDateId] = useState<PAYMENT_PROCCESS_DATE>(
|
||||
PAYMENT_PROCCESS_DATE.NOW
|
||||
PAYMENT_PROCCESS_DATE.NOW,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -356,7 +356,7 @@ export default function OrganizationNotPayedAppointments() {
|
||||
id: category.id.toString(),
|
||||
name: category.name,
|
||||
description: category.description,
|
||||
}))
|
||||
})),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -370,7 +370,7 @@ export default function OrganizationNotPayedAppointments() {
|
||||
const [clientIds, setClientIds] = useState<string[]>([]);
|
||||
|
||||
const [collaboratorFilterData, setCollaboratorFilterData] = useState<TextObjectFilterResult[]>(
|
||||
[]
|
||||
[],
|
||||
);
|
||||
const [collaboratorId, setCollaboratorId] = useState<string>("");
|
||||
|
||||
@@ -484,8 +484,8 @@ export default function OrganizationNotPayedAppointments() {
|
||||
parseInt(
|
||||
process.env.NEXT_PUBLIC_DATAGRID_PAGE_SIZE
|
||||
? process.env.NEXT_PUBLIC_DATAGRID_PAGE_SIZE
|
||||
: "10"
|
||||
)
|
||||
: "10",
|
||||
),
|
||||
);
|
||||
const [payments, setPayments] = useState<PaginateNotPayedAppointmentsResult>();
|
||||
const paymentsRef = useRef(payments);
|
||||
@@ -595,7 +595,6 @@ export default function OrganizationNotPayedAppointments() {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const generarReporte = async () => {
|
||||
eventHandler.setEventType(EVENT_TYPES.LOADING);
|
||||
try {
|
||||
@@ -625,27 +624,27 @@ export default function OrganizationNotPayedAppointments() {
|
||||
reader.onloadend = () => resolve(reader.result as string);
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
} catch(e) {}
|
||||
} catch (e) {}
|
||||
|
||||
const tableBody: any[] = [
|
||||
[
|
||||
{ text: "Cliente", bold: true, color: "#333333", fillColor: "#f5f5f5" },
|
||||
{ text: "Datos del Turno", bold: true, color: "#333333", fillColor: "#f5f5f5" },
|
||||
{ text: "Monto", bold: true, color: "#333333", fillColor: "#f5f5f5" }
|
||||
]
|
||||
{ text: "Monto", bold: true, color: "#333333", fillColor: "#f5f5f5" },
|
||||
],
|
||||
];
|
||||
|
||||
report.items.forEach(item => {
|
||||
report.items.forEach((item) => {
|
||||
tableBody.push([
|
||||
item.clientName || "-",
|
||||
{
|
||||
text: [
|
||||
{ text: `${item.serviceName || "-"}\n`, bold: true, fontSize: 11 },
|
||||
`Prof: ${item.employeeName || "-"}\nFecha: ${dayjs(item.appointmentDate).format("DD/MM/YYYY HH:mm")} hs`
|
||||
`Prof: ${item.employeeName || "-"}\nFecha: ${dayjs(item.appointmentDate).format("DD/MM/YYYY HH:mm")} hs`,
|
||||
],
|
||||
fontSize: 10
|
||||
fontSize: 10,
|
||||
},
|
||||
{ text: "$" + item.price.toLocaleString("es-AR"), alignment: "right" }
|
||||
{ text: "$" + item.price.toLocaleString("es-AR"), alignment: "right" },
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -653,52 +652,81 @@ export default function OrganizationNotPayedAppointments() {
|
||||
tableBody.push([
|
||||
{ text: "TOTAL ADEUDADO", bold: true, colSpan: 2, alignment: "right" },
|
||||
{},
|
||||
{ text: "$" + report.totalAmount.toLocaleString("es-AR"), bold: true, alignment: "right" }
|
||||
{
|
||||
text: "$" + report.totalAmount.toLocaleString("es-AR"),
|
||||
bold: true,
|
||||
alignment: "right",
|
||||
},
|
||||
]);
|
||||
|
||||
const docDefinition: unknown = {
|
||||
content: [
|
||||
{
|
||||
columns: [
|
||||
{ text: "Reporte de Turnos Adeudados", fontSize: 18, bold: true, margin: [0, 0, 0, 10], width: '*' },
|
||||
...(logoDataUrl ? [{ image: logoDataUrl, width: 45, margin: [0, 0, 0, 10], alignment: 'right' }] : [])
|
||||
]
|
||||
{
|
||||
text: "Reporte de Turnos Adeudados",
|
||||
fontSize: 18,
|
||||
bold: true,
|
||||
margin: [0, 0, 0, 10],
|
||||
width: "*",
|
||||
},
|
||||
...(logoDataUrl
|
||||
? [
|
||||
{
|
||||
image: logoDataUrl,
|
||||
width: 45,
|
||||
margin: [0, 0, 0, 10],
|
||||
alignment: "right",
|
||||
},
|
||||
]
|
||||
: []),
|
||||
],
|
||||
},
|
||||
{ text: `Filtros aplicados:`, bold: true, margin: [0, 0, 0, 5] },
|
||||
{
|
||||
text: [
|
||||
{ text: "Clientes Seleccionados: ", bold: true },
|
||||
`${clientIds.length > 0 ? clientIds.length : "Todos"}`
|
||||
`${clientIds.length > 0 ? clientIds.length : "Todos"}`,
|
||||
],
|
||||
margin: [0, 0, 0, 2]
|
||||
margin: [0, 0, 0, 2],
|
||||
},
|
||||
{
|
||||
text: [
|
||||
{ text: "Período: ", bold: true },
|
||||
`${dateFrom ? dateFrom.format("DD/MM/YYYY") : "Inicio"} al ${dateTo ? dateTo.format("DD/MM/YYYY") : "Fin"}`
|
||||
`${dateFrom ? dateFrom.format("DD/MM/YYYY") : "Inicio"} al ${dateTo ? dateTo.format("DD/MM/YYYY") : "Fin"}`,
|
||||
],
|
||||
margin: [0, 0, 0, 20]
|
||||
margin: [0, 0, 0, 20],
|
||||
},
|
||||
{
|
||||
table: {
|
||||
headerRows: 1,
|
||||
widths: [120, "*", "auto"],
|
||||
body: tableBody
|
||||
body: tableBody,
|
||||
},
|
||||
layout: "lightHorizontalLines"
|
||||
}
|
||||
]
|
||||
layout: "lightHorizontalLines",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
if ((window as unknown as { Android: any }).Android && (window as unknown as { Android: any }).Android.savePdf) {
|
||||
if (
|
||||
(window as unknown as { Android: any }).Android &&
|
||||
(window as unknown as { Android: any }).Android.savePdf
|
||||
) {
|
||||
pdfMake.createPdf(docDefinition as any).getBase64((data: any) => {
|
||||
(window as unknown as { Android: any }).Android?.savePdf(data, `reporte-adeudados.pdf`);
|
||||
(window as unknown as { Android: any }).Android?.savePdf(
|
||||
data,
|
||||
`reporte-adeudados.pdf`,
|
||||
);
|
||||
});
|
||||
} else {
|
||||
pdfMake.createPdf(docDefinition as any).download(`reporte-adeudados.pdf`);
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
alert.showError((error as { format?: () => string }).format ? (error as { format: () => string }).format() : "Error generando PDF");
|
||||
alert.showError(
|
||||
(error as { format?: () => string }).format
|
||||
? (error as { format: () => string }).format()
|
||||
: "Error generando PDF",
|
||||
);
|
||||
} finally {
|
||||
eventHandler.setEventType(EVENT_TYPES.CLEAR);
|
||||
}
|
||||
@@ -832,14 +860,24 @@ export default function OrganizationNotPayedAppointments() {
|
||||
setMethodId={setMethodId}
|
||||
clientData={clientFilterData}
|
||||
setClientIds={setClientIds}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
filter.setOnFilter(() => { });
|
||||
filter.setOnFilter(() => {});
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, [paymentsTotal, collaboratorFilterData, serviceFilterData, methodFilterData, clientFilterData, clientIds, collaboratorId, serviceId, methodId]);
|
||||
}, [
|
||||
paymentsTotal,
|
||||
collaboratorFilterData,
|
||||
serviceFilterData,
|
||||
methodFilterData,
|
||||
clientFilterData,
|
||||
clientIds,
|
||||
collaboratorId,
|
||||
serviceId,
|
||||
methodId,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
eventHandler.setEventType(EVENT_TYPES.SLEEP);
|
||||
@@ -881,45 +919,81 @@ export default function OrganizationNotPayedAppointments() {
|
||||
loadNotPayedAppointmentsTotal();
|
||||
}, [clientIds, collaboratorId, serviceId, methodId, dateFrom, dateTo, reloadPayments]);
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Location />
|
||||
|
||||
<SecureByPlan content={SECURE_CONTENTS.PAYMENTS} companyId={id}>
|
||||
<div style={{ maxWidth: "800px", margin: "0 auto", paddingBottom: "100px", marginTop: "0px" }}>
|
||||
|
||||
<div
|
||||
style={{
|
||||
maxWidth: "800px",
|
||||
margin: "0 auto",
|
||||
paddingBottom: "100px",
|
||||
marginTop: "0px",
|
||||
}}
|
||||
>
|
||||
{/* Top Status Card */}
|
||||
<div style={{ position: "sticky", top: "70px", zIndex: 100, marginBottom: "50px", display: "flex", flexDirection: "column", background: "white", paddingBottom: "10px", paddingTop: "5px", margin: "0 -10px", paddingLeft: "10px", paddingRight: "10px" }}>
|
||||
|
||||
|
||||
{/* Tabs Selector */}
|
||||
<div style={{ display: "flex", justifyContent: "center", marginBottom: "15px" }}>
|
||||
<ThemeProvider theme={turnosXpressTheme}>
|
||||
<div style={{
|
||||
<div
|
||||
style={{
|
||||
position: "sticky",
|
||||
top: "70px",
|
||||
zIndex: 100,
|
||||
marginBottom: "50px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
background: "white",
|
||||
paddingBottom: "10px",
|
||||
paddingTop: "5px",
|
||||
margin: "0 -10px",
|
||||
paddingLeft: "10px",
|
||||
paddingRight: "10px",
|
||||
}}
|
||||
>
|
||||
{/* Tabs Selector */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
background: "rgba(255,255,255,0.9)",
|
||||
backdropFilter: "blur(10px)",
|
||||
borderRadius: "30px",
|
||||
padding: "5px",
|
||||
boxShadow: "0 4px 15px rgba(0,0,0,0.05)"
|
||||
}}>
|
||||
<ButtonMaterial
|
||||
variant="text"
|
||||
onClick={() => goTo(`/admin/org/profile/${id}/payments`)}
|
||||
style={{ borderRadius: "25px", color: "#666", fontWeight: "bold", padding: "8px 25px" }}
|
||||
justifyContent: "center",
|
||||
marginBottom: "15px",
|
||||
}}
|
||||
>
|
||||
<ThemeProvider theme={turnosXpressTheme}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
background: "rgba(255,255,255,0.9)",
|
||||
backdropFilter: "blur(10px)",
|
||||
borderRadius: "30px",
|
||||
padding: "5px",
|
||||
boxShadow: "0 4px 15px rgba(0,0,0,0.05)",
|
||||
}}
|
||||
>
|
||||
Pagados
|
||||
</ButtonMaterial>
|
||||
<ButtonMaterial
|
||||
variant="contained"
|
||||
style={{ borderRadius: "25px", boxShadow: "0 2px 8px rgba(0,0,0,0.1)", fontWeight: "bold", padding: "8px 25px" }}
|
||||
>
|
||||
Adeudados
|
||||
</ButtonMaterial>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
</div>
|
||||
<ButtonMaterial
|
||||
variant="text"
|
||||
onClick={() => goTo(`/admin/org/profile/${id}/payments`)}
|
||||
style={{
|
||||
borderRadius: "25px",
|
||||
color: "#666",
|
||||
fontWeight: "bold",
|
||||
padding: "8px 25px",
|
||||
}}
|
||||
>
|
||||
Pagados
|
||||
</ButtonMaterial>
|
||||
<ButtonMaterial
|
||||
variant="contained"
|
||||
style={{
|
||||
borderRadius: "25px",
|
||||
boxShadow: "0 2px 8px rgba(0,0,0,0.1)",
|
||||
fontWeight: "bold",
|
||||
padding: "8px 25px",
|
||||
}}
|
||||
>
|
||||
Adeudados
|
||||
</ButtonMaterial>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
layout
|
||||
@@ -928,25 +1002,33 @@ export default function OrganizationNotPayedAppointments() {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
padding: isMinimized ? "25px 50px" : "40px 20px",
|
||||
borderRadius: isMinimized ? "15px" : "20px"
|
||||
borderRadius: isMinimized ? "15px" : "20px",
|
||||
}}
|
||||
style={{
|
||||
background: "linear-gradient(135deg, #FF416C 0%, #FF4B2B 100%)", // Red gradient for debts
|
||||
color: "white",
|
||||
textAlign: "center",
|
||||
boxShadow: isMinimized ? "0 4px 15px rgba(0,0,0,0.3)" : "0 10px 30px rgba(0,0,0,0.15)",
|
||||
boxShadow: isMinimized
|
||||
? "0 4px 15px rgba(0,0,0,0.3)"
|
||||
: "0 10px 30px rgba(0,0,0,0.15)",
|
||||
position: "relative",
|
||||
|
||||
display: "flex",
|
||||
flexDirection: isMinimized ? "row" : "column",
|
||||
alignItems: "center",
|
||||
justifyContent: isMinimized ? "space-between" : "center",
|
||||
transition: "box-shadow 0.3s ease"
|
||||
transition: "box-shadow 0.3s ease",
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
onClick={() => setForceMinimized(!forceMinimized)}
|
||||
style={{ position: "absolute", top: "10px", left: "10px", color: "rgba(255,255,255,0.7)", zIndex: 10 }}
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "10px",
|
||||
left: "10px",
|
||||
color: "rgba(255,255,255,0.7)",
|
||||
zIndex: 10,
|
||||
}}
|
||||
size="small"
|
||||
title={forceMinimized ? "Maximizar" : "Minimizar"}
|
||||
>
|
||||
@@ -954,28 +1036,59 @@ export default function OrganizationNotPayedAppointments() {
|
||||
</IconButton>
|
||||
<IconButton
|
||||
onClick={() => filter.toggle()}
|
||||
style={{ position: "absolute", top: "10px", right: "10px", color: "rgba(255,255,255,0.7)", zIndex: 10 }}
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "10px",
|
||||
right: "10px",
|
||||
color: "rgba(255,255,255,0.7)",
|
||||
zIndex: 10,
|
||||
}}
|
||||
size="small"
|
||||
title="Filtrar"
|
||||
>
|
||||
<FilterAltOutlinedIcon />
|
||||
</IconButton>
|
||||
<div style={{ position: "absolute", top: "-50px", right: "-50px", width: "150px", height: "150px", borderRadius: "50%", background: "rgba(255,255,255,0.05)" }}></div>
|
||||
<div style={{ position: "absolute", bottom: "-30px", left: "-30px", width: "100px", height: "100px", borderRadius: "50%", background: "rgba(255,255,255,0.05)" }}></div>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "-50px",
|
||||
right: "-50px",
|
||||
width: "150px",
|
||||
height: "150px",
|
||||
borderRadius: "50%",
|
||||
background: "rgba(255,255,255,0.05)",
|
||||
}}
|
||||
></div>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
bottom: "-30px",
|
||||
left: "-30px",
|
||||
width: "100px",
|
||||
height: "100px",
|
||||
borderRadius: "50%",
|
||||
background: "rgba(255,255,255,0.05)",
|
||||
}}
|
||||
></div>
|
||||
|
||||
<motion.div
|
||||
animate={{
|
||||
fontSize: isMinimized ? "14px" : "16px",
|
||||
marginBottom: isMinimized ? "0px" : "10px"
|
||||
marginBottom: isMinimized ? "0px" : "10px",
|
||||
}}
|
||||
style={{
|
||||
fontWeight: "bold",
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: "2px",
|
||||
opacity: 0.9,
|
||||
}}
|
||||
style={{ fontWeight: "bold", textTransform: "uppercase", letterSpacing: "2px", opacity: 0.9 }}
|
||||
>
|
||||
Total Adeudado
|
||||
</motion.div>
|
||||
<motion.div
|
||||
animate={{
|
||||
fontSize: isMinimized ? "24px" : "56px",
|
||||
margin: isMinimized ? "0px" : "10px 0"
|
||||
margin: isMinimized ? "0px" : "10px 0",
|
||||
}}
|
||||
style={{ fontWeight: "900" }}
|
||||
>
|
||||
@@ -989,16 +1102,29 @@ export default function OrganizationNotPayedAppointments() {
|
||||
exit={{ opacity: 0 }}
|
||||
style={{ marginTop: "15px" }}
|
||||
>
|
||||
<div style={{ marginBottom: "15px", width: "250px", maxWidth: "100%" }}>
|
||||
<div
|
||||
style={{
|
||||
marginBottom: "15px",
|
||||
width: "250px",
|
||||
maxWidth: "100%",
|
||||
}}
|
||||
>
|
||||
<TextRangeDateModern
|
||||
label="Período"
|
||||
dateFrom={dateFrom}
|
||||
dateTo={dateTo}
|
||||
setDateFrom={setDateFrom}
|
||||
setDateTo={setDateTo}
|
||||
/>
|
||||
label="Período"
|
||||
dateFrom={dateFrom}
|
||||
dateTo={dateTo}
|
||||
setDateFrom={setDateFrom}
|
||||
setDateTo={setDateTo}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ display: "flex", gap: "10px", alignItems: "center", flexWrap: "wrap" }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: "10px",
|
||||
alignItems: "center",
|
||||
flexWrap: "wrap",
|
||||
}}
|
||||
>
|
||||
<ButtonMaterial
|
||||
variant="contained"
|
||||
startIcon={<PayIcon />}
|
||||
@@ -1009,7 +1135,7 @@ export default function OrganizationNotPayedAppointments() {
|
||||
fontWeight: "bold",
|
||||
borderRadius: "20px",
|
||||
padding: "8px 20px",
|
||||
textTransform: "none"
|
||||
textTransform: "none",
|
||||
}}
|
||||
>
|
||||
Pagar Todos
|
||||
@@ -1023,10 +1149,13 @@ export default function OrganizationNotPayedAppointments() {
|
||||
fontWeight: "bold",
|
||||
borderRadius: "20px",
|
||||
padding: "8px 20px",
|
||||
textTransform: "none"
|
||||
textTransform: "none",
|
||||
}}
|
||||
>
|
||||
<PictureAsPdfIcon style={{ fontSize: "18px", marginRight: "5px" }} /> PDF
|
||||
<PictureAsPdfIcon
|
||||
style={{ fontSize: "18px", marginRight: "5px" }}
|
||||
/>{" "}
|
||||
PDF
|
||||
</ButtonMaterial>
|
||||
</div>
|
||||
</motion.div>
|
||||
@@ -1035,10 +1164,22 @@ export default function OrganizationNotPayedAppointments() {
|
||||
</div>
|
||||
|
||||
{/* Dynamic Spacer for layout shift */}
|
||||
<div style={{ height: isMinimized ? "150px" : "0px", transition: "height 0.3s ease" }}></div>
|
||||
<div
|
||||
style={{
|
||||
height: isMinimized ? "150px" : "0px",
|
||||
transition: "height 0.3s ease",
|
||||
}}
|
||||
></div>
|
||||
|
||||
{/* Payments List */}
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: "15px", padding: "15px 10px 0 10px" }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "15px",
|
||||
padding: "15px 10px 0 10px",
|
||||
}}
|
||||
>
|
||||
<AnimatePresence>
|
||||
{payments?.data.map((payment, index) => (
|
||||
<motion.div
|
||||
@@ -1054,31 +1195,72 @@ export default function OrganizationNotPayedAppointments() {
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
boxShadow: "0 4px 15px rgba(0,0,0,0.05)",
|
||||
borderLeft: `4px solid var(--red)`
|
||||
borderLeft: `4px solid var(--red)`,
|
||||
}}
|
||||
>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "15px" }}>
|
||||
<div style={{
|
||||
background: "rgba(255, 75, 43, 0.1)",
|
||||
padding: "10px",
|
||||
borderRadius: "12px",
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
color: "var(--red)"
|
||||
}}>
|
||||
gap: "15px",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
background: "rgba(255, 75, 43, 0.1)",
|
||||
padding: "10px",
|
||||
borderRadius: "12px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
color: "var(--red)",
|
||||
}}
|
||||
>
|
||||
<CreditCardIcon />
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ fontWeight: "800", fontSize: "15px", color: "#333", marginBottom: "4px" }}>{payment.clientName}</div>
|
||||
<div style={{ fontWeight: "700", fontSize: "13px", color: "var(--purple)", marginBottom: "4px" }}>{payment.serviceName}</div>
|
||||
<div
|
||||
style={{
|
||||
fontWeight: "800",
|
||||
fontSize: "15px",
|
||||
color: "#333",
|
||||
marginBottom: "4px",
|
||||
}}
|
||||
>
|
||||
{payment.clientName}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontWeight: "700",
|
||||
fontSize: "13px",
|
||||
color: "var(--purple)",
|
||||
marginBottom: "4px",
|
||||
}}
|
||||
>
|
||||
{payment.serviceName}
|
||||
</div>
|
||||
<div style={{ fontSize: "12px", color: "#888" }}>
|
||||
{dayjs(payment.createdAt).format("DD MMMM YYYY • HH:mm")} • {payment.employeeName}
|
||||
{dayjs(payment.createdAt).format(
|
||||
"DD MMMM YYYY • HH:mm",
|
||||
)}{" "}
|
||||
• {payment.employeeName}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "15px" }}>
|
||||
<div style={{ fontWeight: "900", fontSize: "16px", color: "var(--red)" }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "15px",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontWeight: "900",
|
||||
fontSize: "16px",
|
||||
color: "var(--red)",
|
||||
}}
|
||||
>
|
||||
{formatPrice(payment.price)}
|
||||
</div>
|
||||
<IconButton
|
||||
@@ -1096,10 +1278,22 @@ export default function OrganizationNotPayedAppointments() {
|
||||
))}
|
||||
|
||||
{(!payments?.data || payments.data.length === 0) && (
|
||||
<div style={{ textAlign: "center", padding: "50px", color: "#aaa" }}>
|
||||
<CreditCardIcon sx={{ fontSize: "60px", opacity: 0.2, marginBottom: "15px" }} />
|
||||
<div style={{ fontSize: "18px", fontWeight: "bold" }}>No hay pagos adeudados</div>
|
||||
<div style={{ fontSize: "14px", marginTop: "5px" }}>Intenta ajustar los filtros de fecha</div>
|
||||
<div
|
||||
style={{ textAlign: "center", padding: "50px", color: "#aaa" }}
|
||||
>
|
||||
<CreditCardIcon
|
||||
sx={{
|
||||
fontSize: "60px",
|
||||
opacity: 0.2,
|
||||
marginBottom: "15px",
|
||||
}}
|
||||
/>
|
||||
<div style={{ fontSize: "18px", fontWeight: "bold" }}>
|
||||
No hay pagos adeudados
|
||||
</div>
|
||||
<div style={{ fontSize: "14px", marginTop: "5px" }}>
|
||||
Intenta ajustar los filtros de fecha
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
@@ -1107,7 +1301,9 @@ export default function OrganizationNotPayedAppointments() {
|
||||
|
||||
{/* Pagination */}
|
||||
{payments && payments.pages > 1 && (
|
||||
<div style={{ display: "flex", justifyContent: "center", marginTop: "40px" }}>
|
||||
<div
|
||||
style={{ display: "flex", justifyContent: "center", marginTop: "40px" }}
|
||||
>
|
||||
<Pagination
|
||||
count={payments.pages}
|
||||
page={payments.page}
|
||||
@@ -1134,7 +1330,7 @@ export default function OrganizationNotPayedAppointments() {
|
||||
data={paymentMethhodFilterData}
|
||||
onChange={(id) => {
|
||||
setPaymentMethodId(
|
||||
id as CLIENT_ACCOUNT_PAYMENT_METHODS
|
||||
id as CLIENT_ACCOUNT_PAYMENT_METHODS,
|
||||
);
|
||||
}}
|
||||
/>
|
||||
@@ -1185,7 +1381,7 @@ export default function OrganizationNotPayedAppointments() {
|
||||
data={paymentMethhodFilterData}
|
||||
onChange={(id) => {
|
||||
setPaymentMethodId(
|
||||
id as CLIENT_ACCOUNT_PAYMENT_METHODS
|
||||
id as CLIENT_ACCOUNT_PAYMENT_METHODS,
|
||||
);
|
||||
}}
|
||||
/>
|
||||
@@ -1219,7 +1415,6 @@ export default function OrganizationNotPayedAppointments() {
|
||||
</DialogActions>
|
||||
</>
|
||||
</DialogWindow>
|
||||
|
||||
</div>
|
||||
</SecureByPlan>
|
||||
</>
|
||||
|
||||
+345
-116
@@ -47,6 +47,7 @@ import SearchOffIcon from "@mui/icons-material/SearchOff";
|
||||
import UnfoldLessIcon from "@mui/icons-material/UnfoldLess";
|
||||
import UnfoldMoreIcon from "@mui/icons-material/UnfoldMore";
|
||||
import FilterAltOutlinedIcon from "@mui/icons-material/FilterAltOutlined";
|
||||
import { useBottomToolbarStore } from "@core/Store/BottomToolbar.Store";
|
||||
|
||||
type UrlData = {
|
||||
id: string;
|
||||
@@ -68,8 +69,12 @@ const FilterContent = (props: FilterContentProps) => {
|
||||
const [clientFilterContent] = useState<TextObjectModalContent>({
|
||||
header: (
|
||||
<div>
|
||||
<div style={{ fontWeight: "700", fontSize: "14px", paddingTop: "7px" }}>Seleccionar Cliente:</div>
|
||||
<p style={{ fontWeight: "500", fontSize: "13px", paddingTop: "2px" }}>Ingrese el nombre del cliente para buscarlo.</p>
|
||||
<div style={{ fontWeight: "700", fontSize: "14px", paddingTop: "7px" }}>
|
||||
Seleccionar Cliente:
|
||||
</div>
|
||||
<p style={{ fontWeight: "500", fontSize: "13px", paddingTop: "2px" }}>
|
||||
Ingrese el nombre del cliente para buscarlo.
|
||||
</p>
|
||||
</div>
|
||||
),
|
||||
bottom: <div> </div>,
|
||||
@@ -81,8 +86,12 @@ const FilterContent = (props: FilterContentProps) => {
|
||||
const [collaboratorFilterContent] = useState<TextObjectModalContent>({
|
||||
header: (
|
||||
<div>
|
||||
<div style={{ fontWeight: "700", fontSize: "14px", paddingTop: "7px" }}>Seleccionar Colaborador:</div>
|
||||
<p style={{ fontWeight: "500", fontSize: "13px", paddingTop: "2px" }}>Ingrese el nombre del colaborador para buscarlo.</p>
|
||||
<div style={{ fontWeight: "700", fontSize: "14px", paddingTop: "7px" }}>
|
||||
Seleccionar Colaborador:
|
||||
</div>
|
||||
<p style={{ fontWeight: "500", fontSize: "13px", paddingTop: "2px" }}>
|
||||
Ingrese el nombre del colaborador para buscarlo.
|
||||
</p>
|
||||
</div>
|
||||
),
|
||||
bottom: <div> </div>,
|
||||
@@ -94,8 +103,12 @@ const FilterContent = (props: FilterContentProps) => {
|
||||
const [serviceFilterContent] = useState<TextObjectModalContent>({
|
||||
header: (
|
||||
<div>
|
||||
<div style={{ fontWeight: "700", fontSize: "14px", paddingTop: "7px" }}>Seleccionar Servicio:</div>
|
||||
<p style={{ fontWeight: "500", fontSize: "13px", paddingTop: "2px" }}>Ingrese el nombre del servicio para buscarlo.</p>
|
||||
<div style={{ fontWeight: "700", fontSize: "14px", paddingTop: "7px" }}>
|
||||
Seleccionar Servicio:
|
||||
</div>
|
||||
<p style={{ fontWeight: "500", fontSize: "13px", paddingTop: "2px" }}>
|
||||
Ingrese el nombre del servicio para buscarlo.
|
||||
</p>
|
||||
</div>
|
||||
),
|
||||
bottom: <div> </div>,
|
||||
@@ -107,8 +120,12 @@ const FilterContent = (props: FilterContentProps) => {
|
||||
const [methodFilterContent] = useState<TextObjectModalContent>({
|
||||
header: (
|
||||
<div>
|
||||
<div style={{ fontWeight: "700", fontSize: "14px", paddingTop: "7px" }}>Seleccionar Método de Pago:</div>
|
||||
<p style={{ fontWeight: "500", fontSize: "13px", paddingTop: "2px" }}>Ingrese el nombre del método de pago para buscarlo.</p>
|
||||
<div style={{ fontWeight: "700", fontSize: "14px", paddingTop: "7px" }}>
|
||||
Seleccionar Método de Pago:
|
||||
</div>
|
||||
<p style={{ fontWeight: "500", fontSize: "13px", paddingTop: "2px" }}>
|
||||
Ingrese el nombre del método de pago para buscarlo.
|
||||
</p>
|
||||
</div>
|
||||
),
|
||||
bottom: <div> </div>,
|
||||
@@ -152,6 +169,7 @@ export default function OrganizationEdit() {
|
||||
const data = useParams<UrlData>();
|
||||
const id = data.id;
|
||||
const location = useLocationStore();
|
||||
const bottomToolbar = useBottomToolbarStore();
|
||||
const eventHandler = useEventHandlerStore();
|
||||
const SessionInfo = useSessionStore();
|
||||
const filter = useFilterStore();
|
||||
@@ -168,7 +186,9 @@ export default function OrganizationEdit() {
|
||||
const [clientFilterData, setClientFilterData] = useState<TextObjectFilterResult[]>([]);
|
||||
const [clientIds, setClientIds] = useState<string[]>([]);
|
||||
|
||||
const [collaboratorFilterData, setCollaboratorFilterData] = useState<TextObjectFilterResult[]>([]);
|
||||
const [collaboratorFilterData, setCollaboratorFilterData] = useState<TextObjectFilterResult[]>(
|
||||
[],
|
||||
);
|
||||
const [collaboratorId, setCollaboratorId] = useState<string>("");
|
||||
|
||||
const [serviceFilterData, setServiceFilterData] = useState<TextObjectFilterResult[]>([]);
|
||||
@@ -188,7 +208,6 @@ export default function OrganizationEdit() {
|
||||
|
||||
const generarReporte = async () => {
|
||||
try {
|
||||
|
||||
const pdfMake = await import("pdfmake/build/pdfmake");
|
||||
const pdfFonts = (await import("pdfmake/build/vfs_fonts")) as any;
|
||||
pdfMake.vfs = pdfFonts.pdfMake ? pdfFonts.pdfMake.vfs : pdfFonts.vfs;
|
||||
@@ -201,7 +220,7 @@ export default function OrganizationEdit() {
|
||||
serviceId: serviceId ? serviceId : undefined,
|
||||
employeeId: collaboratorId ? collaboratorId : undefined,
|
||||
method: methodId ? (methodId as any) : undefined,
|
||||
sessionUser: SessionInfo.userId
|
||||
sessionUser: SessionInfo.userId,
|
||||
});
|
||||
|
||||
if (!report.items || report.items.length === 0) {
|
||||
@@ -218,86 +237,114 @@ export default function OrganizationEdit() {
|
||||
reader.onloadend = () => resolve(reader.result as string);
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
} catch(e) {}
|
||||
} catch (e) {}
|
||||
|
||||
const tableBody: any[] = [
|
||||
[
|
||||
{ text: "Cliente", bold: true, color: "#333333", fillColor: "#f5f5f5" },
|
||||
{ text: "Datos del Turno", bold: true, color: "#333333", fillColor: "#f5f5f5" },
|
||||
{ text: "Monto", bold: true, color: "#333333", fillColor: "#f5f5f5" }
|
||||
]
|
||||
{ text: "Monto", bold: true, color: "#333333", fillColor: "#f5f5f5" },
|
||||
],
|
||||
];
|
||||
|
||||
report.items.forEach(item => {
|
||||
report.items.forEach((item) => {
|
||||
tableBody.push([
|
||||
item.clientName || "-",
|
||||
{
|
||||
text: [
|
||||
{ text: `${item.serviceName || "-"}\n`, bold: true, fontSize: 11 },
|
||||
`Prof: ${item.employeeName || "-"}\nFecha: ${dayjs(item.appointmentDate).format("DD/MM/YYYY HH:mm")} hs\nMétodo: ${item.method || "-"}`
|
||||
`Prof: ${item.employeeName || "-"}\nFecha: ${dayjs(item.appointmentDate).format("DD/MM/YYYY HH:mm")} hs\nMétodo: ${item.method || "-"}`,
|
||||
],
|
||||
fontSize: 10
|
||||
fontSize: 10,
|
||||
},
|
||||
{ text: "$" + item.price.toLocaleString("es-AR"), alignment: "right" }
|
||||
{ text: "$" + item.price.toLocaleString("es-AR"), alignment: "right" },
|
||||
]);
|
||||
});
|
||||
|
||||
tableBody.push([
|
||||
{ text: "TOTAL PROCESADO", bold: true, colSpan: 2, alignment: "right" },
|
||||
{},
|
||||
{ text: "$" + report.totalAmount.toLocaleString("es-AR"), bold: true, alignment: "right" }
|
||||
{
|
||||
text: "$" + report.totalAmount.toLocaleString("es-AR"),
|
||||
bold: true,
|
||||
alignment: "right",
|
||||
},
|
||||
]);
|
||||
|
||||
const docDefinition: unknown = {
|
||||
content: [
|
||||
{
|
||||
columns: [
|
||||
{ text: "Reporte de Cobros Procesados", fontSize: 18, bold: true, margin: [0, 0, 0, 10], width: '*' },
|
||||
...(logoDataUrl ? [{ image: logoDataUrl, width: 45, margin: [0, 0, 0, 10], alignment: 'right' }] : [])
|
||||
]
|
||||
{
|
||||
text: "Reporte de Cobros Procesados",
|
||||
fontSize: 18,
|
||||
bold: true,
|
||||
margin: [0, 0, 0, 10],
|
||||
width: "*",
|
||||
},
|
||||
...(logoDataUrl
|
||||
? [
|
||||
{
|
||||
image: logoDataUrl,
|
||||
width: 45,
|
||||
margin: [0, 0, 0, 10],
|
||||
alignment: "right",
|
||||
},
|
||||
]
|
||||
: []),
|
||||
],
|
||||
},
|
||||
{ text: `Filtros aplicados:`, bold: true, margin: [0, 0, 0, 5] },
|
||||
{
|
||||
text: [
|
||||
{ text: "Clientes Seleccionados: ", bold: true },
|
||||
`${clientIds.length > 0 ? clientIds.length : "Todos"}`
|
||||
`${clientIds.length > 0 ? clientIds.length : "Todos"}`,
|
||||
],
|
||||
margin: [0, 0, 0, 2]
|
||||
margin: [0, 0, 0, 2],
|
||||
},
|
||||
{
|
||||
text: [
|
||||
{ text: "Período: ", bold: true },
|
||||
`${dateFrom ? dateFrom.format("DD/MM/YYYY") : "Inicio"} al ${dateTo ? dateTo.format("DD/MM/YYYY") : "Fin"}`
|
||||
`${dateFrom ? dateFrom.format("DD/MM/YYYY") : "Inicio"} al ${dateTo ? dateTo.format("DD/MM/YYYY") : "Fin"}`,
|
||||
],
|
||||
margin: [0, 0, 0, 20]
|
||||
margin: [0, 0, 0, 20],
|
||||
},
|
||||
{
|
||||
table: {
|
||||
headerRows: 1,
|
||||
widths: [120, "*", "auto"],
|
||||
body: tableBody
|
||||
body: tableBody,
|
||||
},
|
||||
layout: "lightHorizontalLines"
|
||||
}
|
||||
]
|
||||
layout: "lightHorizontalLines",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
if ((window as unknown as { Android: any }).Android && (window as unknown as { Android: any }).Android.savePdf) {
|
||||
if (
|
||||
(window as unknown as { Android: any }).Android &&
|
||||
(window as unknown as { Android: any }).Android.savePdf
|
||||
) {
|
||||
pdfMake.createPdf(docDefinition as any).getBase64((data: any) => {
|
||||
(window as unknown as { Android: any }).Android?.savePdf(data, `reporte-procesados.pdf`);
|
||||
(window as unknown as { Android: any }).Android?.savePdf(
|
||||
data,
|
||||
`reporte-procesados.pdf`,
|
||||
);
|
||||
});
|
||||
} else {
|
||||
pdfMake.createPdf(docDefinition as any).download(`reporte-procesados.pdf`);
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
console.error(error);
|
||||
alert.showError((error as { format?: () => string }).format ? (error as { format: () => string }).format() : "Error generando PDF");
|
||||
alert.showError(
|
||||
(error as { format?: () => string }).format
|
||||
? (error as { format: () => string }).format()
|
||||
: "Error generando PDF",
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
const handleScroll = (e: Event) => {
|
||||
const handleScroll = (e: Event) => {
|
||||
const target = e.target as HTMLElement;
|
||||
// Check if it's a DOM element scrolling
|
||||
if (target && target.scrollTop !== undefined) {
|
||||
@@ -389,15 +436,23 @@ export default function OrganizationEdit() {
|
||||
|
||||
useEffect(() => {
|
||||
const cFilter: FindClientsParams = { companyId: id };
|
||||
filterObjects<FindClientsParams>("clients/filter-all", cFilter).then((res) => setClientFilterData(res));
|
||||
filterObjects<FindClientsParams>("clients/filter-all", cFilter).then((res) =>
|
||||
setClientFilterData(res),
|
||||
);
|
||||
|
||||
const eFilter: FindEmployeesParams = { companyId: id };
|
||||
filterObjects<FindEmployeesParams>("employees/filter-all", eFilter).then((res) => setCollaboratorFilterData(res));
|
||||
filterObjects<FindEmployeesParams>("employees/filter-all", eFilter).then((res) =>
|
||||
setCollaboratorFilterData(res),
|
||||
);
|
||||
|
||||
const sFilter: FindServicesParams = { companyId: id };
|
||||
filterObjects<FindServicesParams>("services/filter-all", sFilter).then((res) => setServiceFilterData(res));
|
||||
filterObjects<FindServicesParams>("services/filter-all", sFilter).then((res) =>
|
||||
setServiceFilterData(res),
|
||||
);
|
||||
|
||||
setMethodFilterData(paymentMethods.map((m) => ({ id: m.id, text: m.name, name: m.name, image: "" })));
|
||||
setMethodFilterData(
|
||||
paymentMethods.map((m) => ({ id: m.id, text: m.name, name: m.name, image: "" })),
|
||||
);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -413,18 +468,31 @@ export default function OrganizationEdit() {
|
||||
setMethodId={setMethodId}
|
||||
clientData={clientFilterData}
|
||||
setClientIds={setClientIds}
|
||||
clientIds={clientIds}
|
||||
/>
|
||||
clientIds={clientIds}
|
||||
/>,
|
||||
);
|
||||
filter.setOnFilter(() => { });
|
||||
filter.setOnFilter(() => {});
|
||||
}, [collaboratorFilterData, serviceFilterData, methodFilterData, clientFilterData]);
|
||||
|
||||
useEffect(() => {
|
||||
eventHandler.setEventType(EVENT_TYPES.SLEEP);
|
||||
location.clear();
|
||||
bottomToolbar.set(<></>);
|
||||
location.add({ url: "/admin/org", title: "Organizaciones", icon: null });
|
||||
location.add({ url: "/admin/org/profile/" + id, title: "Perfil", icon: <StorefrontOutlinedIcon sx={{ mr: 0.5 }} fontSize="inherit" /> });
|
||||
location.add({ url: "/admin/org/profile/" + id, title: "Pagos", icon: <PaymentsIcon sx={{ fontSize: "32px", mr: "10px" }} /> });
|
||||
location.add({
|
||||
url: "/admin/org/profile/" + id,
|
||||
title: "Perfil",
|
||||
icon: <StorefrontOutlinedIcon sx={{ mr: 0.5 }} fontSize="inherit" />,
|
||||
});
|
||||
location.add({
|
||||
url: "/admin/org/profile/" + id,
|
||||
title: "Pagos",
|
||||
icon: <PaymentsIcon sx={{ fontSize: "32px", mr: "10px" }} />,
|
||||
});
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -444,41 +512,81 @@ export default function OrganizationEdit() {
|
||||
<Location />
|
||||
|
||||
<SecureByPlan content={SECURE_CONTENTS.PAYMENTS} companyId={id}>
|
||||
<div style={{ maxWidth: "800px", margin: "0 auto", paddingBottom: "100px", marginTop: "0px" }}>
|
||||
|
||||
<div
|
||||
style={{
|
||||
maxWidth: "800px",
|
||||
margin: "0 auto",
|
||||
paddingBottom: "100px",
|
||||
marginTop: "0px",
|
||||
}}
|
||||
>
|
||||
{/* Sentinel element to detect scroll */}
|
||||
<div ref={sentinelRef} style={{ height: "1px", width: "100%" }}></div>
|
||||
|
||||
{/* Top Status Card */}
|
||||
<div style={{ position: "sticky", top: "70px", zIndex: 100, marginBottom: "50px", display: "flex", flexDirection: "column", background: "white", paddingBottom: "10px", paddingTop: "5px", margin: "0 -10px", paddingLeft: "10px", paddingRight: "10px" }}>
|
||||
|
||||
{/* Tabs Selector */}
|
||||
<div style={{ display: "flex", justifyContent: "center", marginBottom: "15px" }}>
|
||||
<ThemeProvider theme={turnosXpressTheme}>
|
||||
<div style={{
|
||||
<div
|
||||
style={{
|
||||
position: "sticky",
|
||||
top: "70px",
|
||||
zIndex: 100,
|
||||
marginBottom: "50px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
background: "white",
|
||||
paddingBottom: "10px",
|
||||
paddingTop: "5px",
|
||||
margin: "0 -10px",
|
||||
paddingLeft: "10px",
|
||||
paddingRight: "10px",
|
||||
}}
|
||||
>
|
||||
{/* Tabs Selector */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
background: "rgba(255,255,255,0.9)",
|
||||
backdropFilter: "blur(10px)",
|
||||
borderRadius: "30px",
|
||||
padding: "5px",
|
||||
boxShadow: "0 4px 15px rgba(0,0,0,0.05)"
|
||||
}}>
|
||||
<ButtonMaterial
|
||||
variant="contained"
|
||||
style={{ borderRadius: "25px", boxShadow: "0 2px 8px rgba(0,0,0,0.1)", fontWeight: "bold", padding: "8px 25px" }}
|
||||
justifyContent: "center",
|
||||
marginBottom: "15px",
|
||||
}}
|
||||
>
|
||||
<ThemeProvider theme={turnosXpressTheme}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
background: "rgba(255,255,255,0.9)",
|
||||
backdropFilter: "blur(10px)",
|
||||
borderRadius: "30px",
|
||||
padding: "5px",
|
||||
boxShadow: "0 4px 15px rgba(0,0,0,0.05)",
|
||||
}}
|
||||
>
|
||||
Pagados
|
||||
</ButtonMaterial>
|
||||
<ButtonMaterial
|
||||
variant="text"
|
||||
onClick={() => goTo(`/admin/org/profile/${id}/payments/not-payed`)}
|
||||
style={{ borderRadius: "25px", color: "#666", fontWeight: "bold", padding: "8px 25px" }}
|
||||
>
|
||||
Adeudados
|
||||
</ButtonMaterial>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
</div>
|
||||
<ButtonMaterial
|
||||
variant="contained"
|
||||
style={{
|
||||
borderRadius: "25px",
|
||||
boxShadow: "0 2px 8px rgba(0,0,0,0.1)",
|
||||
fontWeight: "bold",
|
||||
padding: "8px 25px",
|
||||
}}
|
||||
>
|
||||
Pagados
|
||||
</ButtonMaterial>
|
||||
<ButtonMaterial
|
||||
variant="text"
|
||||
onClick={() =>
|
||||
goTo(`/admin/org/profile/${id}/payments/not-payed`)
|
||||
}
|
||||
style={{
|
||||
borderRadius: "25px",
|
||||
color: "#666",
|
||||
fontWeight: "bold",
|
||||
padding: "8px 25px",
|
||||
}}
|
||||
>
|
||||
Adeudados
|
||||
</ButtonMaterial>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
layout
|
||||
@@ -487,25 +595,33 @@ export default function OrganizationEdit() {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
padding: isMinimized ? "25px 50px" : "40px 20px",
|
||||
borderRadius: isMinimized ? "15px" : "20px"
|
||||
borderRadius: isMinimized ? "15px" : "20px",
|
||||
}}
|
||||
style={{
|
||||
background: "linear-gradient(135deg, #4b6cb7 0%, #182848 100%)",
|
||||
color: "white",
|
||||
textAlign: "center",
|
||||
boxShadow: isMinimized ? "0 4px 15px rgba(0,0,0,0.3)" : "0 10px 30px rgba(0,0,0,0.15)",
|
||||
boxShadow: isMinimized
|
||||
? "0 4px 15px rgba(0,0,0,0.3)"
|
||||
: "0 10px 30px rgba(0,0,0,0.15)",
|
||||
position: "relative",
|
||||
|
||||
display: "flex",
|
||||
flexDirection: isMinimized ? "row" : "column",
|
||||
alignItems: "center",
|
||||
justifyContent: isMinimized ? "space-between" : "center",
|
||||
transition: "box-shadow 0.3s ease"
|
||||
transition: "box-shadow 0.3s ease",
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
onClick={() => setForceMinimized(!forceMinimized)}
|
||||
style={{ position: "absolute", top: "10px", left: "10px", color: "rgba(255,255,255,0.7)", zIndex: 10 }}
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "10px",
|
||||
left: "10px",
|
||||
color: "rgba(255,255,255,0.7)",
|
||||
zIndex: 10,
|
||||
}}
|
||||
size="small"
|
||||
title={forceMinimized ? "Maximizar" : "Minimizar"}
|
||||
>
|
||||
@@ -513,28 +629,59 @@ export default function OrganizationEdit() {
|
||||
</IconButton>
|
||||
<IconButton
|
||||
onClick={() => filter.toggle()}
|
||||
style={{ position: "absolute", top: "10px", right: "10px", color: "rgba(255,255,255,0.7)", zIndex: 10 }}
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "10px",
|
||||
right: "10px",
|
||||
color: "rgba(255,255,255,0.7)",
|
||||
zIndex: 10,
|
||||
}}
|
||||
size="small"
|
||||
title="Filtrar"
|
||||
>
|
||||
<FilterAltOutlinedIcon />
|
||||
</IconButton>
|
||||
<div style={{ position: "absolute", top: "-50px", right: "-50px", width: "150px", height: "150px", borderRadius: "50%", background: "rgba(255,255,255,0.05)" }}></div>
|
||||
<div style={{ position: "absolute", bottom: "-30px", left: "-30px", width: "100px", height: "100px", borderRadius: "50%", background: "rgba(255,255,255,0.05)" }}></div>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "-50px",
|
||||
right: "-50px",
|
||||
width: "150px",
|
||||
height: "150px",
|
||||
borderRadius: "50%",
|
||||
background: "rgba(255,255,255,0.05)",
|
||||
}}
|
||||
></div>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
bottom: "-30px",
|
||||
left: "-30px",
|
||||
width: "100px",
|
||||
height: "100px",
|
||||
borderRadius: "50%",
|
||||
background: "rgba(255,255,255,0.05)",
|
||||
}}
|
||||
></div>
|
||||
|
||||
<motion.div
|
||||
animate={{
|
||||
fontSize: isMinimized ? "14px" : "16px",
|
||||
marginBottom: isMinimized ? "0px" : "10px"
|
||||
marginBottom: isMinimized ? "0px" : "10px",
|
||||
}}
|
||||
style={{
|
||||
fontWeight: "bold",
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: "2px",
|
||||
opacity: 0.9,
|
||||
}}
|
||||
style={{ fontWeight: "bold", textTransform: "uppercase", letterSpacing: "2px", opacity: 0.9 }}
|
||||
>
|
||||
Total Recaudado
|
||||
</motion.div>
|
||||
<motion.div
|
||||
animate={{
|
||||
fontSize: isMinimized ? "24px" : "56px",
|
||||
margin: isMinimized ? "0px" : "10px 0"
|
||||
margin: isMinimized ? "0px" : "10px 0",
|
||||
}}
|
||||
style={{ fontWeight: "900" }}
|
||||
>
|
||||
@@ -547,7 +694,16 @@ export default function OrganizationEdit() {
|
||||
exit={{ opacity: 0 }}
|
||||
style={{ fontSize: "14px", opacity: 0.8 }}
|
||||
>
|
||||
<div style={{ display: "flex", gap: "10px", alignItems: "center", flexWrap: "wrap", justifyContent: "center", marginTop: "10px" }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: "10px",
|
||||
alignItems: "center",
|
||||
flexWrap: "wrap",
|
||||
justifyContent: "center",
|
||||
marginTop: "10px",
|
||||
}}
|
||||
>
|
||||
<div style={{ width: "250px", maxWidth: "100%" }}>
|
||||
<TextRangeDateModern
|
||||
label="Período"
|
||||
@@ -567,10 +723,13 @@ export default function OrganizationEdit() {
|
||||
borderRadius: "20px",
|
||||
padding: "8px 20px",
|
||||
textTransform: "none",
|
||||
height: "56px"
|
||||
height: "56px",
|
||||
}}
|
||||
>
|
||||
<PictureAsPdfIcon style={{ fontSize: "18px", marginRight: "5px" }} /> PDF
|
||||
<PictureAsPdfIcon
|
||||
style={{ fontSize: "18px", marginRight: "5px" }}
|
||||
/>{" "}
|
||||
PDF
|
||||
</ButtonMaterial>
|
||||
</div>
|
||||
</motion.div>
|
||||
@@ -579,10 +738,22 @@ export default function OrganizationEdit() {
|
||||
</div>
|
||||
|
||||
{/* Dynamic Spacer for layout shift */}
|
||||
<div style={{ height: isMinimized ? "100px" : "0px", transition: "height 0.3s ease" }}></div>
|
||||
<div
|
||||
style={{
|
||||
height: isMinimized ? "100px" : "0px",
|
||||
transition: "height 0.3s ease",
|
||||
}}
|
||||
></div>
|
||||
|
||||
{/* Payments List */}
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: "12px", paddingTop: "15px" }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "12px",
|
||||
paddingTop: "15px",
|
||||
}}
|
||||
>
|
||||
{dataList.length > 0 ? (
|
||||
<AnimatePresence>
|
||||
{dataList.map((payment, index) => (
|
||||
@@ -602,43 +773,85 @@ export default function OrganizationEdit() {
|
||||
padding: "16px 20px",
|
||||
boxShadow: "0 4px 12px rgba(0,0,0,0.05)",
|
||||
borderLeft: "5px solid #28a745",
|
||||
position: "relative"
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "15px", flex: 1 }}>
|
||||
<div style={{
|
||||
width: "50px",
|
||||
height: "50px",
|
||||
borderRadius: "12px",
|
||||
backgroundColor: "rgba(40, 167, 69, 0.1)",
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
color: "#28a745"
|
||||
}}>
|
||||
gap: "15px",
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: "50px",
|
||||
height: "50px",
|
||||
borderRadius: "12px",
|
||||
backgroundColor: "rgba(40, 167, 69, 0.1)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
color: "#28a745",
|
||||
}}
|
||||
>
|
||||
{getPaymentIcon(payment.method)}
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
<div style={{ fontSize: "16px", fontWeight: "bold", color: "#333", marginBottom: "2px" }}>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "16px",
|
||||
fontWeight: "bold",
|
||||
color: "#333",
|
||||
marginBottom: "2px",
|
||||
}}
|
||||
>
|
||||
{payment.clientName}
|
||||
</div>
|
||||
<div style={{ fontSize: "14px", color: "var(--wine-dark)", fontWeight: "bold", marginBottom: "4px" }}>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "14px",
|
||||
color: "var(--wine-dark)",
|
||||
fontWeight: "bold",
|
||||
marginBottom: "4px",
|
||||
}}
|
||||
>
|
||||
{payment.serviceName}
|
||||
</div>
|
||||
<div style={{ display: "flex", gap: "10px", fontSize: "12px", color: "#888" }}>
|
||||
<span>{dayjs(payment.createdAt).format("DD MMMM YYYY • HH:mm")}</span>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: "10px",
|
||||
fontSize: "12px",
|
||||
color: "#888",
|
||||
}}
|
||||
>
|
||||
<span>
|
||||
{dayjs(payment.createdAt).format(
|
||||
"DD MMMM YYYY • HH:mm",
|
||||
)}
|
||||
</span>
|
||||
<span>•</span>
|
||||
<span>{payment.employeeName}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "15px" }}>
|
||||
<div style={{
|
||||
fontSize: "20px",
|
||||
fontWeight: "900",
|
||||
color: "#28a745",
|
||||
textAlign: "right"
|
||||
}}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "15px",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "20px",
|
||||
fontWeight: "900",
|
||||
color: "#28a745",
|
||||
textAlign: "right",
|
||||
}}
|
||||
>
|
||||
+{formatPrice(payment.price)}
|
||||
</div>
|
||||
<IconButton
|
||||
@@ -646,14 +859,18 @@ export default function OrganizationEdit() {
|
||||
size="small"
|
||||
onClick={() => {
|
||||
confirm.show(
|
||||
"¿Estás seguro que quieres eliminar el pago de " + payment.clientName + "?",
|
||||
"¿Estás seguro que quieres eliminar el pago de " +
|
||||
payment.clientName +
|
||||
"?",
|
||||
() => deletePaymentHandler(payment.id),
|
||||
() => { }
|
||||
() => {},
|
||||
);
|
||||
}}
|
||||
sx={{
|
||||
backgroundColor: "rgba(220, 53, 69, 0.05)",
|
||||
"&:hover": { backgroundColor: "rgba(220, 53, 69, 0.15)" }
|
||||
"&:hover": {
|
||||
backgroundColor: "rgba(220, 53, 69, 0.15)",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<DeleteIcon fontSize="small" />
|
||||
@@ -666,17 +883,29 @@ export default function OrganizationEdit() {
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
style={{ textAlign: "center", padding: "60px 20px", backgroundColor: "#fff", borderRadius: "15px", border: "1px dashed #ccc" }}
|
||||
style={{
|
||||
textAlign: "center",
|
||||
padding: "60px 20px",
|
||||
backgroundColor: "#fff",
|
||||
borderRadius: "15px",
|
||||
border: "1px dashed #ccc",
|
||||
}}
|
||||
>
|
||||
<SearchOffIcon sx={{ fontSize: "64px", color: "#ccc", marginBottom: "15px" }} />
|
||||
<SearchOffIcon
|
||||
sx={{ fontSize: "64px", color: "#ccc", marginBottom: "15px" }}
|
||||
/>
|
||||
<h2 style={{ margin: 0, color: "#999" }}>Sin Pagos</h2>
|
||||
<p style={{ color: "#aaa" }}>No se encontraron pagos registrados para este período.</p>
|
||||
<p style={{ color: "#aaa" }}>
|
||||
No se encontraron pagos registrados para este período.
|
||||
</p>
|
||||
</motion.div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{payments && payments.pages > 1 && (
|
||||
<div style={{ display: "flex", justifyContent: "center", marginTop: "40px" }}>
|
||||
<div
|
||||
style={{ display: "flex", justifyContent: "center", marginTop: "40px" }}
|
||||
>
|
||||
<Pagination
|
||||
count={payments.pages}
|
||||
page={payments.page}
|
||||
|
||||
@@ -17,6 +17,7 @@ import Avatar from "@components/Avatar/Avatar";
|
||||
import Button from "@core/app/components/Button/Button";
|
||||
import { useConfirmStore } from "@core/Store/Confirm.Store";
|
||||
import { getMondayWeekStart } from "@core/helpers/week";
|
||||
import { useBottomToolbarStore } from "@core/Store/BottomToolbar.Store";
|
||||
|
||||
dayjs.locale("es");
|
||||
|
||||
@@ -28,6 +29,7 @@ export default function Schedules() {
|
||||
const data = useParams<UrlData>();
|
||||
const id = data.id;
|
||||
const location = useLocationStore();
|
||||
const bottomToolbar = useBottomToolbarStore();
|
||||
const eventHandler = useEventHandlerStore();
|
||||
const SessionInfo = useSessionStore();
|
||||
const alert = useAlert();
|
||||
@@ -38,6 +40,8 @@ export default function Schedules() {
|
||||
useEffect(() => {
|
||||
location.clear();
|
||||
|
||||
bottomToolbar.set(<></>);
|
||||
|
||||
location.add({
|
||||
url: "/admin/org",
|
||||
title: "Organizaciones",
|
||||
@@ -55,6 +59,10 @@ export default function Schedules() {
|
||||
title: "Horarios Habilitados",
|
||||
icon: null,
|
||||
});
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -118,7 +126,7 @@ export default function Schedules() {
|
||||
},
|
||||
() => {
|
||||
return;
|
||||
}
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
+22
-11
@@ -80,7 +80,7 @@ export default function OrganizationService() {
|
||||
const [serviceDiscountName, setServiceDiscountName] = useState<string | undefined>(undefined);
|
||||
|
||||
const [servicePublished, setServicePublished] = useState<SERVICE_PUBLISHED_STATUS | undefined>(
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
|
||||
const [savePublishedStatusAvailable, setSavePublishedStatusAvailable] = useState(false);
|
||||
@@ -149,7 +149,7 @@ export default function OrganizationService() {
|
||||
>
|
||||
Aplicar Descuento
|
||||
</ButtonMaterial>
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
}, []);
|
||||
|
||||
@@ -271,8 +271,12 @@ export default function OrganizationService() {
|
||||
setServiceDiscountType(response.discountType);
|
||||
setServiceDiscountValue(response.discountValue);
|
||||
setServiceDiscountName(response.discountName);
|
||||
setShowPublicScores(response.showPublicScores !== undefined ? response.showPublicScores : true);
|
||||
setShowPublicOpinions(response.showPublicOpinions !== undefined ? response.showPublicOpinions : true);
|
||||
setShowPublicScores(
|
||||
response.showPublicScores !== undefined ? response.showPublicScores : true,
|
||||
);
|
||||
setShowPublicOpinions(
|
||||
response.showPublicOpinions !== undefined ? response.showPublicOpinions : true,
|
||||
);
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
@@ -283,7 +287,7 @@ export default function OrganizationService() {
|
||||
const formatDiscount = (
|
||||
value: number | undefined,
|
||||
type: string | undefined,
|
||||
name: string | undefined
|
||||
name: string | undefined,
|
||||
): string => {
|
||||
if (value === undefined || value === null || type === undefined || type === null) {
|
||||
return "";
|
||||
@@ -464,7 +468,7 @@ export default function OrganizationService() {
|
||||
setServicePublished(
|
||||
checked
|
||||
? SERVICE_PUBLISHED_STATUS.PUBLISHED
|
||||
: SERVICE_PUBLISHED_STATUS.PRIVATE
|
||||
: SERVICE_PUBLISHED_STATUS.PRIVATE,
|
||||
);
|
||||
}}
|
||||
/>
|
||||
@@ -506,10 +510,15 @@ export default function OrganizationService() {
|
||||
/>
|
||||
|
||||
<MaterialAlert severity="info" sx={{ marginTop: "20px" }}>
|
||||
<b>Visibilidad pública:</b> Elegí si querés mostrar puntuaciones y opiniones de este servicio en páginas públicas. Disponible para planes pagos.
|
||||
<b>Visibilidad pública:</b> Elegí si querés mostrar puntuaciones y opiniones de este
|
||||
servicio en páginas públicas. Disponible para planes pagos.
|
||||
</MaterialAlert>
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: "10px", marginTop: "10px" }}>
|
||||
<label style={{ display: "flex", alignItems: "center", gap: "10px", fontWeight: 600 }}>
|
||||
<div
|
||||
style={{ display: "flex", flexDirection: "column", gap: "10px", marginTop: "10px" }}
|
||||
>
|
||||
<label
|
||||
style={{ display: "flex", alignItems: "center", gap: "10px", fontWeight: 600 }}
|
||||
>
|
||||
<Switch
|
||||
checked={showPublicScores}
|
||||
disabled={!canEditPublicRatingFlags}
|
||||
@@ -520,7 +529,9 @@ export default function OrganizationService() {
|
||||
/>
|
||||
Mostrar puntuaciones públicas
|
||||
</label>
|
||||
<label style={{ display: "flex", alignItems: "center", gap: "10px", fontWeight: 600 }}>
|
||||
<label
|
||||
style={{ display: "flex", alignItems: "center", gap: "10px", fontWeight: 600 }}
|
||||
>
|
||||
<Switch
|
||||
checked={showPublicOpinions}
|
||||
disabled={!canEditPublicRatingFlags}
|
||||
@@ -567,7 +578,7 @@ export default function OrganizationService() {
|
||||
() => {
|
||||
deleteDiscountHandler();
|
||||
},
|
||||
() => {}
|
||||
() => {},
|
||||
);
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -32,8 +32,9 @@ import {
|
||||
WhatsappIcon as WhatsAppShareIcon,
|
||||
TwitterIcon,
|
||||
EmailIcon,
|
||||
TelegramIcon
|
||||
TelegramIcon,
|
||||
} from "react-share";
|
||||
import { useBottomToolbarStore } from "@core/Store/BottomToolbar.Store";
|
||||
|
||||
type UrlData = {
|
||||
id: string;
|
||||
@@ -43,6 +44,7 @@ export default function Org() {
|
||||
const urlData = useParams<UrlData>();
|
||||
const id = urlData.id;
|
||||
const location = useLocationStore();
|
||||
const bottomToolbar = useBottomToolbarStore();
|
||||
|
||||
const eventHandler = useEventHandlerStore();
|
||||
const alert = useAlert();
|
||||
@@ -58,6 +60,8 @@ export default function Org() {
|
||||
useEffect(() => {
|
||||
location.clear();
|
||||
|
||||
bottomToolbar.set(<></>);
|
||||
|
||||
location.add({
|
||||
url: "/admin/org",
|
||||
title: "Mis organizaciones",
|
||||
@@ -75,6 +79,10 @@ export default function Org() {
|
||||
title: "Mis servicios",
|
||||
icon: <StorefrontOutlinedIcon sx={{ fontSize: "32px", mr: "10px" }} />,
|
||||
});
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -105,7 +113,7 @@ export default function Org() {
|
||||
<div
|
||||
className={style.serviceCard}
|
||||
style={{
|
||||
borderLeft: `6px solid ${data.color}`
|
||||
borderLeft: `6px solid ${data.color}`,
|
||||
}}
|
||||
onClick={() => handleServiceClick(data.id)}
|
||||
>
|
||||
@@ -115,7 +123,11 @@ export default function Org() {
|
||||
<div className={style.serviceInfo}>
|
||||
<h1>{data.name}</h1>
|
||||
<p>{data.description}</p>
|
||||
<ServiceRatingSummary serviceId={data.id} variant="row" showOpinionCount={false} />
|
||||
<ServiceRatingSummary
|
||||
serviceId={data.id}
|
||||
variant="row"
|
||||
showOpinionCount={false}
|
||||
/>
|
||||
</div>
|
||||
<div className={style.serviceActions}>
|
||||
<span className={style.servicePrice}>{formatPrice(data.price)}</span>
|
||||
@@ -159,8 +171,21 @@ export default function Org() {
|
||||
<div style={{ marginBottom: "20px" }}> </div>
|
||||
|
||||
{shareService && (
|
||||
<Dialog open={!!shareService} onClose={() => setShareService(null)} maxWidth="sm" fullWidth>
|
||||
<DialogTitle sx={{ m: 0, p: 2, display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||||
<Dialog
|
||||
open={!!shareService}
|
||||
onClose={() => setShareService(null)}
|
||||
maxWidth="sm"
|
||||
fullWidth
|
||||
>
|
||||
<DialogTitle
|
||||
sx={{
|
||||
m: 0,
|
||||
p: 2,
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<span style={{ fontWeight: "bold" }}>Compartir Servicio</span>
|
||||
<IconButton
|
||||
aria-label="close"
|
||||
@@ -171,23 +196,57 @@ export default function Org() {
|
||||
</IconButton>
|
||||
</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
<div style={{ textAlign: "center", marginBottom: "30px", fontSize: "16px", color: "var(--black-light)" }}>
|
||||
Compartí tu servicio <strong>{shareService.name}</strong> para que tus clientes puedan reservarlo directamente.
|
||||
<div
|
||||
style={{
|
||||
textAlign: "center",
|
||||
marginBottom: "30px",
|
||||
fontSize: "16px",
|
||||
color: "var(--black-light)",
|
||||
}}
|
||||
>
|
||||
Compartí tu servicio <strong>{shareService.name}</strong> para que tus
|
||||
clientes puedan reservarlo directamente.
|
||||
</div>
|
||||
<div style={{ display: "flex", justifyContent: "center", flexDirection: "row", alignItems: "center", gap: "20px", paddingBottom: "20px" }}>
|
||||
<WhatsappShareButton title={"Reserva este servicio: " + shareService.name} separator=":: " url={window.location.origin + "/landing/service/" + shareService.id}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: "20px",
|
||||
paddingBottom: "20px",
|
||||
}}
|
||||
>
|
||||
<WhatsappShareButton
|
||||
title={"Reserva este servicio: " + shareService.name}
|
||||
separator=":: "
|
||||
url={window.location.origin + "/landing/service/" + shareService.id}
|
||||
>
|
||||
<WhatsAppShareIcon size={54} round />
|
||||
</WhatsappShareButton>
|
||||
<FacebookShareButton title={"Reserva este servicio: " + shareService.name} url={window.location.origin + "/landing/service/" + shareService.id}>
|
||||
<FacebookShareButton
|
||||
title={"Reserva este servicio: " + shareService.name}
|
||||
url={window.location.origin + "/landing/service/" + shareService.id}
|
||||
>
|
||||
<FacebookIcon size={54} round />
|
||||
</FacebookShareButton>
|
||||
<EmailShareButton title={"Reserva este servicio: " + shareService.name} separator=":: " url={window.location.origin + "/landing/service/" + shareService.id}>
|
||||
<EmailShareButton
|
||||
title={"Reserva este servicio: " + shareService.name}
|
||||
separator=":: "
|
||||
url={window.location.origin + "/landing/service/" + shareService.id}
|
||||
>
|
||||
<EmailIcon size={54} round />
|
||||
</EmailShareButton>
|
||||
<TelegramShareButton title={"Reserva este servicio: " + shareService.name} url={window.location.origin + "/landing/service/" + shareService.id}>
|
||||
<TelegramShareButton
|
||||
title={"Reserva este servicio: " + shareService.name}
|
||||
url={window.location.origin + "/landing/service/" + shareService.id}
|
||||
>
|
||||
<TelegramIcon size={54} round />
|
||||
</TelegramShareButton>
|
||||
<TwitterShareButton title={"Reserva este servicio: " + shareService.name} url={window.location.origin + "/landing/service/" + shareService.id}>
|
||||
<TwitterShareButton
|
||||
title={"Reserva este servicio: " + shareService.name}
|
||||
url={window.location.origin + "/landing/service/" + shareService.id}
|
||||
>
|
||||
<TwitterIcon size={54} round />
|
||||
</TwitterShareButton>
|
||||
</div>
|
||||
|
||||
+3
-3
@@ -54,7 +54,7 @@ export default function TemplateCreate() {
|
||||
|
||||
const insertAtCursor = (
|
||||
ref: React.RefObject<HTMLInputElement | HTMLTextAreaElement>,
|
||||
insertText: string
|
||||
insertText: string,
|
||||
) => {
|
||||
const el = ref.current;
|
||||
if (!el) return; // todavía no está montado
|
||||
@@ -126,14 +126,14 @@ export default function TemplateCreate() {
|
||||
},
|
||||
() => {
|
||||
eventHandler.setEventType(EVENT_TYPES.NEED_SAVE);
|
||||
}
|
||||
},
|
||||
);
|
||||
}}
|
||||
>
|
||||
Eliminar
|
||||
</ButtonMaterial>
|
||||
)}
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
|
||||
loadTemplate();
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
} from "@models/Templates.model";
|
||||
import { findTemplatesByOrganization } from "./Templates.Service";
|
||||
import { useNavigation } from "@core/app/hooks/goto";
|
||||
import { useBottomToolbarStore } from "@core/Store/BottomToolbar.Store";
|
||||
|
||||
type UrlData = {
|
||||
id: string;
|
||||
@@ -29,6 +30,7 @@ export default function TemplatesGrid() {
|
||||
const oid = data.id;
|
||||
const { goTo } = useNavigation();
|
||||
const location = useLocationStore();
|
||||
const bottomToolbar = useBottomToolbarStore();
|
||||
const eventHandler = useEventHandlerStore();
|
||||
|
||||
const formatType = (type: string) => {
|
||||
@@ -91,8 +93,8 @@ export default function TemplatesGrid() {
|
||||
parseInt(
|
||||
process.env.NEXT_PUBLIC_DATAGRID_PAGE_SIZE
|
||||
? process.env.NEXT_PUBLIC_DATAGRID_PAGE_SIZE
|
||||
: "10"
|
||||
)
|
||||
: "10",
|
||||
),
|
||||
);
|
||||
const [templates, setTemplates] = useState<PaginateTemplatesResults>();
|
||||
|
||||
@@ -103,6 +105,8 @@ export default function TemplatesGrid() {
|
||||
useEffect(() => {
|
||||
location.clear();
|
||||
|
||||
bottomToolbar.set(<></>);
|
||||
|
||||
location.add({
|
||||
url: "/admin/org",
|
||||
title: "Mis organizaciones",
|
||||
@@ -122,6 +126,10 @@ export default function TemplatesGrid() {
|
||||
});
|
||||
|
||||
loadTemplates(1, pageSize);
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const loadTemplates = (page: number = 1, pageSize: number = 30) => {
|
||||
|
||||
@@ -26,6 +26,7 @@ import Image from "next/image";
|
||||
import Switch from "@core/app/components/Switch/Switch";
|
||||
import { useConfirmStore } from "@core/Store/Confirm.Store";
|
||||
import SecureByPlan, { SECURE_CONTENTS } from "@core/app/components/SecureByPlan/SecureByPlan";
|
||||
import { useBottomToolbarStore } from "@core/Store/BottomToolbar.Store";
|
||||
|
||||
type UrlData = {
|
||||
id: string;
|
||||
@@ -35,6 +36,7 @@ export default function OrganizationEdit() {
|
||||
const data = useParams<UrlData>();
|
||||
const id = data.id;
|
||||
const location = useLocationStore();
|
||||
const bottomToolbar = useBottomToolbarStore();
|
||||
const eventHandler = useEventHandlerStore();
|
||||
const SessionInfo = useSessionStore();
|
||||
const alert = useAlert();
|
||||
@@ -46,6 +48,8 @@ export default function OrganizationEdit() {
|
||||
useEffect(() => {
|
||||
location.clear();
|
||||
|
||||
bottomToolbar.set(<></>);
|
||||
|
||||
location.add({
|
||||
url: "/admin/org",
|
||||
title: "Organizaciones",
|
||||
@@ -63,6 +67,10 @@ export default function OrganizationEdit() {
|
||||
title: "Whatsapp",
|
||||
icon: <OrgConfigIcon sx={{ fontSize: "32px", mr: "10px" }} />,
|
||||
});
|
||||
|
||||
return () => {
|
||||
bottomToolbar.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -420,7 +428,7 @@ export default function OrganizationEdit() {
|
||||
eventHandler.setEventType(EVENT_TYPES.SLEEP);
|
||||
});
|
||||
},
|
||||
() => { }
|
||||
() => {},
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user