Commit d6ff0bcc authored by Sonia Vidal Gonzalez's avatar Sonia Vidal Gonzalez

Añadiendo una base de datos Firestore (Links).

parent 60c05689
Pipeline #5465 failed with stages
in 1 second
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -3,12 +3,14 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"bootswatch": "^5.1.1",
"firebase": "^7.24.0",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-redux": "^7.1.3",
"react-router-dom": "^5.1.2",
"react-scripts-ts": "3.1.0",
"react-toastify": "^8.0.2",
"recompose": "^0.30.0",
"redux": "^4.0.4"
},
......
......@@ -4,21 +4,10 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootswatch/4.5.2/darkly/bootstrap.min.css" integrity="sha384-nNK9n28pDUDDgIiIqZ/MiyO3F4/9vsMtReZK39klb/MtkZI3/LtjSjlmyVPS3KdN" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<title>React App</title>
</head>
<body>
......@@ -26,15 +15,5 @@
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
import * as React from "react";
import Links from "../Links/Links";
interface InterfaceProps {
users?: any;
......@@ -15,7 +16,7 @@ export class UserList extends React.Component<InterfaceProps, {}> {
return (
<div>
<h2>List of Usernames of Users</h2>
<p>(Saved on Sign Up in Firebase Database)</p>
<p>(connection with the database in Realtime)</p>
{Object.keys(users).map(key => (
<div key={key}>
......@@ -24,6 +25,9 @@ export class UserList extends React.Component<InterfaceProps, {}> {
</ul>
</div>
))}
<h2>Fill in your links:</h2>
<p>connection to the Firestore database</p>
<Links/>
</div>
);
}
......
import * as React from "react";
import { useEffect, useState } from "react";
import db from "../../firebase/firestore";
interface IPageProps {
addOrEditLink: any;
currentId: any;
}
const LinkForm: React.FunctionComponent<IPageProps> = props =>{
// Constantes iniciales
const initialStateValues = {
url:"",
name:"",
description:"",
}
// Creamos el useState con su estado inicial y su cambio posterior:
const [values, setValues ] = useState(initialStateValues);
// Funcion que maneja el cambio de cada input setea las initialStateValues: la propiedad e.target de cada onchange={} de los input
const handleInputChange = (e: { target: { name: string; value: string; }; }) =>{
const {name, value} = e.target;
setValues({...values, [name]: value });
}
// Para validar la URL por ejemplo: Buscar en google => validate url regex javascript
const validURL = (str: string) => {
const pattern = new RegExp(
"^(https?:\\/\\/)?" + // protocol
"((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|" + // domain name
"((\\d{1,3}\\.){3}\\d{1,3}))" + // OR ip (v4) address
"(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*" + // port and path
"(\\?[;&a-z\\d%_.~+=-]*)?" + // query string
"(\\#[-a-z\\d_]*)?$",
"i"
); // fragment locator
return !!pattern.test(str);
};
// Evento que escucha al enviar el formulario, simplemente para ver que en consola esta funcionando:
const handleSubmit = (e: { preventDefault: () => void; }) => {
e.preventDefault();
// Utilizamos el validador de de la URL para que la gente ponga bien la URL:
if (!validURL(values.url)) {
return console.log("La url no es valida");
}
// Le pasamos las props al addOrEditLink que esta en el component Links y este lo guardara en la base de datos (FIN DEL ASUNTO....)
props.addOrEditLink(values);
// Una vez guardados los datos procedemos a setearlos y de esta manera dejamos limpios los intput:
setValues({...initialStateValues})
}
const getLinkById = async (id: any, ) => {
const doc = await db.collection("links").doc(id).get();
if (doc.exists) {
// console.log(doc.id, " => ", doc.data());
const nomb = [doc.data()?.name];
const pagina = [doc.data()?.url];
const descripcion = [doc.data()?.description];
/* console.log("Nombre del sitio: ",nomb.toString());
console.log("URL del sito: ",pagina.toString());
console.log("Breve descripción: ",descripcion.toString()); */
setValues({
url: pagina.toString(),
name: nomb.toString(),
description: descripcion.toString(),
});
}else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
}
useEffect(() => {
if (props.currentId === "") {
setValues({ ...initialStateValues });
} else {
getLinkById(props.currentId);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.currentId]);
return(
<form onSubmit={handleSubmit} className="card card-body border-primary">
<div className="form-group input-group">
<div className="input-group-text bg-light">
<i className="material-icons">insert_link</i>
</div>
<input style={{ color: "black" }} type="text" className="form-control" placeholder="https://someurl.xyz" value={values.url} name="url" onChange={handleInputChange}/>
</div>
<br/>
<div className="form-group input-group">
<div className="input-group-text bg-light">
<i className="material-icons">create</i>
</div>
<input style={{ color: "black" }} type="text" value={values.name} name="name" placeholder="Website Name" className="form-control" onChange={handleInputChange}/>
</div>
<br/>
<div className="form-group">
<textarea style={{ color: "black" }} className="form-control" placeholder="Write a Description" name="description" value={values.description} onChange={handleInputChange}/>
</div>
<br/>
<button className="btn btn-primary btn-block">
{props.currentId === "" ? "Save" : "Update"}
</button>
</form>
)
}
export default LinkForm;
import * as React from "react";
import { useEffect, useState } from "react";
import LinksForm from "./LinkForm";
// Importacion del firestore
import db from "../../firebase/firestore";
// Importamos toast para mensajes dinamicos (instalamos librería => npm install --save react-toastify)
// import { toast } from "react-toastify";
// import firebase from "firebase";
const Links = () => {
// Creamos el useState con su estado inicial de los (links) y su cambio posterior (setLinks):
;
const [links, setLinks] = useState<any[]>([]);
// Creamos el useState con su estado inicial de los (currentId) y su cambio posterior (setCurrentId):
const [currentId, setCurrentId] = useState("");
// Hacemos la consulta para traernos todos los links de firebase. Es de manera asincrona asi que tenemos que usar async.
// Con onSnapshot hacemos que al renderizar aparaezca al instate.
const getLinks = async () => {
db.collection("links").onSnapshot((querySnapshot) => {
const docs = [] as any;
querySnapshot.forEach((doc) => {
docs.push({ ...doc.data(), id: doc.id });
});
setLinks(docs);
});
};
// Borramos los datos facilmente con el delete() Mandamos un mensaje de si esta seguro de borrar los datos.
// Y creamos un toast para mandar un mensaje dimamico diciendo que lo hemos borrado
const onDeleteLink = async (id: string | undefined) => {
if (window.confirm("are you sure you want to delete this link?")) {
await db.collection("links").doc(id).delete();
console.log("Link Removed Successfully");
}
};
// Con el useEffect cada vez que renderice la página llamará al getLinks() y este traerá los datos.
useEffect(() => {
getLinks();
}, []);
// 2 OPCIONES:
// 1. Añadimos los datos a la colección de firbase seteando el linkObject y creamos otro mensaje dimamico para que se vea.
// 2. Actualizamos los datos a la colección de firbase haciendo un update el linkObject y creamos otro mensaje dimamico para que se vea.
const addOrEditLink = async (linkObject: { [x: string]: any; }) => {
try {
if (currentId === "") {
console.log("Añado datos a la base");
await db.collection("links").doc().set(linkObject);
console.log("New Link Added");
} else {
console.log("Entro en el update");
await db.collection("links").doc(currentId).update(linkObject);
console.log("Link Updated Successfully");
setCurrentId("");
}
} catch (error) {
console.error(error);
}
};
return (
<>
<div className="col-md-4 p-2">
<LinksForm {...{ addOrEditLink, currentId, links }} />
</div>
<div className="col-md-8 p-2">
{links.map((link) => (
<div className="card mb-1" key={link.id}>
<div className="card-body">
<div className="d-flex justify-content-between">
<h4>{link.name}</h4>
<div>
<i
className="material-icons text-danger" style={{ cursor: "pointer" }}
onClick={() => onDeleteLink(link.id)}
>
close
</i>
<i
className="material-icons " style={{ cursor: "pointer" }}
onClick={() => setCurrentId(link.id)}
>
create
</i>
</div>
</div>
<p>{link.description}</p>
<a href={link.url} target="_blank" rel="noopener noreferrer">Go to Website</a>
</div>
</div>
))}
</div>
</>
);
};
export default Links;
\ No newline at end of file
......@@ -19,3 +19,6 @@ if (!firebase.apps.length) {
export const auth = firebase.auth();
export const db = firebase.database();
export default firebase;
import fb from '../firebase/firebase';
import 'firebase/firestore';
export const db = fb.firestore();
// Exportamos el firestore para guardar colecciones, guardar datos.. etc
export default db;
{
"extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"],
"rules": {
"no-console": false,
"jsx-no-lambda": false,
"object-literal-sort-keys": false,
"interface-name": false,
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment