Skip to content
Open
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
9 changes: 9 additions & 0 deletions .learn/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"config": {
"editor": {
"agent": "vscode"
},
"autoPlay": true
},
"currentExercise": null
}
13 changes: 13 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^5.5.0",
"react-router-dom": "^6.18.0"
},
"devDependencies": {
Expand All @@ -27,6 +28,6 @@
"vite": "^4.4.8"
},
"engines": {
"node": ">=20.0.0"
}
"node": ">=20.0.0"
}
}
164 changes: 164 additions & 0 deletions src/ContactForm.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@

body {
background-color: #f8f9fa;
}

.contact-list-container {
max-width: 900px;
margin: 20px auto;
padding: 20px;
background-color: white;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.contact-list-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}

.form-container {
max-width: 600px;
margin: 40px auto;
padding: 20px;
background-color: #fff;
}

.form-title {
text-align: center;
font-size: 24px;
font-weight: 500;
margin-bottom: 30px;
color: #333;
}

.form-group {
margin-bottom: 20px;
}

.label-text {
display: none;
}

.form-input {
width: 100%;
padding: 12px 15px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
font-size: 16px;
color: #6c757d;
}

.form-input:focus {
border-color: #007bff;
outline: none;
box-shadow: 0 0 5px rgba(0, 123, 255, 0.2);
}

.save-button {
width: 100%;
padding: 15px;
margin-top: 10px;
background-color: #0f8878;
color: white;
border: none;
border-radius: 4px;
font-size: 18px;
text-transform: uppercase;
cursor: pointer;
font-weight: 600;
}

.save-button:hover {
background-color: #0056b3;
}

.back-link-container {
text-align: left;
margin-top: 15px;
}

.back-link {
color: #007bff;
font-size: 14px;
text-decoration: underline;
cursor: pointer;
background: none;
border: none;
padding: 0;
margin: 0;
}

/* Contenedor General */
.contact-list-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}

.create-contact-btn {
padding: 10px 15px;
background-color: #007bff; /* Color primario */
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}

.contact-ul {
list-style: none; /* Quita los puntos de la lista */
padding: 0;
}

/* Tarjeta de Contacto (Filas) */
.contact-card {
display: flex;
justify-content: space-between; /* Alinea los detalles a la izquierda y las acciones a la derecha */
align-items: center;
padding: 15px 20px;
margin-bottom: 15px;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
background-color: white;
}

.contact-details {
display: flex;
gap: 20px;
align-items: center;
}

.contact-info p {
margin: 5px 0; /* Espaciado entre las líneas de información */
font-size: 0.95em;
}

/* Acciones (Botones) */
.contact-actions {
display: flex;
gap: 10px;
}

.edit-btn,
.delete-btn {
padding: 8px 12px;
border: 1px solid transparent;
border-radius: 5px;
cursor: pointer;
font-weight: bold;
}

.edit-btn {
background-color: #ffc107; /* Amarillo */
color: #333;
}

.delete-btn {
background-color: #dc3545; /* Rojo */
color: white;
}
26 changes: 13 additions & 13 deletions src/components/ScrollToTop.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,25 @@ import { useEffect, useRef } from "react";
import PropTypes from "prop-types";

// This component allows the scroll to go to the beginning when changing the view,
// otherwise it would remain in the position of the previous view.
// Investigate more about this React behavior :D
// otherwise it would remain in the position of the previous view.
// Investigate more about this React behavior :D

const ScrollToTop = ({ location, children }) => {
const prevLocation = useRef(location);
const prevLocation = useRef(location);

useEffect(() => {
if (location !== prevLocation.current) {
window.scrollTo(0, 0);
}
prevLocation.current = location;
}, [location]);
useEffect(() => {
if (location !== prevLocation.current) {
window.scrollTo(0, 0);
}
prevLocation.current = location;
}, [location]);

return children;
return children;
};

export default ScrollToTop;

ScrollToTop.propTypes = {
location: PropTypes.object,
children: PropTypes.any
};
location: PropTypes.object,
children: PropTypes.any,
};
71 changes: 53 additions & 18 deletions src/main.jsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,57 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import './index.css' // Global styles for your application
import { RouterProvider } from "react-router-dom"; // Import RouterProvider to use the router
import { router } from "./routes"; // Import the router configuration
import { StoreProvider } from './hooks/useGlobalReducer'; // Import the StoreProvider for global state management
import React, { createContext, useReducer } from "react";
import ReactDOM from "react-dom/client";
import "./index.css"; // Global styles for your application
import { RouterProvider } from "react-router-dom"; // Import RouterProvider to use the router
import { router } from "./routes"; // Import the router configuration

export const Context = createContext();

const reducter = (store, action) => {
if (action.type === "CREATE_CONTACT") {
const updatedContactList = [...store.contactList, action.value];
return { ...store, contactList: updatedContactList };
}
if (action.type === "EDIT_CONTACT") {
const updatedContactList = store.contactList.map((contact, index) => {
if (index === action.position) {
return action.value;
}
return contact;
});
return { ...store, contactList: updatedContactList };
}

if (action.type === "REMOVE_CONTACT") {
const updatedContactList = store.contactList.filter((_, index) => {
return action.position !== index;
});
return { ...store, contactList: updatedContactList };
}
return store;
};

const Main = () => {
return (
<React.StrictMode>
{/* Provide global state to all components */}
<StoreProvider>
{/* Set up routing for the application */}
<RouterProvider router={router}>
</RouterProvider>
</StoreProvider>
</React.StrictMode>
);
}
const [store, dispatch] = useReducer(reducter, {
contactList: [
{
name: "",
email: "ejemplo@mail.com",
Phone: "",
Adress: "",
},
],
});

return (
<React.StrictMode>
{/* Provide global state to all components */}
<Context.Provider value={{ store, dispatch }}>
{/* Set up routing for the application */}
<RouterProvider router={router}></RouterProvider>
</Context.Provider>
</React.StrictMode>
);
};

// Render the Main component into the root DOM element.
ReactDOM.createRoot(document.getElementById('root')).render(<Main />)
ReactDOM.createRoot(document.getElementById("root")).render(<Main />);
Loading