Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions src/front/components/Admin/Leads.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@

import { useEffect, useReducer } from "react";
import storeReducer, { initialStore } from "../../store";

const fetchAllLeads = async (dispatch) => {
const apiUrl = import.meta.env.VITE_BACKEND_URL;
dispatch({ type: 'GET_ALL_LEADS_START' })
try {
const response = await fetch(`${apiUrl}/api/leads`)

if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || "Error al obtener los leads");
}
const leadsData = await response.json();
dispatch({ type: 'GET_ALL_LEADS_SUCCESS', payload: leadsData })
} catch (error) {
console.error("Error fetching leads:", error);
dispatch({ type: 'GET_ALL_LEADS_FAILURE', payload: error.message })
}
}

export const Leads = () => {
const [store, dispatch] = useReducer(storeReducer, initialStore());

useEffect(() => {
fetchAllLeads(dispatch);
}, [dispatch])

const { leads, leadsFetchStatus } = store;

if (leadsFetchStatus.status === 'loading') {
return (
<div className="d-flex justify-content-center">
<div className="spinner-border text-warning" role="status">
<span className="visually-hidden">Cargando leads...</span>
</div>
</div>
)
}

if (leadsFetchStatus.status === 'error') {
return (
<div className="alert alert-danger" role="alert">
Error al cargar los leads: {leadsFetchStatus.error}
</div>
)
}

return (
<div className="container">
<div className="row">
<div className="col">
{leads.length === 0 ? (
<p className="text-white">No se encontraron leads</p>
) : (
<table class="table ">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Nombre</th>
<th scope="col">Email</th>
<th scope="col">Teléfono</th>
<th scope="col">Proyecto</th>
<th scope="col">Mensaje</th>
</tr>
</thead>
<tbody>
{leads.map((lead, index) => (
<tr key={lead.id || index}>
<th scope="row">{lead.id || index + 1}</th>
<td>{lead.name}</td>
<td>{lead.email}</td>
<td>{lead.phone}</td>
<td>{lead.company}</td>
<td>{lead.message}</td>
</tr>
))}
</tbody>
</table>
)
}
</div>
</div>
</div>
)
}
40 changes: 20 additions & 20 deletions src/front/components/HeaderAbout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,29 @@ export const HeaderAbout = () => {
const { t } = useTranslation();

return (

<section className="w-100 h-100 mb-5 mt-5 position-relative">
<img src={HomeAbout} alt="CloudTech background image" className="z-n1 mx-auto position-absolute mt-5 w-100 h-100 object-fit-cover d-sm-block"/>
<div className="position-absolute w-100 h-100 bg-dark bg-opacity-50 mx-auto mt-5"></div>
<div className="container w-100 h-100">
<div className="row z-0">
<div className="col-12 col-lg-6 offset-lg-6 my-5 pt-5 d-flex flex-column justify-content-center align-items-center z-1 text-lg-end">
<h1 className="hero-title-home display-3 fw-bolder text-warning mt-sm-0 mt-5 mb-4">
{t('about.sectionTitle')}
</h1>

<p className="hero-subtitle-home fs-5 text-white w-75 mb-5">
{t('about.sectionDescription')}
</p>

<div className="d-flex flex-column justify-content-center flex-md-row gap-3 w-100">
<Link to="/proyectos" className="btn btn-outline-light btn-lg rounded-pill px-5">Proyectos</Link>
<Link to="/contacto" className="btn btn-outline-yellow btn-lg rounded-pill px-5">Contáctanos</Link>
</div>
</div>
<img src={HomeAbout} alt="CloudTech background image" className="z-n1 mx-auto position-absolute mt-5 w-100 h-100 object-fit-cover d-sm-block" />
<div className="position-absolute w-100 h-100 bg-dark bg-opacity-50 mx-auto mt-5"></div>
<div className="container w-100 h-100">
<div className="row z-0">
<div className="col-12 col-lg-6 offset-lg-6 my-5 pt-5 d-flex flex-column justify-content-center align-items-center z-1 text-lg-end">
<h1 className="hero-title-home display-3 fw-bolder text-warning mt-sm-0 mt-5 mb-4">
{t('about.sectionTitle')}
</h1>

<p className="hero-subtitle-home fs-5 text-white w-75 mb-5">
{t('about.sectionDescription')}
</p>

<div className="d-flex flex-column justify-content-center flex-md-row gap-3 w-100">
<Link to="/proyectos" className="btn btn-outline-light btn-lg rounded-pill px-5">{t('headerAbout.portfolioButton')}</Link>
<Link to="/contacto" className="btn btn-outline-yellow btn-lg rounded-pill px-5">{t('headerAbout.contactButton')}</Link>
</div>
</div>
</section>
</div>
</div>
</section>


)
Expand Down
8 changes: 8 additions & 0 deletions src/front/components/ProtectedRoute.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React, { Children } from 'react';
import { Navigate } from 'react-router-dom';

export const ProtectedRoute = ({ children }) => {
const token = localStorage.getItem('accessToken');

return token ? children : <Navigate to="/" />
};
12 changes: 12 additions & 0 deletions src/front/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -362,3 +362,15 @@ h6 {
.text-stat-symbol {
color: #fbff06;
}

/* Admin Styles */

.adminOption {
color: white;
transition: color 0.3s ease;
text-decoration: none;
}

.adminOption:hover {
color: #fbff06;
}
63 changes: 63 additions & 0 deletions src/front/pages/Admin.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { useState, useEffect, useContext } from "react"
import { Link } from "react-router-dom"
import { Leads } from "../components/Admin/Leads"
import { AppContext } from "./Layout"

export const Admin = () => {
const { setShowNavbar, setShowFooter } = useContext(AppContext)
const [activeContent, setActiveContent] = useState("");

useEffect(() => {
if (setShowNavbar || setShowFooter) {
setShowNavbar(false);
setShowFooter(false);
}
return () => {
if (setShowNavbar || setShowFooter) {
setShowNavbar(true);
setShowFooter(true);
}
}
}, [setShowNavbar, setShowFooter])

const handleActiveContent = (contentName) => {
setActiveContent(contentName);
}

const renderContent = () => {
switch (activeContent) {
case 'leads':
return <Leads />
default:
return <h3 className="text-white p-3">Selecciona una opción del panel.</h3>
}
}

return (
<div className="container-fluid">
<div className="row">
<div className="col-md-3 col-lg-2 bg-dark text-white p-3" style={{ "height": "100vh" }}>
<h3 className="fw-bold section-title mb-3 text-center">Panel de Administrador</h3>
<h4 className="mb-4 border-bottom pb-3 text-center">¡Bienvenido!</h4>
<ul className="nav flex-column">
<li><hr class="dropdown-divider" /></li>
<li className="nav-item">
<Link to={""}
className={`adminOption fs-5 ms-4 ${activeContent === 'leads' ? 'fw-bold' : ''}`}
onClick={(e) => {
e.preventDefault();
handleActiveContent('leads');
}}
>
Ver Leads
</Link>
</li>
</ul>
</div>
<div className="col-md-9 col-lg-10 pt-4" style={{ "height": "100vh", overflowY: "auto" }}>
{renderContent()}
</div>
</div>
</div>
)
}
16 changes: 9 additions & 7 deletions src/front/pages/Layout.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useReducer, createContext} from "react"
import React, { useReducer, createContext, useState } from "react"
import { Outlet, useLocation } from "react-router-dom/dist";
import storeReducer, { initialStore } from "../store.js";
import ScrollToTop from "../components/ScrollToTop"
Expand All @@ -13,17 +13,19 @@ export const AppContext = createContext(null);
export const Layout = () => {

const [store, dispatch] = useReducer(storeReducer, initialStore());
const [showNavbar, setShowNavbar] = useState(true)
const [showFooter, setShowFooter] = useState(true)

const location = useLocation();

return (
<AppContext.Provider value={{ store, dispatch }}>
<AppContext.Provider value={{ store, dispatch, showNavbar, setShowNavbar, setShowFooter }}>
<>
<ScrollToTop location={location} />
<Navbar />
<Outlet />
<WhatsappButton />
<Footer />
<ScrollToTop location={location} />
{showNavbar && <Navbar />}
<Outlet />
<WhatsappButton />
{showFooter && <Footer />}
</>
</AppContext.Provider>
)
Expand Down
4 changes: 4 additions & 0 deletions src/front/routes.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { About } from "./pages/About";
import { ServicesPage } from "./pages/Services";
import { Portfolio } from "./pages/Projects";
import { Contact } from "./pages/Contact";
import { Admin } from "./pages/Admin";
import { ProtectedRoute } from "./components/ProtectedRoute";

export const router = createBrowserRouter(
createRoutesFromElements(
Expand All @@ -29,6 +31,8 @@ export const router = createBrowserRouter(
<Route path="/services" element={<ServicesPage />} />
<Route path="/projects" element={<Portfolio />} />
<Route path="/contact" element={<Contact />} />
<Route path="/admin" element={<Admin />} />
{/* <Route path="/admin" element={<ProtectedRoute><Admin /></ProtectedRoute>} /> */}
</Route>
)
);
Loading