├── .gitignore ├── index.html ├── package-lock.json ├── package.json ├── postcss.config.js ├── public └── _redirects ├── src ├── App.jsx ├── components │ ├── Alerta.jsx │ ├── Busqueda.jsx │ ├── Colaborador.jsx │ ├── FormularioColaborador.jsx │ ├── FormularioProyecto.jsx │ ├── Header.jsx │ ├── ModalEliminarColaborador.jsx │ ├── ModalEliminarTarea.jsx │ ├── ModalFormularioTarea.jsx │ ├── PreviewProyecto.jsx │ ├── Sidebar.jsx │ └── Tarea.jsx ├── config │ └── clienteAxios.jsx ├── context │ ├── AuthProvider.jsx │ └── ProyectosProvider.jsx ├── favicon.svg ├── helpers │ └── formatearFecha.jsx ├── hooks │ ├── useAdmin.jsx │ ├── useAuth.jsx │ └── useProyectos.jsx ├── index.css ├── layouts │ ├── AuthLayout.jsx │ └── RutaProtegida.jsx ├── main.jsx └── paginas │ ├── ConfirmarCuenta.jsx │ ├── EditarProyecto.jsx │ ├── Login.jsx │ ├── NuevoColaborador.jsx │ ├── NuevoPassword.jsx │ ├── NuevoProyecto.jsx │ ├── OlvidePassword.jsx │ ├── Proyecto.jsx │ ├── Proyectos.jsx │ └── Registrar.jsx ├── tailwind.config.js └── vite.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | # Logs 3 | logs 4 | *.log 5 | npm-debug.log* 6 | yarn-debug.log* 7 | yarn-error.log* 8 | pnpm-debug.log* 9 | lerna-debug.log* 10 | 11 | node_modules 12 | dist 13 | dist-ssr 14 | *.local 15 | 16 | # Editor directories and files 17 | .vscode/* 18 | !.vscode/extensions.json 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | UpTask 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "preview": "vite preview" 9 | }, 10 | "dependencies": { 11 | "@headlessui/react": "^1.5.0", 12 | "axios": "^0.25.0", 13 | "react": "^17.0.2", 14 | "react-dom": "^17.0.2", 15 | "react-router-dom": "^6.2.1", 16 | "socket.io-client": "^4.4.1" 17 | }, 18 | "devDependencies": { 19 | "@vitejs/plugin-react": "^1.0.7", 20 | "autoprefixer": "^10.4.2", 21 | "postcss": "^8.4.6", 22 | "tailwindcss": "^3.0.22", 23 | "vite": "^2.8.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /public/_redirects: -------------------------------------------------------------------------------- 1 | /* /index.html 200 -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import { BrowserRouter, Routes, Route } from 'react-router-dom' 2 | 3 | import AuthLayout from './layouts/AuthLayout' 4 | import RutaProtegida from './layouts/RutaProtegida' 5 | 6 | import Login from './paginas/Login' 7 | import Registrar from './paginas/Registrar' 8 | import OlvidePassword from './paginas/OlvidePassword' 9 | import NuevoPassword from './paginas/NuevoPassword' 10 | import ConfirmarCuenta from './paginas/ConfirmarCuenta' 11 | import Proyectos from './paginas/Proyectos' 12 | import NuevoProyecto from './paginas/NuevoProyecto' 13 | import Proyecto from './paginas/Proyecto' 14 | import EditarProyecto from './paginas/EditarProyecto' 15 | import NuevoColaborador from './paginas/NuevoColaborador' 16 | 17 | import {AuthProvider} from './context/AuthProvider' 18 | import {ProyectosProvider} from './context/ProyectosProvider' 19 | 20 | 21 | 22 | function App() { 23 | 24 | 25 | return ( 26 | 27 | 28 | 29 | 30 | }> 31 | } /> 32 | } /> 33 | } /> 34 | } /> 35 | } /> 36 | 37 | 38 | }> 39 | } /> 40 | } /> 41 | } /> 42 | } /> 43 | } /> 44 | 45 | 46 | 47 | 48 | 49 | ) 50 | } 51 | 52 | export default App 53 | -------------------------------------------------------------------------------- /src/components/Alerta.jsx: -------------------------------------------------------------------------------- 1 | const Alerta = ({alerta}) => { 2 | return ( 3 |
4 | {alerta.msg} 5 |
6 | ) 7 | } 8 | 9 | export default Alerta -------------------------------------------------------------------------------- /src/components/Busqueda.jsx: -------------------------------------------------------------------------------- 1 | import { Fragment, useState } from 'react' 2 | import { Combobox, Dialog, Transition } from '@headlessui/react' 3 | import useProyectos from '../hooks/useProyectos' 4 | 5 | function classNames(...classes) { 6 | return classes.filter(Boolean).join(' ') 7 | } 8 | 9 | const Busqueda = () => { 10 | const [ busqueda, setBusqueda ] = useState('') 11 | const { buscador, handleBuscador, proyectos } = useProyectos() 12 | 13 | const proyectosFiltrados = busqueda === '' ? [] : proyectos.filter(proyecto => proyecto.nombre.toLowerCase().includes(busqueda.toLowerCase())) 14 | 15 | return ( 16 | setBusqueda('') }> 17 | 18 | 27 | 28 | 29 | 30 | 39 | (window.location = `/proyectos/${proyecto._id}`) } 43 | > 44 |
45 | setBusqueda(e.target.value)} 49 | /> 50 |
51 | 52 | {proyectosFiltrados.length > 0 && ( 53 | 54 | {proyectosFiltrados.map( proyecto => ( 55 | classNames('cursor-default select-none px-4 py-2', active && 'bg-sky-600 text-white') } 59 | > 60 | {proyecto.nombre} 61 | 62 | ))} 63 | 64 | )} 65 |
66 |
67 |
68 |
69 | ) 70 | } 71 | 72 | export default Busqueda 73 | -------------------------------------------------------------------------------- /src/components/Colaborador.jsx: -------------------------------------------------------------------------------- 1 | import useProyectos from "../hooks/useProyectos" 2 | 3 | const Colaborador = ({colaborador}) => { 4 | const { handleModalEliminarColaborador } = useProyectos() 5 | 6 | const {  nombre, email } = colaborador 7 | 8 | return ( 9 |
10 |
11 |

{nombre}

12 |

{email}

13 |
14 | 15 |
16 | 21 |
22 |
23 | ) 24 | } 25 | 26 | export default Colaborador -------------------------------------------------------------------------------- /src/components/FormularioColaborador.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import useProyectos from '../hooks/useProyectos' 3 | import Alerta from './Alerta' 4 | 5 | const FormularioColaborador = () => { 6 | const [email, setEmail] = useState('') 7 | 8 | const { mostrarAlerta, alerta, submitColaborador } = useProyectos() 9 | 10 | const handleSubmit = e => { 11 | e.preventDefault(); 12 | 13 | if(email === '') { 14 | mostrarAlerta({ 15 | msg: 'El Email es Obligatorio', 16 | error: true 17 | }) 18 | return 19 | } 20 | 21 | submitColaborador(email) 22 | 23 | } 24 | 25 | const { msg } = alerta 26 | 27 | return ( 28 |
32 | {msg && } 33 |
34 | 40 | setEmail(e.target.value)} 47 | /> 48 |
49 | 50 | 55 | 56 | 57 | ) 58 | } 59 | 60 | export default FormularioColaborador -------------------------------------------------------------------------------- /src/components/FormularioProyecto.jsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react' 2 | import { useParams } from 'react-router-dom' 3 | import useProyectos from '../hooks/useProyectos' 4 | import Alerta from './Alerta' 5 | 6 | const FormularioProyecto = () => { 7 | const [id, setId] = useState(null) 8 | const [nombre, setNombre] = useState('') 9 | const [descripcion, setDescripcion] = useState('') 10 | const [fechaEntrega, setFechaEntrega] = useState('') 11 | const [cliente, setCliente] = useState('') 12 | 13 | const params = useParams(); 14 | const { mostrarAlerta, alerta, submitProyecto, proyecto } = useProyectos(); 15 | 16 | useEffect(() => { 17 | if( params.id ) { 18 | setId(proyecto._id) 19 | setNombre(proyecto.nombre) 20 | setDescripcion(proyecto.descripcion) 21 | setFechaEntrega(proyecto.fechaEntrega?.split('T')[0]) 22 | setCliente(proyecto.cliente) 23 | } 24 | }, [params]) 25 | 26 | 27 | const handleSubmit = async e => { 28 | e.preventDefault(); 29 | 30 | if([nombre, descripcion, fechaEntrega, cliente].includes('') ) { 31 | mostrarAlerta({ 32 | msg: 'Todos los Campos son Obligatorios', 33 | error: true 34 | }) 35 | 36 | return 37 | } 38 | 39 | // Pasar los datos hacia el provider 40 | await submitProyecto({ id, nombre, descripcion, fechaEntrega, cliente}) 41 | 42 | setId(null) 43 | setNombre('') 44 | setDescripcion('') 45 | setFechaEntrega('') 46 | setCliente('') 47 | } 48 | 49 | const { msg } = alerta 50 | 51 | return ( 52 |
56 | {msg && } 57 | 58 |
59 | 63 | 64 | setNombre(e.target.value)} 71 | /> 72 |
73 | 74 |
75 | 79 | 80 |