first commit

This commit is contained in:
2026-07-16 20:48:43 -03:00
commit 5696cee264
1111 changed files with 322270 additions and 0 deletions
@@ -0,0 +1,227 @@
"use client";
import AnimatedContainer from "@components/AnimatedConainer/AnimatedContainer";
import WhatsAppIcon from "@mui/icons-material/WhatsApp";
import LocationOnIcon from "@mui/icons-material/LocationOn";
import Button from "@core/app/components/Button/Button";
import LocationMap from "@core/app/components/LocationMap/LocationMap";
import EventIcon from "@mui/icons-material/Event";
import LocalOfferIcon from "@mui/icons-material/LocalOffer";
import PersonIcon from "@mui/icons-material/Person";
import AttachMoneyIcon from "@mui/icons-material/AttachMoney";
import { PublicOrganizationView } from "@core/Models/Company.model";
import OrganizationHeader from "@core/app/components/Home/OrganizationHeader/OrganizationHeader";
import { UserAppointmentView, UserAppointmentViewParams } from "@core/Models/Views.model";
import { useEffect, useState } from "react";
import { deleteAppointment, viewAppointment } from "../Appointments.Service";
import { useAlert } from "@core/Store/Alert.Store";
import { useParams } from "next/navigation";
import { EVENT_TYPES, useEventHandlerStore } from "@core/Store/EventHandler.Store";
import { useSessionStore } from "@core/Store/Sesion.Store";
import style from "./page.module.css";
import dayjs from "dayjs";
import "dayjs/locale/es";
import { formatPrice } from "@core/app/helpers/Numbers";
import { DeleteAppointmentParams } from "@core/Models/Appointments.model";
import { useConfirmStore } from "@core/Store/Confirm.Store";
import { useNavigation } from "@core/app/hooks/goto";
import { ScrollToTop } from "@core/app/components/ScrollTop";
dayjs.locale("es");
type UrlData = {
aid: string;
};
type PositionType = [number, number];
export default function OrganizationPublicProfile() {
const data = useParams<UrlData>();
const aid = data.aid;
const [appointmentInfo, setAppointmentInfo] = useState<UserAppointmentView | null>(null);
const [orgData, setOrgData] = useState<PublicOrganizationView | null>(null);
const [position, setPosition] = useState<PositionType>([0, 0]);
const alert = useAlert();
const confirm = useConfirmStore();
const eventHandler = useEventHandlerStore();
const SessionInfo = useSessionStore();
const { goTo } = useNavigation();
const loadAppointmentData = async () => {
const data: UserAppointmentViewParams = {
appointmentId: aid,
sessionUser: SessionInfo.userId,
};
eventHandler.setEventType(EVENT_TYPES.LOADING);
viewAppointment(data)
.then((response) => {
setAppointmentInfo(response);
setOrgData(response.organization);
setPosition([response.organization.latitude, response.organization.longitude]);
})
.catch((error) => {
console.error(error);
alert.showError(error.format());
})
.finally(() => {
eventHandler.setEventType(EVENT_TYPES.SLEEP);
});
};
const handleCancellAppointment = () => {
confirm.show(
"¿Está seguro que desea cancelar el turno?",
() => {
const data: DeleteAppointmentParams = {
id: aid,
validation: true,
sessionUser: SessionInfo.userId,
};
eventHandler.setEventType(EVENT_TYPES.LOADING);
deleteAppointment(data)
.then(() => {
alert.showSuccess("Turno cancelado correctamente.");
setTimeout(() => {
goTo("/landing/my-appointments");
}, 2000);
})
.catch((error) => {
alert.showError(error.format());
})
.finally(() => {
eventHandler.setEventType(EVENT_TYPES.SLEEP);
});
},
() => {}
);
};
useEffect(() => {
if (!SessionInfo.userId) {
eventHandler.setEventType(EVENT_TYPES.SLEEP);
return;
}
loadAppointmentData();
}, [SessionInfo.userId]);
return (
<>
{appointmentInfo && orgData && (
<AnimatedContainer
color={orgData.headerColor}
minSize={150}
maxSize={500}
items={10}
style={{
background: `linear-gradient(180deg, ${orgData.headerColor} 0%, var(--white) 50%)`,
}}
>
<ScrollToTop />
<div className="homeCentered">
<OrganizationHeader organization={orgData} />
<div className={style.organizationContent}>
<div className={style.organizationServices}>
<h1>Detalles de tu Reserva</h1>
<p className={style.introText}>
Bienvenido a los detalles de tu turno. Aquí encontrarás toda la
información sobre tu reserva, así como opciones para cancelarla
o ponerte en contacto directo con nosotros.
</p>
<div className={style.infoGrid}>
<div className={style.infoCard}>
<div className={style.infoIconWrapper}>
<EventIcon />
</div>
<div className={style.infoContent}>
<span className={style.infoLabel}>Fecha y Hora</span>
<span className={style.infoValue}>
{dayjs(appointmentInfo.appointment.appointmentDate)
.format("D [de] MMMM [de] YYYY - HH:mm [hs]")}
</span>
</div>
</div>
<div className={style.infoCard}>
<div className={style.infoIconWrapper}>
<LocalOfferIcon />
</div>
<div className={style.infoContent}>
<span className={style.infoLabel}>Servicio</span>
<span className={style.infoValue}>
{appointmentInfo.appointment.serviceName}
</span>
<span className={style.infoSubValue}>
{appointmentInfo.appointment.serviceDescription}
</span>
</div>
</div>
<div className={style.infoCard}>
<div className={style.infoIconWrapper}>
<PersonIcon />
</div>
<div className={style.infoContent}>
<span className={style.infoLabel}>Profesional</span>
<span className={style.infoValue}>
{appointmentInfo.appointment.collaboratorName}
</span>
</div>
</div>
<div className={style.infoCard}>
<div className={style.infoIconWrapper}>
<AttachMoneyIcon />
</div>
<div className={style.infoContent}>
<span className={style.infoLabel}>Precio</span>
<span className={style.infoValue}>
{formatPrice(appointmentInfo.appointment.price)}
</span>
</div>
</div>
</div>
</div>
<div className={style.organizationMap}>
<h2>Información Útil</h2>
<div className={style.mapWrapper}>
<LocationMap position={position} orgData={orgData} />
</div>
<div className={style.contactInfo}>
<div className={style.contactRow}>
<LocationOnIcon />
<span>{orgData.address}</span>
</div>
<div className={style.contactRow}>
<WhatsAppIcon />
<span>{orgData.phone}</span>
</div>
</div>
<div className={style.actionButtons}>
<Button
color="primary"
text="Cancelar turno"
width="100%"
onClick={handleCancellAppointment}
/>
<Button
color="secondary"
text="Enviar mensaje"
width="100%"
onClick={() => {
goTo(`/landing/org/${orgData.id}/send-message`);
}}
/>
</div>
</div>
</div>
</div>
</AnimatedContainer>
)}
{appointmentInfo === null && <h1>Cargando...</h1>}
</>
);
}