From a676f0ae808c05536cc005a13033fc8e3d0e3489 Mon Sep 17 00:00:00 2001 From: Pedro Caloiero Date: Fri, 14 Oct 2022 11:33:43 -0300 Subject: [PATCH 01/38] 1 --- .../components/utils/Stripe/checkoutForm.js | 82 +++++-------------- client/src/components/utils/Stripe/payment.js | 19 +++++ 2 files changed, 39 insertions(+), 62 deletions(-) diff --git a/client/src/components/utils/Stripe/checkoutForm.js b/client/src/components/utils/Stripe/checkoutForm.js index adf1bcb..84439b6 100644 --- a/client/src/components/utils/Stripe/checkoutForm.js +++ b/client/src/components/utils/Stripe/checkoutForm.js @@ -6,6 +6,10 @@ import { // PaymentRequestButtonElement, useElements, useStripe, + CardNumberElement, + CardExpiryElement, + FpxBankElement, + CardCvcElement // loadStripe } from "@stripe/react-stripe-js"; import swal from 'sweetalert'; @@ -14,32 +18,6 @@ import { NavBar } from "../nav/nav"; import style from './checkoutForm.module.css' const { REACT_APP_HOST } = process.env; -// import subimg1 from "./subimg1.jpg" - - -// const appearance = { -// theme: 'night', -// labels: 'floating' -// }; - -const appearance = { - theme: 'night', - labels: 'floating', - - variables: { - colorPrimary: '#0570de', - colorBackground: '#ffffff', - colorText: '#30313d', - colorDanger: '#df1b41', - fontFamily: 'Ideal Sans, system-ui, sans-serif', - spacingUnit: '2px', - borderRadius: '4px', - // See all possible variables below - } -}; - -// Pass the appearance object to the Elements instance -// const elements = stripe.elements({clientSecret, appearance}); export function PaymentForm() { @@ -57,28 +35,6 @@ export function PaymentForm() { const stripe = useStripe(); const elements = useElements(); - // const element = elements.create('card', { - // style: { - // base: { - // iconColor: '#c4f0ff', - // color: '#fff', - // fontWeight: '500', - // fontFamily: 'Roboto, Open Sans, Segoe UI, sans-serif', - // fontSize: '16px', - // fontSmoothing: 'antialiased', - // ':-webkit-autofill': { - // color: '#fce883', - // }, - // '::placeholder': { - // color: '#87BBFD', - // }, - // }, - // invalid: { - // iconColor: '#FFC7EE', - // color: '#FFC7EE', - // }, - // }, - // }); const createSubscription = async () => { @@ -101,16 +57,6 @@ export function PaymentForm() { }), }); - // const response = await axios.post('localhost:5000/user/premium',{ - // headers: { - // "Content-Type": "application/json", - // }, - // body: JSON.stringify({ - // userName: storageLocal.username, - // userEmail: storageLocal.email, - // paymentMethod: paymentMethod.paymentMethod.id, - // }) - // }) if (!response.ok) return alert("Payment unsuccessful!"); const data = await response.json(); @@ -132,16 +78,28 @@ export function PaymentForm() {
-
- {/* +
+ {/*
*/} + + + + + - -
+ + {/*
+ + + + + + +
*/}
diff --git a/client/src/components/utils/Stripe/payment.js b/client/src/components/utils/Stripe/payment.js index 16e5818..5f4fc18 100644 --- a/client/src/components/utils/Stripe/payment.js +++ b/client/src/components/utils/Stripe/payment.js @@ -6,6 +6,25 @@ import { PaymentForm } from './checkoutForm' const stripePromise = loadStripe("pk_test_51LpumKJocvWwgusfuIDgKMDWBBTXIYMiqNNp1I0a6FOuXMVVnNFrqUOuUmJzvONbAVs0Fc7NAGCCNGm4AumQptBV00bOAnI6rN") +// const appearance = { +// theme: 'night', +// labels: 'floating', + +// variables: { +// colorPrimary: '#0570de', +// colorBackground: '#ffffff', +// colorText: '#30313d', +// colorDanger: '#df1b41', +// fontFamily: 'Ideal Sans, system-ui, sans-serif', +// spacingUnit: '2px', +// borderRadius: '4px', +// // See all possible variables below +// } +// }; + +// const options = { +// appearance +// } export function Payment () { From 8c5f821c504222dafe5ba245efc92371fbf3a0a1 Mon Sep 17 00:00:00 2001 From: Pedro Caloiero Date: Fri, 14 Oct 2022 11:44:23 -0300 Subject: [PATCH 02/38] 1 --- .../controllers/usersControllers/userfree.controller.js | 2 +- client/src/components/utils/Stripe/checkoutForm.js | 8 +------- client/src/components/utils/nav/LoggedUser.js | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/api/src/controllers/usersControllers/userfree.controller.js b/api/src/controllers/usersControllers/userfree.controller.js index b423e0f..3e604bd 100644 --- a/api/src/controllers/usersControllers/userfree.controller.js +++ b/api/src/controllers/usersControllers/userfree.controller.js @@ -49,7 +49,7 @@ const changeToPremium = async (userEmail, userName, paymentMethod) =>{ // console.log('sos vos?¡',user) const factura = await Payment.findOrCreate({where:{ paymenthID: subscription.id, - }}) +}}) // console.log('facturaa',factura) await user.addMonthly_payment(factura.dataValues) diff --git a/client/src/components/utils/Stripe/checkoutForm.js b/client/src/components/utils/Stripe/checkoutForm.js index a6ee3c7..74bebbc 100644 --- a/client/src/components/utils/Stripe/checkoutForm.js +++ b/client/src/components/utils/Stripe/checkoutForm.js @@ -14,7 +14,7 @@ import { } from "@stripe/react-stripe-js"; import swal from 'sweetalert'; import { NavBar } from "../nav/nav"; -import { useNavigate } from "react-router-dom" + import style from './checkoutForm.module.css' const { REACT_APP_HOST } = process.env; @@ -22,17 +22,12 @@ const { REACT_APP_HOST } = export function PaymentForm() { - const navigate2 = useNavigate() - useEffect(() => { const loggedUserSession = window.sessionStorage.getItem("user") if(loggedUserSession){ const userLogged = JSON.parse(loggedUserSession) setUser(userLogged) } - if(!loggedUserSession){ - navigate2("/home") - } },[]) const [user, setUser] = useState('') @@ -94,7 +89,6 @@ export function PaymentForm() { - {/*
diff --git a/client/src/components/utils/nav/LoggedUser.js b/client/src/components/utils/nav/LoggedUser.js index 287d438..ba0f1a7 100644 --- a/client/src/components/utils/nav/LoggedUser.js +++ b/client/src/components/utils/nav/LoggedUser.js @@ -4,7 +4,7 @@ import img from "./logo"; const LoggedUser = (user) => { const renderPages = (user) =>{ - if (user.free) {} + // if (user.free) {} if(user.premium){ return(<> From 27b7fa7a0c1a7daf26a196d805a929ef8a16395c Mon Sep 17 00:00:00 2001 From: facoogle Date: Fri, 14 Oct 2022 12:57:02 -0300 Subject: [PATCH 03/38] Nuevo componente IMC --- .../utils/imcalculator/imcalculator.css | 28 ++++++++++++++++++- .../utils/imcalculator/imcalculator.js | 15 ++++++---- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/client/src/components/utils/imcalculator/imcalculator.css b/client/src/components/utils/imcalculator/imcalculator.css index 509a7bc..c423d5a 100644 --- a/client/src/components/utils/imcalculator/imcalculator.css +++ b/client/src/components/utils/imcalculator/imcalculator.css @@ -1,4 +1,10 @@ +.IMC{ + padding-top: 20px; +} + + .imc-calculator{ + margin-bottom: 20px; background: #56ab2f; /* fallback for old browsers */ background: -webkit-linear-gradient(to right, #a8e063, #56ab2f); /* Chrome 10-25, Safari 5.1-6 */ background: linear-gradient(to right, #a8e063, #56ab2f); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */ @@ -8,9 +14,29 @@ max-width: 800px; align-items: center; border-radius: 10px; - color: white + color: white; + padding-bottom: 200px; } .area-input-calculator h1{ justify-content: center; +} + +.imc-calculator h2{ + max-width: 500px; + padding-top: 10px; + position: absolute; + font-size: 14px; +} + +.imc-calculator h3{ + padding-top: 150px; + position: absolute; + justify-content: center; + +} + + +.IMC .form-control{ + margin: 10px; } \ No newline at end of file diff --git a/client/src/components/utils/imcalculator/imcalculator.js b/client/src/components/utils/imcalculator/imcalculator.js index 41a18dc..c6a3c5c 100644 --- a/client/src/components/utils/imcalculator/imcalculator.js +++ b/client/src/components/utils/imcalculator/imcalculator.js @@ -1,6 +1,7 @@ import React from 'react'; import "./imcalculator.css" import { useState } from 'react'; +import swal from 'sweetalert'; export const CalculatorIMC= ()=>{ @@ -18,9 +19,9 @@ export const CalculatorIMC= ()=>{ const imc = peso / (alt * alt); if(altura === "" && peso === ""){ - alert("[ERROR 404] Por favor, rellene el peso y la altura correctamente !"); + swal("Debes insertar ambos datos, Peso y Altura"); }else if(!alt){ - alert("[ERROR 404] Por favor, rellene el peso y la altura correctamente !"); + swal("Por favor, rellene el peso y la altura correctamente !"); }else if (imc < 16.9){ setMensagem(`Estas muy bajo de peso!`); @@ -61,6 +62,7 @@ export const CalculatorIMC= ()=>{ } return( +

Calculadora de IMC

@@ -88,12 +90,13 @@ export const CalculatorIMC= ()=>{

{mensagem}
{efeitos}
- {imcMessage} +

+

+ {imcMessage} +

-
- © 2022 Nutry-U -
+
); } From 529b2f27881ac95622d2b1d97916af985431dea5 Mon Sep 17 00:00:00 2001 From: facoogle Date: Fri, 14 Oct 2022 13:04:37 -0300 Subject: [PATCH 04/38] nuevo componente --- client/src/components/utils/imcalculator/imcalculator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/utils/imcalculator/imcalculator.js b/client/src/components/utils/imcalculator/imcalculator.js index c6a3c5c..08ddf07 100644 --- a/client/src/components/utils/imcalculator/imcalculator.js +++ b/client/src/components/utils/imcalculator/imcalculator.js @@ -15,7 +15,7 @@ export const CalculatorIMC= ()=>{ function calcularIMC (){ - const alt = altura / 100; + const alt = altura / 100; const imc = peso / (alt * alt); if(altura === "" && peso === ""){ From 6941b4e7ad5f8091430956a3fe72f0ec078a420e Mon Sep 17 00:00:00 2001 From: Pedro Caloiero Date: Fri, 14 Oct 2022 17:46:00 -0300 Subject: [PATCH 05/38] noanda --- .../usersControllers/userfree.controller.js | 10 ++++----- client/package.json | 1 + .../components/utils/Stripe/checkoutForm.js | 21 ++++++++++--------- client/src/components/utils/Stripe/payment.js | 4 ++-- client/src/components/utils/nav/LoggedUser.js | 2 +- 5 files changed, 20 insertions(+), 18 deletions(-) diff --git a/api/src/controllers/usersControllers/userfree.controller.js b/api/src/controllers/usersControllers/userfree.controller.js index 3e604bd..24af20a 100644 --- a/api/src/controllers/usersControllers/userfree.controller.js +++ b/api/src/controllers/usersControllers/userfree.controller.js @@ -49,12 +49,12 @@ const changeToPremium = async (userEmail, userName, paymentMethod) =>{ // console.log('sos vos?¡',user) const factura = await Payment.findOrCreate({where:{ paymenthID: subscription.id, -}}) + }}) + + console.log('facturaa',factura) + user.addMonthly_payment(factura.dataValues) + user.update({ premium: true }) - // console.log('facturaa',factura) - await user.addMonthly_payment(factura.dataValues) - user.update({ premium: true }) - return { message: 'Subscription successfully initiated', diff --git a/client/package.json b/client/package.json index 9c95c7e..d3ddb24 100644 --- a/client/package.json +++ b/client/package.json @@ -25,6 +25,7 @@ "react-router-dom": "^6.4.1", "react-scripts": "^2.1.3", "redux": "^4.2.0", + "stripe": "^10.14.0", "styled-components": "^5.3.6", "sweetalert": "^2.1.2", "web-vitals": "^2.1.4", diff --git a/client/src/components/utils/Stripe/checkoutForm.js b/client/src/components/utils/Stripe/checkoutForm.js index 74bebbc..f05040c 100644 --- a/client/src/components/utils/Stripe/checkoutForm.js +++ b/client/src/components/utils/Stripe/checkoutForm.js @@ -14,7 +14,7 @@ import { } from "@stripe/react-stripe-js"; import swal from 'sweetalert'; import { NavBar } from "../nav/nav"; - +import { useNavigate } from "react-router-dom" import style from './checkoutForm.module.css' const { REACT_APP_HOST } = process.env; @@ -22,13 +22,18 @@ const { REACT_APP_HOST } = export function PaymentForm() { + const navigate2 = useNavigate() useEffect(() => { const loggedUserSession = window.sessionStorage.getItem("user") if(loggedUserSession){ const userLogged = JSON.parse(loggedUserSession) setUser(userLogged) } + if(!loggedUserSession){ + navigate2("/home") + } },[]) + const [user, setUser] = useState('') @@ -78,19 +83,15 @@ export function PaymentForm() {
-
- {/* - - - -
*/} - +
+ + {/* - + */} - +
{/*
diff --git a/client/src/components/utils/Stripe/payment.js b/client/src/components/utils/Stripe/payment.js index 5f4fc18..a35804b 100644 --- a/client/src/components/utils/Stripe/payment.js +++ b/client/src/components/utils/Stripe/payment.js @@ -23,11 +23,11 @@ const stripePromise = loadStripe("pk_test_51LpumKJocvWwgusfuIDgKMDWBBTXIYMiqNNp1 // }; // const options = { -// appearance +// appearance, +// clientSecret // } export function Payment () { - return( diff --git a/client/src/components/utils/nav/LoggedUser.js b/client/src/components/utils/nav/LoggedUser.js index ba0f1a7..287d438 100644 --- a/client/src/components/utils/nav/LoggedUser.js +++ b/client/src/components/utils/nav/LoggedUser.js @@ -4,7 +4,7 @@ import img from "./logo"; const LoggedUser = (user) => { const renderPages = (user) =>{ - // if (user.free) {} + if (user.free) {} if(user.premium){ return(<> From d0836805f7d6bc70809d2a63018bbe99f2498e95 Mon Sep 17 00:00:00 2001 From: Pedro Caloiero Date: Fri, 14 Oct 2022 18:07:18 -0300 Subject: [PATCH 06/38] este si --- .../usersControllers/userfree.controller.js | 10 +++++----- api/src/db.js | 2 +- api/src/models/Payment.js | 1 - 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/api/src/controllers/usersControllers/userfree.controller.js b/api/src/controllers/usersControllers/userfree.controller.js index 24af20a..7b8ffec 100644 --- a/api/src/controllers/usersControllers/userfree.controller.js +++ b/api/src/controllers/usersControllers/userfree.controller.js @@ -47,13 +47,13 @@ const changeToPremium = async (userEmail, userName, paymentMethod) =>{ // console.log('ESTOOO',subscription) const user = await User.findOne({where:{email: userEmail}}) // console.log('sos vos?¡',user) - const factura = await Payment.findOrCreate({where:{ + const factura = await Payment.create({ paymenthID: subscription.id, - }}) + }) - console.log('facturaa',factura) - user.addMonthly_payment(factura.dataValues) - user.update({ premium: true }) + // console.log('facturaa',factura) + await user.addPayment(factura) + user.update({ premium: true }) return { diff --git a/api/src/db.js b/api/src/db.js index a70cde4..cac1c20 100644 --- a/api/src/db.js +++ b/api/src/db.js @@ -66,7 +66,7 @@ User.hasMany(Recipe, {as: "new_recipe", foreignKey: "userId"}) User.hasMany(Favorites, { foreignKey: "userId"}) User.hasMany(Post, { foreignKey: "userId"}) User.hasMany(Ranking, { foreignKey: "userId"}) -User.hasMany(Payment, {as: 'monthly_payment', foreignKey: 'userId'}) +User.hasMany(Payment, { foreignKey: 'userId'}) Payment.belongsTo(User) Favorites.belongsTo(User) Post.belongsTo(User) diff --git a/api/src/models/Payment.js b/api/src/models/Payment.js index 69b20de..4d7bec4 100644 --- a/api/src/models/Payment.js +++ b/api/src/models/Payment.js @@ -1,7 +1,6 @@ const { DataTypes } = require('sequelize'); module.exports = (sequelize) => { - sequelize.define('payment', { paymenthID:{ type: DataTypes.STRING, From 04b1247431d759260b5ae646a54d5555044ec1fe Mon Sep 17 00:00:00 2001 From: Pedro Caloiero Date: Fri, 14 Oct 2022 20:07:50 -0300 Subject: [PATCH 07/38] falta dar estilos --- .../components/utils/Stripe/checkoutForm.js | 54 +++++++++++++------ .../utils/Stripe/checkoutForm.module.css | 6 +++ 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/client/src/components/utils/Stripe/checkoutForm.js b/client/src/components/utils/Stripe/checkoutForm.js index f05040c..c0ea90f 100644 --- a/client/src/components/utils/Stripe/checkoutForm.js +++ b/client/src/components/utils/Stripe/checkoutForm.js @@ -46,7 +46,7 @@ export function PaymentForm() { try { const paymentMethod = await stripe.createPaymentMethod({ - card: elements.getElement("card"), + card: elements.getElement("cardNumber"), type: "card", }); @@ -78,29 +78,49 @@ export function PaymentForm() { } }; + //style + const inputStyle = { + iconColor: '#c4f0ff', + color: '#ff0', + fontWeight: '500', + fontFamily: 'Roboto, Open Sans, Segoe UI, sans-serif', + fontSize: '16px', + fontSmoothing: 'antialiased', + ':-webkit-autofill': { + color: '#fce883', + }, + '::placeholder': { + color: '#87BBFD', + }, +} + return (
-
- - {/* - - - - */} +
+ + + + + + +
- {/*
- - - - - - -
*/} -
diff --git a/client/src/components/utils/Stripe/checkoutForm.module.css b/client/src/components/utils/Stripe/checkoutForm.module.css index 0dfbe21..126e5ce 100644 --- a/client/src/components/utils/Stripe/checkoutForm.module.css +++ b/client/src/components/utils/Stripe/checkoutForm.module.css @@ -15,4 +15,10 @@ padding-top: 25px; padding-bottom: 25px; border-radius: 10px; +} + +.cardInputWrapper{ + border: 2px solid #00f; + border-radius: 8px; + padding: 20px 4px; } \ No newline at end of file From 061240afc2a4e631151896cbb7d544815d9b69bf Mon Sep 17 00:00:00 2001 From: Pedro Caloiero Date: Sat, 15 Oct 2022 15:55:06 -0300 Subject: [PATCH 08/38] Payment method con estilos --- api/src/routes/users/user.js | 2 +- .../components/utils/Stripe/checkoutForm.js | 37 ++++++++----------- .../utils/Stripe/checkoutForm.module.css | 20 +++++++++- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/api/src/routes/users/user.js b/api/src/routes/users/user.js index 6c52b1d..dc68ae3 100644 --- a/api/src/routes/users/user.js +++ b/api/src/routes/users/user.js @@ -43,7 +43,7 @@ router.get("/confirm/:token", confirmAccount); router.post('/premium', async (req,res) =>{ let {userEmail, userName, paymentMethod} = req.body let respuesta = await changeToPremium(userEmail, userName, paymentMethod) - console.log('estoo', JSON.stringify(respuesta)) + // console.log('estoo', JSON.stringify(respuesta)) res.json({ respuesta }) diff --git a/client/src/components/utils/Stripe/checkoutForm.js b/client/src/components/utils/Stripe/checkoutForm.js index c0ea90f..07b5ef4 100644 --- a/client/src/components/utils/Stripe/checkoutForm.js +++ b/client/src/components/utils/Stripe/checkoutForm.js @@ -67,14 +67,15 @@ export function PaymentForm() { const data = await response.json(); // const datae = JSON.parse(data) - console.log('ESTIIIII', data.respuesta) + // console.log('ESTIIIII', data.respuesta) const confirm = await stripe.confirmCardPayment(data.respuesta.clientSecret); if (confirm.error) return alert("Payment unsuccessful!"); - swal("Payment Successful! Subscription active."); + swal("Payment Successful! Subscription active.").then(navigate2('/home')) + } catch (err) { - console.error(err); - swal("Payment failed! " + err.message); + // console.error(err); + swal("Payment failed! Please checkout the given information" ); } }; @@ -100,24 +101,16 @@ export function PaymentForm() {
- - - - - - + +
+ +
+ + + + + +
diff --git a/client/src/components/utils/Stripe/checkoutForm.module.css b/client/src/components/utils/Stripe/checkoutForm.module.css index 126e5ce..0bb1002 100644 --- a/client/src/components/utils/Stripe/checkoutForm.module.css +++ b/client/src/components/utils/Stripe/checkoutForm.module.css @@ -18,7 +18,25 @@ } .cardInputWrapper{ - border: 2px solid #00f; + text-decoration: none; + background-color: rgba(92, 91, 91, 0.261); + border: 2px solid rgb(40, 114, 17); border-radius: 8px; padding: 20px 4px; +} + +.cardInputWrapper:focus{ + outline:none; + background-color: rgba(92, 91, 91, 0.261); + border: 2px solid rgb(40, 114, 17); + border-radius: 8px; + padding: 20px 4px; +} + +.label{ + font-size: 18px; +} + +.button{ + padding-left: 40px; } \ No newline at end of file From c46d934878b42c6e7c204b8f1c8316587d173980 Mon Sep 17 00:00:00 2001 From: facoogle Date: Sat, 15 Oct 2022 16:29:42 -0300 Subject: [PATCH 09/38] ADD Create Calculator --- .../usersControllers/profiles.controllers.js | 52 +++++++++++++++++++ api/src/db.js | 3 +- api/src/models/Profile.js | 25 +++++++++ api/src/routes/users/profiles.js | 20 +++++++ api/src/routes/users/user.js | 4 +- .../utils/imcalculator/imcalculator.css | 5 ++ .../utils/imcalculator/imcalculator.js | 32 ++++++++++-- client/src/components/utils/nav/LoggedUser.js | 2 + client/src/redux/actions/useractions.js | 16 ++++++ 9 files changed, 154 insertions(+), 5 deletions(-) create mode 100644 api/src/controllers/usersControllers/profiles.controllers.js create mode 100644 api/src/models/Profile.js create mode 100644 api/src/routes/users/profiles.js diff --git a/api/src/controllers/usersControllers/profiles.controllers.js b/api/src/controllers/usersControllers/profiles.controllers.js new file mode 100644 index 0000000..48b883b --- /dev/null +++ b/api/src/controllers/usersControllers/profiles.controllers.js @@ -0,0 +1,52 @@ +const { User, Profile } = require("../../db"); + +const CreateImc = async(userId, peso, altura, imc)=>{ + + try { + let user = await User.findByPk(userId); + let userProfile = await Profile.findOne({ + where: { + userId: user.dataValues.id, + }}) + + if(!userProfile && user){ + let newProfile = await Profile.create({ + + userId: user.dataValues.id, + peso: peso, + altura:altura, + imc:imc, + + }); + await user.addProfiles(newProfile); + return { + succes:newProfile + }; + } + if(userProfile && user){ + + let newProfile = await Profile.update( + { peso: peso, altura:altura, imc:imc}, + { + where: { + userId: user.dataValues.id, + }, + }) + + return { + succes:newProfile, + }; + } + + + + } catch (error) { + console.log(error) + } +} + + + +module.exports = { + CreateImc + }; \ No newline at end of file diff --git a/api/src/db.js b/api/src/db.js index cac1c20..b8278df 100644 --- a/api/src/db.js +++ b/api/src/db.js @@ -58,7 +58,7 @@ let capsEntries = entries.map((entry) => [entry[0][0].toUpperCase() + entry[0].s sequelize.models = Object.fromEntries(capsEntries); -const { User, Diet, Recipe, Ingredient, Payment, Favorites, Post, Ranking} = sequelize.models; +const { User, Diet, Recipe, Ingredient, Payment, Favorites, Post, Ranking, Profile} = sequelize.models; // hay que corregir estas relaciones User.hasMany(Diet, {as: "fav_diet", foreignKey: "userId"}) @@ -83,6 +83,7 @@ Favorites.belongsToMany(Recipe,{ through: "recipes_favorites"}) Ingredient.belongsToMany(Recipe,{ through: "recipes_ingredients"}) Diet.belongsToMany(Ingredient,{ through: "diets_ingredients"}) Ingredient.belongsToMany(Diet,{ through: "diets_ingredients"}) +User.hasOne(Profile) diff --git a/api/src/models/Profile.js b/api/src/models/Profile.js new file mode 100644 index 0000000..e04c596 --- /dev/null +++ b/api/src/models/Profile.js @@ -0,0 +1,25 @@ +const { DataTypes } = require('sequelize'); + +module.exports = (sequelize) => { + sequelize.define('profile', { + + imgperfil:{ + type: DataTypes.STRING, + defaultValue: "https://d500.epimg.net/cincodias/imagenes/2016/07/04/lifestyle/1467646262_522853_1467646344_noticia_normal.jpg" + }, + peso:{ + type: DataTypes.TEXT, + + }, + altura:{ + type: DataTypes.TEXT, + + }, + imc:{ + type: DataTypes.TEXT, + + }, + }, { + timestamps: true, + }); +}; \ No newline at end of file diff --git a/api/src/routes/users/profiles.js b/api/src/routes/users/profiles.js new file mode 100644 index 0000000..3f4e019 --- /dev/null +++ b/api/src/routes/users/profiles.js @@ -0,0 +1,20 @@ +const { Router } = require("express"); +const { CreateImc } = require("../../controllers/usersControllers/profiles.controllers") +const auth = require('../../middlewares/auth'); +const router = Router() + +router.post('/calculator',auth ,async (req, res) =>{ + try { + let {userId, peso, altura,imcMessage} = req.body; + console.log("hola soy peso",peso) + let newList = await CreateImc(userId, peso,altura,imcMessage) + res.json(newList) + + } catch (error) { + console.log('err',error) + + } +}) + + +module.exports = router; \ No newline at end of file diff --git a/api/src/routes/users/user.js b/api/src/routes/users/user.js index 6c52b1d..311932c 100644 --- a/api/src/routes/users/user.js +++ b/api/src/routes/users/user.js @@ -1,5 +1,5 @@ const { Router } = require("express"); - +const profiles = require('./profiles') const { User } = require("../../db"); const usersRoutes = require("./users"); const adminRoutes = require("./admin"); @@ -53,5 +53,7 @@ router.post('/premium', async (req,res) =>{ router.post("/forgot-password", forgotPassword) router.post("/new-password/:token", newPassword) +router.use("/profiles", profiles); + module.exports = router; diff --git a/client/src/components/utils/imcalculator/imcalculator.css b/client/src/components/utils/imcalculator/imcalculator.css index c423d5a..006246b 100644 --- a/client/src/components/utils/imcalculator/imcalculator.css +++ b/client/src/components/utils/imcalculator/imcalculator.css @@ -39,4 +39,9 @@ .IMC .form-control{ margin: 10px; +} + +.IMC .btn-secondary{ + margin-top: 185px; + margin-left: -110px; } \ No newline at end of file diff --git a/client/src/components/utils/imcalculator/imcalculator.js b/client/src/components/utils/imcalculator/imcalculator.js index 08ddf07..8cd2c75 100644 --- a/client/src/components/utils/imcalculator/imcalculator.js +++ b/client/src/components/utils/imcalculator/imcalculator.js @@ -1,14 +1,24 @@ import React from 'react'; import "./imcalculator.css" import { useState } from 'react'; +import {useDispatch, useSelector} from "react-redux"; import swal from 'sweetalert'; +import { addCalculator } from '../../../redux/actions/useractions'; export const CalculatorIMC= ()=>{ + const dispatch = useDispatch() + const [peso, setPeso] = useState(""); const [altura, setAltura] = useState(""); + const user = window.sessionStorage.getItem("user") + let userLogged + if(user){ + userLogged = JSON.parse(user) +} + const [mensagem, setMensagem] = useState(""); const [efeitos, setEfeitos] = useState(""); const [imcMessage, setImcMessage] = useState(""); @@ -26,7 +36,7 @@ export const CalculatorIMC= ()=>{ }else if (imc < 16.9){ setMensagem(`Estas muy bajo de peso!`); setEfeitos(`Efectos secundarios: pérdida de cabello, infertilidad, períodos menstruales perdidos.`); - setImcMessage(`Seu IMC é: ${imc.toFixed(2)}`); + setImcMessage(`Su IMC : ${imc.toFixed(2)}`); }else if(imc >= 17 && imc < 18.4){ setMensagem(`Estas bajo de peso !`); @@ -57,10 +67,22 @@ export const CalculatorIMC= ()=>{ setEfeitos(`Efectos secundarios: reflujo, dificultad para moverse, úlceras de decúbito, diabetes, ataque cardíaco, accidente cerebrovascular.`); setImcMessage(`Su IMC es: ${imc.toFixed(2)}`); } - setPeso(""); - setAltura(""); + + } + + const userId = userLogged?userLogged.id:"nada"; + + const handleCalculator = (e) =>{ + e.preventDefault() + dispatch(addCalculator({userId,peso,altura,imcMessage})) + setImcMessage("") + setPeso("") + setAltura("") + setEfeitos("SAVE IN YOUR PROFILE SUCCESS !!!") + setMensagem(``); } + return(
@@ -96,6 +118,10 @@ export const CalculatorIMC= ()=>{ {imcMessage}
+
+ +
+
); diff --git a/client/src/components/utils/nav/LoggedUser.js b/client/src/components/utils/nav/LoggedUser.js index 287d438..9c580d2 100644 --- a/client/src/components/utils/nav/LoggedUser.js +++ b/client/src/components/utils/nav/LoggedUser.js @@ -9,6 +9,7 @@ const LoggedUser = (user) => { return(<> + ) }else if(user.admin){ return(<> @@ -28,6 +29,7 @@ const LoggedUser = (user) => { + ) } diff --git a/client/src/redux/actions/useractions.js b/client/src/redux/actions/useractions.js index 12d6d1a..5024134 100644 --- a/client/src/redux/actions/useractions.js +++ b/client/src/redux/actions/useractions.js @@ -244,4 +244,20 @@ export const deleteList =(listId)=> async(dispatch) =>{ } catch (error) { console.log(error) } +} + +export const addCalculator =(payload)=> async (dispatch) =>{ + try { + let token = JSON.parse(sessionStorage.getItem('token')) + let res = await axios.post(`${url}/user/profiles/calculator`,payload,{ + headers:{ + 'Authorization': `Bearer ${token}`, + 'Accept' : 'application/json', + 'Content-Type': 'application/json' + } + }) + // dispatch(addFavRecipe(res.data)) + } catch (error) { + console.log(error) + } } \ No newline at end of file From 7c001152e955b68d4f27e8fa585005ea2a442e33 Mon Sep 17 00:00:00 2001 From: Pedro Caloiero Date: Sat, 15 Oct 2022 19:35:35 -0300 Subject: [PATCH 10/38] Paymenth con algo de estilos, ta medio feo --- .../components/utils/Stripe/checkoutForm.js | 39 +++++++++++------ .../utils/Stripe/checkoutForm.module.css | 42 ------------------- 2 files changed, 27 insertions(+), 54 deletions(-) delete mode 100644 client/src/components/utils/Stripe/checkoutForm.module.css diff --git a/client/src/components/utils/Stripe/checkoutForm.js b/client/src/components/utils/Stripe/checkoutForm.js index 07b5ef4..42fa522 100644 --- a/client/src/components/utils/Stripe/checkoutForm.js +++ b/client/src/components/utils/Stripe/checkoutForm.js @@ -15,7 +15,7 @@ import { import swal from 'sweetalert'; import { NavBar } from "../nav/nav"; import { useNavigate } from "react-router-dom" -import style from './checkoutForm.module.css' +import './checkoutForm.css' const { REACT_APP_HOST } = process.env; @@ -98,21 +98,36 @@ export function PaymentForm() { return (
-
-
+
+
+

Why you have to be a Premium User?

+
+
+
    +
  • ✅ You can chat with real nutritionists
  • +
  • ✅ You can see more details from the recipes you search
  • +
  • ✅ You will have more slots in your favourite recipe list
  • +
  • ✅ you will have exclusive access to the new features that we implement in the future
  • +
+
+
+
+
- +

BE PREMIUM NOW!

+
+ {/*
- + */}
- - - - - - + + + + + +
- +
diff --git a/client/src/components/utils/Stripe/checkoutForm.module.css b/client/src/components/utils/Stripe/checkoutForm.module.css deleted file mode 100644 index 0bb1002..0000000 --- a/client/src/components/utils/Stripe/checkoutForm.module.css +++ /dev/null @@ -1,42 +0,0 @@ -.paymentContainer{ - margin-top: 50px; - justify-content: center; -} - -.cardContainer{ - display: flex; - max-width: 800px; - justify-content: center; - background: #56ab2f; /* fallback for old browsers */ - background: -webkit-linear-gradient(to right, #a8e063, #56ab2f); /* Chrome 10-25, Safari 5.1-6 */ - background: linear-gradient(to right, #a8e063, #56ab2f); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */ - color: white; - margin: auto; - padding-top: 25px; - padding-bottom: 25px; - border-radius: 10px; -} - -.cardInputWrapper{ - text-decoration: none; - background-color: rgba(92, 91, 91, 0.261); - border: 2px solid rgb(40, 114, 17); - border-radius: 8px; - padding: 20px 4px; -} - -.cardInputWrapper:focus{ - outline:none; - background-color: rgba(92, 91, 91, 0.261); - border: 2px solid rgb(40, 114, 17); - border-radius: 8px; - padding: 20px 4px; -} - -.label{ - font-size: 18px; -} - -.button{ - padding-left: 40px; -} \ No newline at end of file From 47987b12b7af8eaa30c63bdf3733777692b9ac36 Mon Sep 17 00:00:00 2001 From: Pedro Caloiero Date: Sat, 15 Oct 2022 21:18:11 -0300 Subject: [PATCH 11/38] ahora si xd --- .../components/utils/Stripe/checkoutForm.css | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 client/src/components/utils/Stripe/checkoutForm.css diff --git a/client/src/components/utils/Stripe/checkoutForm.css b/client/src/components/utils/Stripe/checkoutForm.css new file mode 100644 index 0000000..431eb8d --- /dev/null +++ b/client/src/components/utils/Stripe/checkoutForm.css @@ -0,0 +1,67 @@ +.paymentContainer{ + margin-top: 50px; + justify-content: center; +} + +.cardContainer{ + display: flex; + max-width: 800px; + justify-content: center; + background: #56ab2f; /* fallback for old browsers */ + background: -webkit-linear-gradient(to right, #a8e063, #56ab2f); /* Chrome 10-25, Safari 5.1-6 */ + background: linear-gradient(to right, #a8e063, #56ab2f); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */ + color: white; + margin: auto; + padding-top: 25px; + padding-bottom: 25px; + border-radius: 10px; +} + +.cardInputWrapper{ + text-decoration: none; + background-color: rgba(92, 91, 91, 0.261); + border: 2px solid rgb(40, 114, 17); + border-radius: 8px; + padding: 20px 4px; +} + +.nameInput{ + text-decoration: none; + background-color: rgba(92, 91, 91, 0.261); + border: 2px solid rgb(40, 114, 17); + border-radius: 8px; + padding: 20px 4px; + box-sizing: border-box; +} + +.cardInputWrapper:focus{ + outline:none; + background-color: rgba(92, 91, 91, 0.261); + border: 2px solid rgb(40, 114, 17); + border-radius: 8px; + padding: 20px 4px; +} + +.label{ + font-size: 16px; +} + +.promotion{ + + flex-direction: row; +} + +.title{ + text-align: center; +} + +.listDiv{ + display: flex; + justify-content: center; +} + +.list{ + font-size: 18px; + padding: 20px; + list-style-type: none; +} \ No newline at end of file From b1d2aafa4da7d7ddb0443f0728f5123327352f93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Duv=C3=A1n=20Merch=C3=A1n?= Date: Sat, 15 Oct 2022 22:38:42 -0500 Subject: [PATCH 12/38] post --- .../PostRanking.controllers.js | 115 ++++++++++++++++++ api/src/db.js | 9 +- api/src/routes/users/post.js | 53 ++++++++ api/src/routes/users/users.js | 3 +- .../recipes/detailrecipe/detailrecipe.js | 67 ++++++++-- .../recipes/detailrecipe/helper/NewPost.js | 33 +++++ .../recipes/detailrecipe/helper/Post.js | 86 +++++++++++++ client/src/components/utils/Modal/Modal.css | 9 +- client/src/components/utils/Modal/Modal.js | 33 +++-- .../utils/SelectFavList/SelectFavList.css | 9 ++ .../utils/SelectFavList/SelectFavList.js | 30 +++-- client/src/hooks/useModal.js | 2 +- client/src/redux/actions/adminAction.js | 2 +- client/src/redux/actions/dietsactions.js | 2 +- client/src/redux/actions/postAction.js | 86 +++++++++++++ client/src/redux/actions/recipeactions.js | 14 ++- client/src/redux/recipeSlice.js | 10 +- client/src/redux/userSlice.js | 10 ++ 18 files changed, 531 insertions(+), 42 deletions(-) create mode 100644 api/src/controllers/usersControllers/PostRanking.controllers.js create mode 100644 api/src/routes/users/post.js create mode 100644 client/src/components/recipes/detailrecipe/helper/NewPost.js create mode 100644 client/src/components/recipes/detailrecipe/helper/Post.js create mode 100644 client/src/components/utils/SelectFavList/SelectFavList.css create mode 100644 client/src/redux/actions/postAction.js diff --git a/api/src/controllers/usersControllers/PostRanking.controllers.js b/api/src/controllers/usersControllers/PostRanking.controllers.js new file mode 100644 index 0000000..b0ddbb6 --- /dev/null +++ b/api/src/controllers/usersControllers/PostRanking.controllers.js @@ -0,0 +1,115 @@ +const { User, Post, Recipe, Ranking } = require("../../db"); + +const getAllPost = async (userId) =>{ + try { + return await User.findByPk(userId, { include: Post } ) + } catch (error) { + console.log(error) + }} + +const getRecipePost = async (recipeId) =>{ + try { + let {posts} = await Recipe.findByPk(recipeId, { include: Post } ) + let post = [] + if(posts){ + await Promise.allSettled( + await posts.map( async( p)=>{ + let user = await User.findByPk(p.userId) + post.push( { + username:user.dataValues.username, + post: p.dataValues, + })})) + return post + } + } catch (error) { + console.log(error) + }} + +const createPost =async (userId, content,recipeId) =>{ + try { + let user = await User.findByPk(userId) + let recipe = await Recipe.findByPk(recipeId) + let newPost = await Post.create({ + content, + userId, + recipeId,}) + + await user.addPost(newPost) + await recipe.addPost(newPost) + return await User.findByPk(userId, { include: Post } ) + } catch (error) { + console.log(error) + }} + +const countRanking = async (recipeId) =>{ + try { + let {count, rows} = await Ranking.findAndCountAll({ + where:{recipeId:recipeId} + }) + let sum = 0 + rows.forEach(ele => { + sum = sum + ele.dataValues.ranking + }); + return sum/count + + } catch (error) { + console.log(error) + } +} + +const addRanking =async (userId , recipeId, ranking) =>{ + try { + let user = await User.findByPk(userId) + let recipe = await Recipe.findByPk(recipeId) + if (!user || !recipe) { + throw new Error('need more data') + }else{ + let newRanking = await Ranking.create({ + ranking, + userId, + recipeId}) + await user.addRanking(newRanking) + await recipe.addRanking(newRanking) + return await Recipe.findByPk(recipeId, { include: Ranking } ) + } + } catch (error) { + console.log(error) + } +} + +const updatePost =async (postId,content) =>{ + try { + let post = await Post.findByPk(postId) + return await post.update({content:content}) + } catch (error) { + console.log(error) + } +} +const updateRanking =async (ranking, rankingId) =>{ + try { + let rank = await Ranking.findByPk(rankingId) + return await rank.update({ranking:ranking}) + } catch (error) { + console.log(error) + } +} +const deletePost =async (postId) =>{ + try { + let post = await Post.findByPk(postId) + await post.destroy() + return('The post was delete') + } catch (error) { + console.log(error) + } +} + +module.exports ={ + getAllPost, + createPost, + getRecipePost, + addRanking, + countRanking, + updateRanking, + updatePost, + deletePost +} \ No newline at end of file diff --git a/api/src/db.js b/api/src/db.js index b8278df..51066da 100644 --- a/api/src/db.js +++ b/api/src/db.js @@ -70,12 +70,15 @@ User.hasMany(Payment, { foreignKey: 'userId'}) Payment.belongsTo(User) Favorites.belongsTo(User) Post.belongsTo(User) -Post.hasMany(Post,{as:'subPost'}) -Post.hasOne(Ranking, {foreignKey:'postId'}) +Post.belongsTo(Recipe) +// Post.hasMany(Post,{as:'subPost'}) +// Post.hasOne(Ranking, {foreignKey:'postId'}) Ranking.belongsTo(User) -Ranking.belongsTo(Post) +Ranking.belongsTo(Recipe) Recipe.belongsTo(User,{ as: "author", foreignKey: "userId"}) Diet.belongsToMany( Recipe,{ through: "diets_recipes"}) +Recipe.hasMany(Post,{ foreignKey: "recipeId"}) +Recipe.hasMany(Ranking,{ foreignKey: "recipeId"}) Recipe.belongsToMany(Diet,{ through: "diets_recipes"}) Recipe.belongsToMany(Ingredient,{ through: "recipes_ingredients"}) Recipe.belongsToMany(Favorites,{ through: "recipes_favorites"}) diff --git a/api/src/routes/users/post.js b/api/src/routes/users/post.js new file mode 100644 index 0000000..f8180b5 --- /dev/null +++ b/api/src/routes/users/post.js @@ -0,0 +1,53 @@ +const { Router } = require("express"); +const { getAllPost, createPost,countRanking, getRecipePost, addRanking, updatePost, updateRanking, deletePost } = require("../../controllers/usersControllers/PostRanking.controllers"); +const router = Router() +const auth = require('../../middlewares/auth'); + +router.get('/:userId',auth, async (req,res)=>{ + let {userId} = req.params + let post = await getAllPost(userId) + res.json(post) +}) +router.post('/:userId',auth, async (req,res)=>{ + let {userId} = req.params + let {content, recipeId} = req.body + let post = await createPost(userId, content, recipeId) + res.json(post) +}) +router.get('/recipe/:recipeId', async (req,res)=>{ + let {recipeId} = req.params + let post = await getRecipePost(recipeId) + res.json(post) +}) +router.get('/reciperank/:recipeId', auth, async (req,res)=>{ + let {recipeId} = req.params + let rank = await countRanking(recipeId) + res.json(rank) +}) +router.patch('/post/:postId', auth, async (req,res)=>{ + let {postId} = req.params + let {content} = req.body + let post = await updatePost(postId,content) + res.json(post) +}) +router.post('/ranking/:recipeId', auth, async (req,res)=>{ + let {recipeId} = req.params + let {ranking, userId} = req.body + let rank = await addRanking(userId , recipeId, ranking) + res.json(rank) +}) +router.patch('/up-ranking', auth, async (req,res)=>{ + let {ranking, rankingId} = req.body + let rank = await updateRanking(ranking, rankingId) + res.json(rank) +}) +router.delete('/post/:postId', auth, async (req,res)=>{ + let {postId} = req.params + console.log('postId',postId) + let post = await deletePost(postId) + res.json(post) +}) + + + +module.exports = router; \ No newline at end of file diff --git a/api/src/routes/users/users.js b/api/src/routes/users/users.js index 7fca34c..bb6526d 100644 --- a/api/src/routes/users/users.js +++ b/api/src/routes/users/users.js @@ -1,12 +1,13 @@ const {Router} = require('express'); const { userInfo } = require('../../controllers/usersControllers/users.controllers'); -const { changeToPremium } = require('../../controllers/usersControllers/userfree.controller'); const auth = require('../../middlewares/auth'); const router = Router() const routeFavorite = require('./favorites') +const routePost = require('./post') router.use('/myfavorite', routeFavorite) +router.use('/post', routePost) // router.patch('/premium', (req,res) =>{ // let user = changeToPremium() diff --git a/client/src/components/recipes/detailrecipe/detailrecipe.js b/client/src/components/recipes/detailrecipe/detailrecipe.js index c9ad0fd..979452b 100644 --- a/client/src/components/recipes/detailrecipe/detailrecipe.js +++ b/client/src/components/recipes/detailrecipe/detailrecipe.js @@ -3,7 +3,7 @@ import React, { useState } from 'react'; import { useDispatch, useSelector } from 'react-redux' import { useEffect, //useState } from 'react'; -import { getRecipeDetail} from '../../../redux/actions/recipeactions'; +import { getRecipeDetail, getRecipePost,} from '../../../redux/actions/recipeactions'; import { useParams } from 'react-router-dom'; import { NavBar } from '../../utils/nav/nav'; @@ -11,20 +11,54 @@ import { NavBar } from '../../utils/nav/nav'; import style from './detail.css' import SelectFavList from '../../utils/SelectFavList/SelectFavList'; +import { useModal } from "../../../hooks/useModal"; +import Modal from "../../utils/Modal/Modal"; +import Post from "./helper/Post"; +import useUser from "../../../hooks/useUser"; +import { createPost, deletePost, updatePost } from "../../../redux/actions/postAction"; +import NewPost from "./helper/NewPost"; const RecipeDetail =()=>{ const dispatch = useDispatch(); const { id } = useParams(); - const [show, setShow ] = useState(false) - const recipe = useSelector(state => state.recipes.detail) + const [isOpen, openModal, closeModal] = useModal(); + const { isLogged, logout } = useUser(); + const recipe = useSelector((state) => state.recipes.detail); + const { detailPost } = useSelector((state) => state.recipes); //setRecipeDetail(recipe) useEffect(() => { dispatch(getRecipeDetail(id)); - console.log(recipe,'ESTAMOS MOSTRANDO RECETA API') + dispatch(getRecipePost(id)); },[]) - + function handleUpdate(postId, value) { + try { + dispatch(updatePost(postId, value)) + setTimeout(() => { + dispatch(getRecipePost(id)) + }, 100); + } catch (error) { + console.log(error); + } + } + function handleDelete(postId) { + try { + alert("Do you wanna delete this list?"); + dispatch(deletePost(postId)) + setTimeout(() => { + dispatch(getRecipePost(id)) + }, 100); + } catch (error) { + console.log(error); + } + } + function handleCreate(content) { + dispatch(createPost(content, id)); + setTimeout(() => { + dispatch(getRecipePost(id)); + }, 100); + } return(
@@ -47,11 +81,10 @@ const RecipeDetail =()=>{
- {show?(<> - ) - :() - } + + + +
@@ -62,6 +95,20 @@ const RecipeDetail =()=>{
recipe
+
+

coments

+ {isLogged ? : null} + {detailPost + ? detailPost.map((post) =>{ + return( ) + }):null + } +
) diff --git a/client/src/components/recipes/detailrecipe/helper/NewPost.js b/client/src/components/recipes/detailrecipe/helper/NewPost.js new file mode 100644 index 0000000..461aa9a --- /dev/null +++ b/client/src/components/recipes/detailrecipe/helper/NewPost.js @@ -0,0 +1,33 @@ +import React, { useState } from "react"; + +const NewPost = ({ onCreate }) => { + const [newValue, setNewValue] = useState(""); + function handleSubmit(e) { + e.preventDefault(); + } + function handleChange(e) { + const value = e.target.value; + setNewValue(value); + } + function handleClickCreate() { + onCreate(newValue); + setNewValue(""); +} + return ( +
+ + +
+ ); + +}; + +export default NewPost; diff --git a/client/src/components/recipes/detailrecipe/helper/Post.js b/client/src/components/recipes/detailrecipe/helper/Post.js new file mode 100644 index 0000000..1b1308a --- /dev/null +++ b/client/src/components/recipes/detailrecipe/helper/Post.js @@ -0,0 +1,86 @@ +import React, { useState } from "react"; + +const Post = ({post, onUpdate, onDelete}) => { + // const dispatch = useDispatch(); + const [isEdit, setIsEdit] = useState(false); + + function ShowPost({post}) { + return ( + <> + {post.post.content} + + + + ); + } + + function EditPost({ post }) { + const [newValue, setNewValue] = useState(post.post.content); + + function handleSubmit(e) { + e.preventDefault(); + } + function handleChange(e) { + const value = e.target.value; + setNewValue(value); + } + function handleClickUpdate() { + onUpdate(post.post.id, newValue); + setIsEdit(false); + } + return ( +
+ + +
+ ); + } + + return ( + +
+

{post.username}

+
+ {isEdit ? : } +
+
+ + ); +}; + +export default Post; diff --git a/client/src/components/utils/Modal/Modal.css b/client/src/components/utils/Modal/Modal.css index 3095a03..22b4db1 100644 --- a/client/src/components/utils/Modal/Modal.css +++ b/client/src/components/utils/Modal/Modal.css @@ -8,22 +8,23 @@ background-color: rgba(0, 0,0, 0.75); display: none; justify-content: center; - align-content: center; + align-items: center; } .modal.is-open{ display: flex; - } .modal-container{ position: relative; min-width: 400px; max-width: 500px; - min-height: 400px; - max-height: 550px; + min-height: 200px; + max-height: 400px; overflow-y: auto; background-color: white; + display: flex; + justify-content: center; } .modal-close{ diff --git a/client/src/components/utils/Modal/Modal.js b/client/src/components/utils/Modal/Modal.js index 29fb2a4..c51fbd4 100644 --- a/client/src/components/utils/Modal/Modal.js +++ b/client/src/components/utils/Modal/Modal.js @@ -1,14 +1,27 @@ -import React from 'react' +import React from "react"; +import './Modal.css' + +const Modal = ({ children, isOpen, closeModal }) => { + const handleModalConteinerClick = (e) => e.stopPropagation(); -const Modal = ({children}) => { return ( -
-
- - {children} -
+
+
+ + {children} +
- ) -} + ); +}; -export default Modal +export default Modal; diff --git a/client/src/components/utils/SelectFavList/SelectFavList.css b/client/src/components/utils/SelectFavList/SelectFavList.css new file mode 100644 index 0000000..6f7eacb --- /dev/null +++ b/client/src/components/utils/SelectFavList/SelectFavList.css @@ -0,0 +1,9 @@ +.list-contein{ + display: grid; + grid-template-rows: 20% 80%; + align-items: center; +} +.checked-item { + background-color:rgb(84, 185, 89); + padding:0.1em 0.2em; + } \ No newline at end of file diff --git a/client/src/components/utils/SelectFavList/SelectFavList.js b/client/src/components/utils/SelectFavList/SelectFavList.js index afda265..1b5ecdc 100644 --- a/client/src/components/utils/SelectFavList/SelectFavList.js +++ b/client/src/components/utils/SelectFavList/SelectFavList.js @@ -1,23 +1,39 @@ -import React, { useEffect } from 'react' +import React, { useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' -import { getLists } from '../../../redux/actions/useractions' +import { addFavorite, getLists } from '../../../redux/actions/useractions' +import './SelectFavList.css' -const SelectFavList = () => { +const SelectFavList = ({recipeId}) => { const dispatch = useDispatch() const {favList} = useSelector((state) => state.user) const {list} = useSelector((state) => state.user) + useEffect(()=>{ dispatch(getLists()) },[]) + const handleCheck = (event) => { + if (event.target.checked) { + dispatch(addFavorite(event.target.value, recipeId)) + // if(!event.target.checked){ + + // } + } + }; + + return ( -
- { +
+

My favorite list

+ {favList? favList.map((f)=>{ return( - {f.name} - )}) +
+ + {f.name} +
+ )}):null }
) diff --git a/client/src/hooks/useModal.js b/client/src/hooks/useModal.js index d083a49..664d9e0 100644 --- a/client/src/hooks/useModal.js +++ b/client/src/hooks/useModal.js @@ -1,6 +1,6 @@ import { useState } from "react"; -export const useModel = (initialValue= false) =>{ +export const useModal = (initialValue= false) =>{ const [isOpen, setIsOpen] = useState(initialValue) const openModal = () => setIsOpen(true) diff --git a/client/src/redux/actions/adminAction.js b/client/src/redux/actions/adminAction.js index 8747e20..d73fbf8 100644 --- a/client/src/redux/actions/adminAction.js +++ b/client/src/redux/actions/adminAction.js @@ -7,7 +7,7 @@ import { getAllRecipes, getAllUsers, getRecipeById, getUserById, banUser, banRec //import {REACT_APP_HOST} from process.env import dotenv from 'dotenv' dotenv.config() -const url = process.env.REACT_APP_HOST +const url = process.env.REACT_APP_HOST || 'http://localhost:5001' //const token = JSON.parse(sessionStorage.getItem('token')) diff --git a/client/src/redux/actions/dietsactions.js b/client/src/redux/actions/dietsactions.js index 094b842..acf30ed 100644 --- a/client/src/redux/actions/dietsactions.js +++ b/client/src/redux/actions/dietsactions.js @@ -4,7 +4,7 @@ import { //filterByDiet, import dotenv from 'dotenv' dotenv.config() - const url = process.env.REACT_APP_HOST + const url = process.env.REACT_APP_HOST || 'http://localhost:5001' export const getDiets =()=>async (dispatch)=>{ diff --git a/client/src/redux/actions/postAction.js b/client/src/redux/actions/postAction.js new file mode 100644 index 0000000..f9042ee --- /dev/null +++ b/client/src/redux/actions/postAction.js @@ -0,0 +1,86 @@ +import axios from 'axios' +import { getUserPost, getUserPosts } from '../userSlice' + + +//-------------------- RUTAS -------------------------- + +//import {REACT_APP_HOST} from process.env +require('dotenv').config() +const url = process.env.REACT_APP_HOST || 'http://localhost:5001' + +//-------------------- ACTIONS ------------------------ + +export const getPosts = () => async (dispatch)=>{ + try { + let user = JSON.parse(sessionStorage.getItem('user')) + let token = JSON.parse(sessionStorage.getItem('token')) + let res = await axios.get(`${url}/user/users/post/${user.id}`,{ + headers:{ + 'Authorization': `Bearer ${token}`, + 'Accept' : 'application/json', + 'Content-Type': 'application/json' + } + }) + dispatch(getUserPosts(res.data)) + } catch (error) { + console.log(error) + } +} +export const createPost = (content, recipeId) => async (dispatch)=>{ + try { + let user = JSON.parse(sessionStorage.getItem('user')) + let token = JSON.parse(sessionStorage.getItem('token')) + await axios.post(`${url}/user/users/post/${user.id}`,{content:content, recipeId:recipeId},{ + headers:{ + 'Authorization': `Bearer ${token}`, + 'Accept' : 'application/json', + 'Content-Type': 'application/json' + } + }) + } catch (error) { + console.log(error) + } +} +export const getPost = () => async (dispatch)=>{ + try { + let user = JSON.parse(sessionStorage.getItem('user')) + let token = JSON.parse(sessionStorage.getItem('token')) + let res = await axios.get(`${url}/user/users/post/recipe/${user.id}`,{ + headers:{ + 'Authorization': `Bearer ${token}`, + 'Accept' : 'application/json', + 'Content-Type': 'application/json' + } + }) + dispatch(getUserPost(res.data)) + } catch (error) { + console.log(error) + } +} +export const updatePost = (postId,content) => async (dispatch)=>{ + try { + let token = JSON.parse(sessionStorage.getItem('token')) + await axios.patch(`${url}/user/users/post/post/${postId}`,{content},{ + headers:{ + 'Authorization': `Bearer ${token}`, + 'Accept' : 'application/json', + 'Content-Type': 'application/json' + }}) + } catch (error) { + console.log(error) + } +} +export const deletePost = (postId) => async (dispatch)=>{ + try { + console.log('postId',postId) + let token = JSON.parse(sessionStorage.getItem('token')) + await axios.delete(`${url}/user/users/post/post/${postId}`,{ + headers:{ + 'Authorization': `Bearer ${token}`, + 'Accept' : 'application/json', + 'Content-Type': 'application/json' + }}) + } catch (error) { + console.log(error) + } +} \ No newline at end of file diff --git a/client/src/redux/actions/recipeactions.js b/client/src/redux/actions/recipeactions.js index bac3ba1..5321ea5 100644 --- a/client/src/redux/actions/recipeactions.js +++ b/client/src/redux/actions/recipeactions.js @@ -1,6 +1,6 @@ import axios from 'axios' import {getAllRecipes, orderByRating, getRecipesByName, - getRecipeById,createRecipe, filterByDiet, getDiets_Recipe + getRecipeById,createRecipe, filterByDiet, getDiets_Recipe, getAllPost } from '../recipeSlice' //-------------------- RUTAS -------------------------- @@ -8,7 +8,8 @@ import {getAllRecipes, orderByRating, getRecipesByName, //import {REACT_APP_HOST} from process.env import dotenv from 'dotenv' dotenv.config() -const url = process.env.REACT_APP_HOST +const url = process.env.REACT_APP_HOST || 'http://localhost:5001' +console.log('process.env.REACT_APP_HOST',process.env.REACT_APP_HOST) //-------------------- ACTIONS ------------------------ export const getRecipes = ()=> async (dispatch) => { @@ -62,7 +63,14 @@ export const filterDiet =(payload)=>async (dispatch)=>{ } } - +export const getRecipePost = (recipeId) => async (dispatch)=>{ + try { + let res = await axios.get(`${url}/user/users/post/recipe/${recipeId}`) + dispatch(getAllPost(res.data)) + } catch (error) { + console.log(error) + } +} // export const getByName = async (dispatch) => { // try{ // let res = await axios.get(`http://${url}/recipes?${name}`) diff --git a/client/src/redux/recipeSlice.js b/client/src/redux/recipeSlice.js index 5a646ba..505b4b6 100644 --- a/client/src/redux/recipeSlice.js +++ b/client/src/redux/recipeSlice.js @@ -7,6 +7,8 @@ export const recipesSlice = createSlice({ recipes:[], detail:{}, allrecipes:[], + detailPost: [], + ranking: 0 }, reducers:{ @@ -31,6 +33,12 @@ export const recipesSlice = createSlice({ deleteRecipe: (state, action)=>{ state.recipes = action.payload }, + getAllPost: (state, action)=>{ + state.detailPost = action.payload + }, + getRanking: (state, action)=>{ + state.ranking = action.payload + }, orderByRating: (state, action)=>{ // eslint-disable-next-line action.payload === "MENOR"? state.recipes.sort((a, b)=>{ @@ -75,6 +83,6 @@ export const recipesSlice = createSlice({ } }) -export const {getAllRecipes, getRecipeById, getRecipesByName, createRecipe, deleteRecipe, orderByRating, filterByDiet, getDiets_Recipe} = recipesSlice.actions +export const {getAllRecipes, getRecipeById, getAllPost, getRanking, getRecipesByName, createRecipe, deleteRecipe, orderByRating, filterByDiet, getDiets_Recipe} = recipesSlice.actions export default recipesSlice.reducer \ No newline at end of file diff --git a/client/src/redux/userSlice.js b/client/src/redux/userSlice.js index 533c6d9..32eadab 100644 --- a/client/src/redux/userSlice.js +++ b/client/src/redux/userSlice.js @@ -6,6 +6,8 @@ export const userSlice = createSlice({ user: {}, favList: [], list: {}, + userPost: [], + post:{} }, reducers: { getUser: (state, action) => { @@ -33,6 +35,12 @@ export const userSlice = createSlice({ deleteListById: (state, action) => { state.favList = action.payload; }, + getUserPosts:(state, action) => { + state.userPost = action.payload; + }, + getUserPost:(state, action) => { + state.post = action.payload; + }, // getUserStatus: (state, action)=>{ // state.logged = action.payload @@ -55,6 +63,8 @@ export const { removeFavRecipe, updateNameList, deleteListById, + getUserPosts, + getUserPost, getUserStatus, createUser, deleteUser, From 26de7634b87a8d44fdb4a13a96b282965309aa6a Mon Sep 17 00:00:00 2001 From: facoogle Date: Sun, 16 Oct 2022 18:07:41 -0300 Subject: [PATCH 13/38] varios cambios --- .../usersControllers/profiles.controllers.js | 61 ++++++++++++++++++- api/src/routes/users/profiles.js | 27 +++++++- .../components/utils/Stripe/checkoutForm.js | 2 +- client/src/pages/userBoart.js/userProfile.css | 52 ++++++++++++++-- client/src/pages/userBoart.js/userProfile.js | 59 +++++++++++++----- client/src/redux/actions/useractions.js | 35 ++++++++++- client/src/redux/userSlice.js | 6 +- 7 files changed, 217 insertions(+), 25 deletions(-) diff --git a/api/src/controllers/usersControllers/profiles.controllers.js b/api/src/controllers/usersControllers/profiles.controllers.js index 48b883b..00d052f 100644 --- a/api/src/controllers/usersControllers/profiles.controllers.js +++ b/api/src/controllers/usersControllers/profiles.controllers.js @@ -47,6 +47,65 @@ const CreateImc = async(userId, peso, altura, imc)=>{ +const uploadProfile = async(userId, img)=>{ + + try { + let user = await User.findByPk(userId); + let userProfile = await Profile.findOne({ + where: { + userId: user.dataValues.id, + }}) + + if(!userProfile && user){ + let newProfile = await Profile.create({ + + userId: user.dataValues.id, + imgperfil:img + + }); + await user.addProfiles(newProfile); + return { + succes:"ProfileNew" + }; + } + if(userProfile && user){ + + let newProfile = await Profile.update( + { imgperfil: img}, + { + where: { + userId: user.dataValues.id, + }, + }) + + return { + succes:"newProfile", + }; + } + + + + } catch (error) { + console.log(error) + } +} + + +const listProfile = async (userId) => { + try { + let pro = await Profile.findAll({ + where: { + userId:userId + }, + }); + return pro; + } catch (error) { + console.log( error); + } +}; + module.exports = { - CreateImc + CreateImc, + uploadProfile, + listProfile }; \ No newline at end of file diff --git a/api/src/routes/users/profiles.js b/api/src/routes/users/profiles.js index 3f4e019..56a5405 100644 --- a/api/src/routes/users/profiles.js +++ b/api/src/routes/users/profiles.js @@ -1,5 +1,5 @@ const { Router } = require("express"); -const { CreateImc } = require("../../controllers/usersControllers/profiles.controllers") +const { CreateImc, uploadProfile, listProfile } = require("../../controllers/usersControllers/profiles.controllers") const auth = require('../../middlewares/auth'); const router = Router() @@ -16,5 +16,30 @@ router.post('/calculator',auth ,async (req, res) =>{ } }) +router.post('/uploadimg',auth ,async (req, res) =>{ + try { + let {userId, image} = req.body; + let newList = await uploadProfile(userId, image) + res.json(newList) + + } catch (error) { + console.log('err',error) + + } +}) + +router.get('/profiles/:userId',auth ,async (req, res) =>{ + try { + let {userId} = req.params; + + let newList = await listProfile(userId) + res.json(newList) + + } catch (error) { + console.log('err',error) + + } +}) + module.exports = router; \ No newline at end of file diff --git a/client/src/components/utils/Stripe/checkoutForm.js b/client/src/components/utils/Stripe/checkoutForm.js index 42fa522..de522da 100644 --- a/client/src/components/utils/Stripe/checkoutForm.js +++ b/client/src/components/utils/Stripe/checkoutForm.js @@ -15,7 +15,7 @@ import { import swal from 'sweetalert'; import { NavBar } from "../nav/nav"; import { useNavigate } from "react-router-dom" -import './checkoutForm.css' +//import './checkoutForm.css' const { REACT_APP_HOST } = process.env; diff --git a/client/src/pages/userBoart.js/userProfile.css b/client/src/pages/userBoart.js/userProfile.css index efd5f0a..424a171 100644 --- a/client/src/pages/userBoart.js/userProfile.css +++ b/client/src/pages/userBoart.js/userProfile.css @@ -1,3 +1,9 @@ +.profileprincipal{ + display: flex; + justify-content: center; + align-items: center; +} + .userprofile { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr; @@ -23,34 +29,68 @@ padding: 1em; background: #f9f9f9; border: 1px solid #c1c1c1; + background-color: green; } .username1 { grid-area: username1; margin-top: 50px; margin-left: 170px; + background-color: aqua; } .userimage { + margin-top: 15px; - grid-area: userimage; + margin-left: 130px; } .userimage1 { - border-radius: 4%; + min-width: 200px; + max-width: 200px; + min-height: 200px; + max-height: 200px; + width: 200px; + height: 200px; + border-radius: 100%; + border: solid 5px black; +} + +.userimage h3{ + min-width: 200px; + max-width: 200px; + min-height: 200px; + max-height: 200px; } .upload1 { - grid-area: upload1; - margin-top: 300px; - margin-left: 430px; + + } .list { grid-area: list; margin-left: 80px; + background-color: chartreuse; } .list1 { grid-area: list1; margin-left: 30px; -} \ No newline at end of file + background-color: chocolate; +} + + + +.btn-cam{ + + align-items: center; + justify-content: center; + font-size: 25px; +} + + +.upload1 input{ + background-color: blueviolet; + display: none; +} + diff --git a/client/src/pages/userBoart.js/userProfile.js b/client/src/pages/userBoart.js/userProfile.js index ac6dac0..44f096b 100644 --- a/client/src/pages/userBoart.js/userProfile.js +++ b/client/src/pages/userBoart.js/userProfile.js @@ -5,12 +5,12 @@ import Info from '../../components/usersBoart/Info'; import List from '../../components/usersBoart/List'; import NewList from '../../components/usersBoart/NewList'; import { NavBar } from '../../components/utils/nav/nav'; -import { changeListName, createList, deleteList, getIdList, getLists, getUserDetail, removeFavorite } from '../../redux/actions/useractions'; +import { changeListName, createList, deleteList, getIdList, getLists, getUserDetail, removeFavorite, uploadImg,getProfileData } from '../../redux/actions/useractions'; import "./userProfile.css" -import { useNavigate } from "react-router-dom" +import { useNavigate, useRevalidator } from "react-router-dom" const UserProfile = () => { @@ -19,11 +19,13 @@ const UserProfile = () => { const {user} =useSelector((state)=>state.user) const {favList} = useSelector((state) => state.user) const {list} = useSelector((state) => state.user) + const {profile} = useSelector((state) => state.user) const [ image, setImage ] = useState("") const [ loading, setLoading ] = useState(false) const uploadImage = async (e) => { + const files = e.target.files; const data = new FormData(); data.append("file", files[0]) @@ -50,11 +52,17 @@ const UserProfile = () => { useEffect(()=>{ if(!loggedUserSession){navigate2("/home")} dispatch(getUserDetail()) + },[]) useEffect(()=>{ dispatch(getLists()) },[]) - + useEffect(()=>{ + dispatch(getProfileData(userId)) + + + },[dispatch]) + console.log("hola soy getProfileData", profile) function handleUpdate(id, value){ try { dispatch(changeListName(id, value)) @@ -96,31 +104,54 @@ const UserProfile = () => { dispatch(getIdList(id)) } + let userLogged + if(loggedUserSession){ + userLogged = JSON.parse(loggedUserSession) + } + + const userId = userLogged?userLogged.id:"nada"; + + const postImg = (e) => { + e.preventDefault() + dispatch(uploadImg({userId,image})) + + } + return (
-
- -
- -
- -
- {loading ? (

Loading picture...

) : ()} +
+ + +
+ {loading ? (

Loading picture...

) : ()}
-
Upload your profile picture
- 📷 + + +
+
+
+
+ +
+ +
+ +

My Lists

diff --git a/client/src/redux/actions/useractions.js b/client/src/redux/actions/useractions.js index 5024134..1ec5bc9 100644 --- a/client/src/redux/actions/useractions.js +++ b/client/src/redux/actions/useractions.js @@ -1,6 +1,6 @@ import axios from 'axios' import { getUser, getUserById, getUserStatus, getAllList, getListById, addFavRecipe, removeFavRecipe, - updateNameList, deleteListById,//createUser, deleteUser + updateNameList, deleteListById, getProfile,//createUser, deleteUser } from '../userSlice' import swal from 'sweetalert'; @@ -260,4 +260,37 @@ export const addCalculator =(payload)=> async (dispatch) =>{ } catch (error) { console.log(error) } +} + +export const uploadImg =(payload)=> async (dispatch) =>{ + try { + let token = JSON.parse(sessionStorage.getItem('token')) + let res = await axios.post(`${url}/user/profiles/uploadimg`,payload,{ + headers:{ + 'Authorization': `Bearer ${token}`, + 'Accept' : 'application/json', + 'Content-Type': 'application/json' + } + }) + // dispatch(addFavRecipe(res.data)) + } catch (error) { + console.log(error) + } +} + +export const getProfileData =(userId) => async (dispatch) =>{ + try { + let token = JSON.parse(sessionStorage.getItem('token')) + let res = await axios.get(`${url}/user/profiles/profiles/${userId}` ,{ + headers:{ + 'Authorization': `Bearer ${token}`, + 'Accept' : 'application/json', + 'Content-Type': 'application/json' + } + }) + //console.log("soy RESSSS", res.data) + dispatch(getProfile(res.data)) + } catch (error) { + console.log(error) + } } \ No newline at end of file diff --git a/client/src/redux/userSlice.js b/client/src/redux/userSlice.js index 533c6d9..204215e 100644 --- a/client/src/redux/userSlice.js +++ b/client/src/redux/userSlice.js @@ -6,6 +6,7 @@ export const userSlice = createSlice({ user: {}, favList: [], list: {}, + profile:{} }, reducers: { getUser: (state, action) => { @@ -33,7 +34,9 @@ export const userSlice = createSlice({ deleteListById: (state, action) => { state.favList = action.payload; }, - + getProfile: (state, action) => { + state.profile = action.payload; + }, // getUserStatus: (state, action)=>{ // state.logged = action.payload // }, @@ -58,6 +61,7 @@ export const { getUserStatus, createUser, deleteUser, + getProfile, } = userSlice.actions; export default userSlice.reducer; From 38cb77712a123494d1ee1a814ad85df7d0ed1de6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Duv=C3=A1n=20Merch=C3=A1n?= Date: Sun, 16 Oct 2022 18:37:58 -0500 Subject: [PATCH 14/38] ranking complete --- api/package.json | 3 +- api/src/controllers/recipescontrollers.js | 4 +- .../PostRanking.controllers.js | 22 ++++++++- api/src/routes/recipe.js | 14 +++++- api/src/routes/users/post.js | 38 ++++++++------- .../recipes/detailrecipe/detailrecipe.js | 15 +++++- .../detailrecipe/helper/RankingPost.js | 43 +++++++++++++++++ .../src/components/usersBoart/FavoriteList.js | 2 +- client/src/components/usersBoart/UserPost.js | 12 +++++ client/src/pages/userBoart.js/userProfile.css | 42 ++++++++++++----- client/src/pages/userBoart.js/userProfile.js | 36 +++++++++++---- client/src/redux/actions/postAction.js | 46 ++++++++++++++++++- client/src/redux/actions/recipeactions.js | 13 ++++-- client/src/redux/userSlice.js | 7 ++- 14 files changed, 248 insertions(+), 49 deletions(-) create mode 100644 client/src/components/recipes/detailrecipe/helper/RankingPost.js create mode 100644 client/src/components/usersBoart/UserPost.js diff --git a/api/package.json b/api/package.json index f76ced8..77512a9 100644 --- a/api/package.json +++ b/api/package.json @@ -22,7 +22,8 @@ "nodemailer": "^6.8.0", "pg": "^8.8.0", "sequelize": "^6.23.2", - "stripe": "^10.13.0" + "stripe": "^10.13.0", + "uuid": "^9.0.0" }, "devDependencies": { "nodemon": "^2.0.20" diff --git a/api/src/controllers/recipescontrollers.js b/api/src/controllers/recipescontrollers.js index 5cf23e8..f4dbd71 100644 --- a/api/src/controllers/recipescontrollers.js +++ b/api/src/controllers/recipescontrollers.js @@ -2,7 +2,7 @@ const axios = require ("axios") const { API_KEY } = process.env const { Recipe, Diet } = require("../db.js") // import dietTypes from '../utils/apispoon' - +const uuid = require('uuid'); const getApiRecipes = async() => { @@ -14,6 +14,7 @@ const getApiRecipes = async() => { if(results !== 0 ) { let dishRecipe = await results?.map((e) => { return { + //id: uuid.v4(), id: e.id, name: e.title, healthScore: e.healthScore, @@ -72,6 +73,7 @@ const getApiNameRecipes = async(name) => { if(results !==0) { let dishName = results?.map((el) => { return { + id: el.id, name: el.title, healthScore: el.healthScore, diff --git a/api/src/controllers/usersControllers/PostRanking.controllers.js b/api/src/controllers/usersControllers/PostRanking.controllers.js index b0ddbb6..f9d23d6 100644 --- a/api/src/controllers/usersControllers/PostRanking.controllers.js +++ b/api/src/controllers/usersControllers/PostRanking.controllers.js @@ -56,14 +56,33 @@ const countRanking = async (recipeId) =>{ console.log(error) } } +const getUserRanking =async(userId , recipeId)=>{ +try { + let rank = await findOne({ + where:{ + userId,recipeId + }}) + return rank +} catch (error) { + console.log(error) +} +} const addRanking =async (userId , recipeId, ranking) =>{ try { let user = await User.findByPk(userId) let recipe = await Recipe.findByPk(recipeId) + let rank = await Ranking.findOne({ + where:{ + userId,recipeId + } + }) if (!user || !recipe) { throw new Error('need more data') }else{ + if (rank) { + return await rank.update({ranking:ranking}) + } else { let newRanking = await Ranking.create({ ranking, userId, @@ -71,7 +90,7 @@ const addRanking =async (userId , recipeId, ranking) =>{ await user.addRanking(newRanking) await recipe.addRanking(newRanking) return await Recipe.findByPk(recipeId, { include: Ranking } ) - } + }} } catch (error) { console.log(error) } @@ -107,6 +126,7 @@ module.exports ={ getAllPost, createPost, getRecipePost, + getUserRanking, addRanking, countRanking, updateRanking, diff --git a/api/src/routes/recipe.js b/api/src/routes/recipe.js index f940f91..2817218 100644 --- a/api/src/routes/recipe.js +++ b/api/src/routes/recipe.js @@ -3,7 +3,8 @@ const router = Router(); const Recipe = require("../db"); const { getApiRecipeByID, createRecipe, deleteRecipe, updateRecipe } = require("../controllers/recipecontrollers"); -const auth = require('../middlewares/auth') +const auth = require('../middlewares/auth'); +const { countRanking, getRecipePost } = require("../controllers/usersControllers/PostRanking.controllers"); router.get("/:id", async (req, res) => { let { id } = req.params; @@ -17,7 +18,16 @@ router.get("/:id", async (req, res) => { .json({ error: "error getting that specific recipe" }); } }); - +router.get('/reciperank/:recipeId', async (req,res)=>{ + let {recipeId} = req.params + let rank = await countRanking(recipeId) + res.json(Math.round(rank)) +}) +router.get('/post/:recipeId', async (req,res)=>{ + let {recipeId} = req.params + let post = await getRecipePost(recipeId) + res.json(post) +}) router.post("/", auth,async (req, res) => { const { name, diff --git a/api/src/routes/users/post.js b/api/src/routes/users/post.js index f8180b5..f4236df 100644 --- a/api/src/routes/users/post.js +++ b/api/src/routes/users/post.js @@ -1,5 +1,5 @@ const { Router } = require("express"); -const { getAllPost, createPost,countRanking, getRecipePost, addRanking, updatePost, updateRanking, deletePost } = require("../../controllers/usersControllers/PostRanking.controllers"); +const { getAllPost, createPost,countRanking, getRecipePost, addRanking, updatePost, updateRanking, deletePost, getUserRanking } = require("../../controllers/usersControllers/PostRanking.controllers"); const router = Router() const auth = require('../../middlewares/auth'); @@ -14,16 +14,22 @@ router.post('/:userId',auth, async (req,res)=>{ let post = await createPost(userId, content, recipeId) res.json(post) }) -router.get('/recipe/:recipeId', async (req,res)=>{ +router.get('/ranking/:recipeId', auth, async (req,res)=>{ let {recipeId} = req.params - let post = await getRecipePost(recipeId) - res.json(post) -}) -router.get('/reciperank/:recipeId', auth, async (req,res)=>{ - let {recipeId} = req.params - let rank = await countRanking(recipeId) - res.json(rank) -}) + let {userId} = req.body + let rank = await getUserRanking(userId , recipeId) + res.json(Math.round(rank)) +}) +// router.get('/recipe/:recipeId', async (req,res)=>{ +// let {recipeId} = req.params +// let post = await getRecipePost(recipeId) +// res.json(post) +// }) +// router.get('/reciperank/:recipeId', async (req,res)=>{ +// let {recipeId} = req.params +// let rank = await countRanking(recipeId) +// res.json(rank) +// }) router.patch('/post/:postId', auth, async (req,res)=>{ let {postId} = req.params let {content} = req.body @@ -34,13 +40,13 @@ router.post('/ranking/:recipeId', auth, async (req,res)=>{ let {recipeId} = req.params let {ranking, userId} = req.body let rank = await addRanking(userId , recipeId, ranking) - res.json(rank) -}) -router.patch('/up-ranking', auth, async (req,res)=>{ - let {ranking, rankingId} = req.body - let rank = await updateRanking(ranking, rankingId) - res.json(rank) + res.json(Math.round(rank)) }) +// router.patch('/up-ranking', auth, async (req,res)=>{ +// let {ranking, rankingId} = req.body +// let rank = await updateRanking(ranking, rankingId) +// res.json(rank) +// }) router.delete('/post/:postId', auth, async (req,res)=>{ let {postId} = req.params console.log('postId',postId) diff --git a/client/src/components/recipes/detailrecipe/detailrecipe.js b/client/src/components/recipes/detailrecipe/detailrecipe.js index 979452b..e0ecb98 100644 --- a/client/src/components/recipes/detailrecipe/detailrecipe.js +++ b/client/src/components/recipes/detailrecipe/detailrecipe.js @@ -3,7 +3,7 @@ import React, { useState } from 'react'; import { useDispatch, useSelector } from 'react-redux' import { useEffect, //useState } from 'react'; -import { getRecipeDetail, getRecipePost,} from '../../../redux/actions/recipeactions'; +import { getRecipeDetail, getRecipePost, getTotalRanking,} from '../../../redux/actions/recipeactions'; import { useParams } from 'react-router-dom'; import { NavBar } from '../../utils/nav/nav'; @@ -17,6 +17,7 @@ import Post from "./helper/Post"; import useUser from "../../../hooks/useUser"; import { createPost, deletePost, updatePost } from "../../../redux/actions/postAction"; import NewPost from "./helper/NewPost"; +import RankingPost from './helper/RankingPost'; const RecipeDetail =()=>{ @@ -26,12 +27,17 @@ const RecipeDetail =()=>{ const { isLogged, logout } = useUser(); const recipe = useSelector((state) => state.recipes.detail); const { detailPost } = useSelector((state) => state.recipes); + const rankingTotal = useSelector((state) => state.recipes.ranking) //setRecipeDetail(recipe) useEffect(() => { dispatch(getRecipeDetail(id)); dispatch(getRecipePost(id)); + dispatch(getTotalRanking(id)) },[]) + useEffect(() => { + dispatch(getTotalRanking(id)) + },[rankingTotal]) function handleUpdate(postId, value) { try { dispatch(updatePost(postId, value)) @@ -79,6 +85,13 @@ const RecipeDetail =()=>{
Health Score
  • {recipe.healthScore}
  • +
    +

    Users calification

    + {

    {rankingTotal?rankingTotal:'No ranking'}

    } +
    + {isLogged? :null} +
    +
    diff --git a/client/src/components/recipes/detailrecipe/helper/RankingPost.js b/client/src/components/recipes/detailrecipe/helper/RankingPost.js new file mode 100644 index 0000000..41eacd7 --- /dev/null +++ b/client/src/components/recipes/detailrecipe/helper/RankingPost.js @@ -0,0 +1,43 @@ +import React,{useState} from 'react' +import { useDispatch, useSelector } from 'react-redux'; +import { getUserRanking, postRanking } from '../../../../redux/actions/postAction'; +import { getTotalRanking } from '../../../../redux/actions/recipeactions'; + + +const RankingPost = ({recipeId}) => { +const dispatch = useDispatch() + + const rankingTotal = useSelector((state) => state.recipes.ranking) + + const [ranking,setRanking] =useState(0) + + function handleSubmit(e){ + e.preventDefault(); + } + function handleInputChange(e){ + setRanking(e.target.value) + } + function handleClickPost() { + console.log('recipeId, ranking 2',recipeId, ranking) + dispatch(postRanking(recipeId, ranking)) + dispatch(getUserRanking(recipeId, ranking)) + setTimeout(() => { + dispatch(getTotalRanking(recipeId)) + }, 100) + } + return ( +
    + + +
    + ) +} + +export default RankingPost diff --git a/client/src/components/usersBoart/FavoriteList.js b/client/src/components/usersBoart/FavoriteList.js index 992ed92..2f17277 100644 --- a/client/src/components/usersBoart/FavoriteList.js +++ b/client/src/components/usersBoart/FavoriteList.js @@ -32,7 +32,7 @@ const FavoriteList = ({ list, onUpdate, onDelete, onRender }) => { } function RenderList() { return ( -
    +
    diff --git a/client/src/components/usersBoart/UserPost.js b/client/src/components/usersBoart/UserPost.js new file mode 100644 index 0000000..50b4571 --- /dev/null +++ b/client/src/components/usersBoart/UserPost.js @@ -0,0 +1,12 @@ +import React from 'react' + +const UserPost = ({post}) => { + console.log('post', post); + return ( +
    +

    {post.content}

    +
    + ) +} + +export default UserPost diff --git a/client/src/pages/userBoart.js/userProfile.css b/client/src/pages/userBoart.js/userProfile.css index efd5f0a..86f4ff4 100644 --- a/client/src/pages/userBoart.js/userProfile.css +++ b/client/src/pages/userBoart.js/userProfile.css @@ -1,5 +1,6 @@ -.userprofile { - display: grid; + .userprofile { + display: grid; + grid-auto-flow: column; /* grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr; grid-template-rows: 1fr 1fr 0fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr; gap: 0px 0px; @@ -28,13 +29,31 @@ grid-area: username1; margin-top: 50px; margin-left: 170px; -} +}*/ + } .userimage { - margin-top: 15px; + /* margin-top: 15px; grid-area: userimage; - margin-left: 130px; -} + margin-left: 130px; */ + + border: solid; + width: 100px; + height: 100px; +} +.name-list{ + display: flex; + width: 250px; + justify-content: space-around; +} +.lists-container{ + background-color: none; +} +.buttonListName{ + width: 180px; + border: none; +} +/* .userimage1 { border-radius: 4%; } @@ -44,13 +63,14 @@ margin-top: 300px; margin-left: 430px; } - +*/ .list { - grid-area: list; - margin-left: 80px; + display: grid; + /* grid-area: list; + margin-left: 80px; */ } - +/* .list1 { grid-area: list1; margin-left: 30px; -} \ No newline at end of file +} */ \ No newline at end of file diff --git a/client/src/pages/userBoart.js/userProfile.js b/client/src/pages/userBoart.js/userProfile.js index ac6dac0..eef8fd8 100644 --- a/client/src/pages/userBoart.js/userProfile.js +++ b/client/src/pages/userBoart.js/userProfile.js @@ -11,15 +11,19 @@ import "./userProfile.css" import { useNavigate } from "react-router-dom" +import { getPosts } from '../../redux/actions/postAction'; +import UserPost from '../../components/usersBoart/UserPost'; const UserProfile = () => { const loggedUserSession = window.sessionStorage.getItem("user") const dispatch = useDispatch() const {user} =useSelector((state)=>state.user) + const {userPost} =useSelector((state)=>state.user) const {favList} = useSelector((state) => state.user) const {list} = useSelector((state) => state.user) + const [ image, setImage ] = useState("") const [ loading, setLoading ] = useState(false) @@ -50,6 +54,7 @@ const UserProfile = () => { useEffect(()=>{ if(!loggedUserSession){navigate2("/home")} dispatch(getUserDetail()) + dispatch(getPosts()) },[]) useEffect(()=>{ dispatch(getLists()) @@ -106,9 +111,9 @@ return (
    - +
    - {loading ? (

    Loading picture...

    ) : ()} + {loading ? (

    Loading picture...

    ) : ()}
    @@ -120,12 +125,14 @@ return ( onChange={uploadImage} > +
    - -
    +
    +
    +

    My Lists

    + onCreate={onCreate} />
    {(favList.length>0)? favList.map(f =>(<> )) : null} - -
    +
    +
    {(Object.entries(list).length>0)? @@ -149,9 +156,20 @@ return (

    select your list

    )}
    +
    - -
    +
    +

    Your post

    + {userPost.length>0? + userPost.map(post=>{ + return( + + ) + }) :null} +
    +
    ) diff --git a/client/src/redux/actions/postAction.js b/client/src/redux/actions/postAction.js index f9042ee..ec5b22d 100644 --- a/client/src/redux/actions/postAction.js +++ b/client/src/redux/actions/postAction.js @@ -1,5 +1,5 @@ import axios from 'axios' -import { getUserPost, getUserPosts } from '../userSlice' +import { getUserPost, getUserPosts,getRanking } from '../userSlice' //-------------------- RUTAS -------------------------- @@ -72,7 +72,6 @@ export const updatePost = (postId,content) => async (dispatch)=>{ } export const deletePost = (postId) => async (dispatch)=>{ try { - console.log('postId',postId) let token = JSON.parse(sessionStorage.getItem('token')) await axios.delete(`${url}/user/users/post/post/${postId}`,{ headers:{ @@ -83,4 +82,47 @@ export const deletePost = (postId) => async (dispatch)=>{ } catch (error) { console.log(error) } +} +export const getUserRanking = (recipeId)=> async(dispatch)=>{ + try { + let user = JSON.parse(sessionStorage.getItem('user')) + let token = JSON.parse(sessionStorage.getItem('token')) + let res = await axios.get(`${url}/user/users/post/ranking/${recipeId}`,{userId:user.id},{ + headers:{ + 'Authorization': `Bearer ${token}`, + 'Accept' : 'application/json', + 'Content-Type': 'application/json' + }}) + dispatch(getRanking(res.data)) + } catch (error) { + console.log(error) + } +} +export const postRanking = (recipeId,ranking)=> async(dispatch)=>{ + try { + console.log('recipeId,ranking',recipeId,ranking) + let user = JSON.parse(sessionStorage.getItem('user')) + let token = JSON.parse(sessionStorage.getItem('token')) + await axios.post(`${url}/user/users/post/ranking/${recipeId}`,{ranking,userId:user.id},{ + headers:{ + 'Authorization': `Bearer ${token}`, + 'Accept' : 'application/json', + 'Content-Type': 'application/json' + }}) + } catch (error) { + console.log(error) + } +} +export const updateRanking = (recipeId,ranking)=> async(dispatch)=>{ + try { + let token = JSON.parse(sessionStorage.getItem('token')) + await axios.patch(`${url}/user/users/post/up-ranking`,{ranking,recipeId},{ + headers:{ + 'Authorization': `Bearer ${token}`, + 'Accept' : 'application/json', + 'Content-Type': 'application/json' + }}) + } catch (error) { + console.log(error) + } } \ No newline at end of file diff --git a/client/src/redux/actions/recipeactions.js b/client/src/redux/actions/recipeactions.js index 5321ea5..13e97c1 100644 --- a/client/src/redux/actions/recipeactions.js +++ b/client/src/redux/actions/recipeactions.js @@ -1,6 +1,6 @@ import axios from 'axios' import {getAllRecipes, orderByRating, getRecipesByName, - getRecipeById,createRecipe, filterByDiet, getDiets_Recipe, getAllPost + getRecipeById,createRecipe, filterByDiet, getDiets_Recipe, getAllPost, getRanking } from '../recipeSlice' //-------------------- RUTAS -------------------------- @@ -9,7 +9,6 @@ import {getAllRecipes, orderByRating, getRecipesByName, import dotenv from 'dotenv' dotenv.config() const url = process.env.REACT_APP_HOST || 'http://localhost:5001' -console.log('process.env.REACT_APP_HOST',process.env.REACT_APP_HOST) //-------------------- ACTIONS ------------------------ export const getRecipes = ()=> async (dispatch) => { @@ -65,12 +64,20 @@ export const filterDiet =(payload)=>async (dispatch)=>{ export const getRecipePost = (recipeId) => async (dispatch)=>{ try { - let res = await axios.get(`${url}/user/users/post/recipe/${recipeId}`) + let res = await axios.get(`${url}/recipe/post/${recipeId}`) dispatch(getAllPost(res.data)) } catch (error) { console.log(error) } } +export const getTotalRanking = (recipeId) => async (dispatch)=>{ + try { + let res = await axios.get(`${url}/recipe/reciperank/${recipeId}`) + dispatch(getRanking(res.data)) + } catch (error) { + console.log(error) + } +} // export const getByName = async (dispatch) => { // try{ // let res = await axios.get(`http://${url}/recipes?${name}`) diff --git a/client/src/redux/userSlice.js b/client/src/redux/userSlice.js index 32eadab..1d249df 100644 --- a/client/src/redux/userSlice.js +++ b/client/src/redux/userSlice.js @@ -7,7 +7,8 @@ export const userSlice = createSlice({ favList: [], list: {}, userPost: [], - post:{} + post:{}, + ranking:0 }, reducers: { getUser: (state, action) => { @@ -41,6 +42,9 @@ export const userSlice = createSlice({ getUserPost:(state, action) => { state.post = action.payload; }, + getRanking:(state, action) => { + state.ranking = action.payload; + }, // getUserStatus: (state, action)=>{ // state.logged = action.payload @@ -68,6 +72,7 @@ export const { getUserStatus, createUser, deleteUser, + getRanking, } = userSlice.actions; export default userSlice.reducer; From 1ed5ae1aa799f7bcbde9b00f9e873620f31e1719 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Duv=C3=A1n=20Merch=C3=A1n?= Date: Sun, 16 Oct 2022 19:40:22 -0500 Subject: [PATCH 15/38] profile --- .../src/components/usersBoart/FavoriteList.js | 4 +-- client/src/pages/userBoart.js/userProfile.css | 29 ++++++++++++++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/client/src/components/usersBoart/FavoriteList.js b/client/src/components/usersBoart/FavoriteList.js index 2f17277..c67e1eb 100644 --- a/client/src/components/usersBoart/FavoriteList.js +++ b/client/src/components/usersBoart/FavoriteList.js @@ -37,7 +37,7 @@ const FavoriteList = ({ list, onUpdate, onDelete, onRender }) => { {list.name}
    + Go to Profile!
    +
    ); } diff --git a/client/src/pages/userBoart.js/userProfile.css b/client/src/pages/userBoart.js/userProfile.css index 7b1d0a3..c76f244 100644 --- a/client/src/pages/userBoart.js/userProfile.css +++ b/client/src/pages/userBoart.js/userProfile.css @@ -32,16 +32,51 @@ margin-left: 170px; }*/ } -.userimage { - /* margin-top: 15px; - grid-area: userimage; - margin-left: 130px; */ - - border: solid; - width: 100px; - height: 100px; + .profileprincipal{ + display: flex; + justify-content: center; + align-items: center; +} + +.profilesecond{ + display:flex; + justify-content: center; +} + +.profiledetalles{ + display: flex; + justify-content: center; +} + +.profiledetalles h3 { + font-size: 16px; + padding: 5px; } + +.username1{ + display: flex; + justify-content: center; +} + + .userimage1 { + min-width: 200px; + max-width: 200px; + min-height: 200px; + max-height: 200px; + width: 200px; + height: 200px; + border-radius: 100%; + border: solid 5px black; +} + +.userimage h3{ + min-width: 200px; + max-width: 200px; + min-height: 200px; + max-height: 200px; +} + .name-list{ display: flex; width: 250px; @@ -63,6 +98,16 @@ text-shadow:inset 0px 1px 0px #ffffff; background:linear-gradient(#ededed, #dfdfdf); } + +.upload1 input{ + background-color: blueviolet; + display: none; +} + +.modifyibm{ + display: flex; + justify-content: center; +} /* .userimage1 { min-width: 200px; diff --git a/client/src/pages/userBoart.js/userProfile.js b/client/src/pages/userBoart.js/userProfile.js index d240023..5e20830 100644 --- a/client/src/pages/userBoart.js/userProfile.js +++ b/client/src/pages/userBoart.js/userProfile.js @@ -150,27 +150,40 @@ return (
    -
    - -
    +
    -
    -
    - {loading ? (

    Loading picture...

    ) : ()} -
    + +
    + { !profile.length?
    +

    Peso: 0 Kg

    +

    Height: 0 Cm

    +

    IBM: 0

    -
    -
    Upload your profile picture
    - - -
    +
    : + profile.map((el) => { + + return ( +
    +

    Peso: {el.peso} Kg

    +

    Height: {el.altura} Cm

    +

    IBM: {el.imc}

    + + +
    + ) + })} +
    + + + +
    + + +
    From b92ab6800df304eaf7a8977e2c3acc1688727927 Mon Sep 17 00:00:00 2001 From: facoogle Date: Sun, 16 Oct 2022 23:26:26 -0300 Subject: [PATCH 17/38] add info user --- client/src/components/utils/imcalculator/imcalculator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/utils/imcalculator/imcalculator.js b/client/src/components/utils/imcalculator/imcalculator.js index 15f5f55..7c7183d 100644 --- a/client/src/components/utils/imcalculator/imcalculator.js +++ b/client/src/components/utils/imcalculator/imcalculator.js @@ -105,7 +105,7 @@ export const CalculatorIMC= ()=>{ onChange={ (e) => setAltura(e.target.value) } /> - From 14e096a03a27e4e6c07140fa1503f14676aea39e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Duv=C3=A1n=20Merch=C3=A1n?= Date: Sun, 16 Oct 2022 22:37:23 -0500 Subject: [PATCH 18/38] css --- .../PostRanking.controllers.js | 23 +- .../components/recipes/cards/card/card.css | 12 +- client/src/components/recipes/cards/cards.css | 17 +- .../recipes/detailrecipe/detail.css | 59 +++-- .../recipes/detailrecipe/detailrecipe.js | 217 ++++++++++-------- .../recipes/detailrecipe/helper/NewPost.js | 2 +- .../detailrecipe/helper/RankingPost.js | 2 +- client/src/components/usersBoart/Info.js | 2 +- client/src/components/usersBoart/UserPost.js | 13 +- .../utils/SelectFavList/SelectFavList.css | 6 + .../utils/SelectFavList/SelectFavList.js | 3 +- client/src/index.css | 20 ++ client/src/pages/userBoart.js/userProfile.css | 19 +- client/src/pages/userBoart.js/userProfile.js | 12 +- 14 files changed, 263 insertions(+), 144 deletions(-) diff --git a/api/src/controllers/usersControllers/PostRanking.controllers.js b/api/src/controllers/usersControllers/PostRanking.controllers.js index f9d23d6..7376461 100644 --- a/api/src/controllers/usersControllers/PostRanking.controllers.js +++ b/api/src/controllers/usersControllers/PostRanking.controllers.js @@ -2,7 +2,28 @@ const { User, Post, Recipe, Ranking } = require("../../db"); const getAllPost = async (userId) =>{ try { - return await User.findByPk(userId, { include: Post } ) + let user = await User.findByPk(userId, { include: Post } ) + let posts = user.posts + let post =[] + // console.log('user',user); + // console.log('posts',posts); + //return await User.findByPk(userId, { include: Post } ) + if (posts) { + await Promise.allSettled( + await posts.map(async p=>{ + let recipe = await Recipe.findByPk(p.recipeId) + post.push({ + userId:p.dataValues.id, + username: user.dataValues.username, + content:p.dataValues.content, + recipeId: recipe.dataValues.id, + recipeImg:recipe.dataValues.image, + recipeName:recipe.dataValues.name, + })})) + console.log('post',post); + return post + } + } catch (error) { console.log(error) }} diff --git a/client/src/components/recipes/cards/card/card.css b/client/src/components/recipes/cards/card/card.css index 9cdaa26..dcfdf02 100644 --- a/client/src/components/recipes/cards/card/card.css +++ b/client/src/components/recipes/cards/card/card.css @@ -1,18 +1,18 @@ -.card-title { - text-decoration: none; - color: #2E2E2E;; -} +@import url('https://fonts.googleapis.com/css2?family=Cabin:ital@1&family=Fraunces:opsz@9..144&family=Merriweather:ital,wght@0,300;1,300&family=Oswald:wght@300;400;700&family=Roboto+Serif:ital,opsz,wght@0,8..144,400;0,8..144,700;1,8..144,300&display=swap'); .card-text { text-decoration: none; color: #2E2E2E;; } - +h5{ + font-family: 'Merriweather:ital', serif; + color: rgb(5, 97, 43); +} .card-title{ width: 230px; - font-size: 15px; + font-size: 20px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; diff --git a/client/src/components/recipes/cards/cards.css b/client/src/components/recipes/cards/cards.css index dddb40c..fa92c2c 100644 --- a/client/src/components/recipes/cards/cards.css +++ b/client/src/components/recipes/cards/cards.css @@ -1,3 +1,14 @@ +@import url('https://fonts.googleapis.com/css?family=Cutive'); +@import url('https://fonts.googleapis.com/css2?family=Cabin:ital@1&family=Fraunces:opsz@9..144&family=Merriweather:ital,wght@0,300;1,300&family=Oswald:wght@300;400;700&family=Roboto+Serif:ital,opsz,wght@0,8..144,400;0,8..144,700;1,8..144,300&display=swap'); + +h1{ + font-family: Cutive, serif; + text-align: center; + font-size: 35px; + color: rgb(6, 249, 75); + text-shadow: rgba(0, 0, 0, 0.96) 2px 2px 2px; + padding: 15px; +} .CardsRecipes{ margin: auto; max-width: 70%; @@ -10,6 +21,7 @@ align-items:baseline; margin: auto; min-height: 700px; + } .OrdenRankingRecipes{ @@ -24,7 +36,7 @@ .options-recipes{ display: flex; justify-content: space-between; - + padding: 5px; } #content-card{ @@ -35,4 +47,7 @@ .Links{ text-decoration: none; +} +.pagination{ + padding: 10px; } \ No newline at end of file diff --git a/client/src/components/recipes/detailrecipe/detail.css b/client/src/components/recipes/detailrecipe/detail.css index d9ba833..6e6b24c 100644 --- a/client/src/components/recipes/detailrecipe/detail.css +++ b/client/src/components/recipes/detailrecipe/detail.css @@ -1,7 +1,8 @@ .detail1 { - display: grid; - grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr; + display: grid; + padding: 10px; + /* grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr; grid-template-rows: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr; gap: 0px 0px; grid-template-areas: @@ -19,42 +20,48 @@ margin: 0 auto; padding: 1em; background: #f9f9f9; - border: 1px solid #c1c1c1; + border: 1px solid #c1c1c1; */ } - - .detail2 { - grid-area: name; + .detailcontent{ + display: grid; + grid-template-columns: 40% 55%; + } + .detailrigth{ + padding: 10px; } + /*.detail2 { + grid-area: name; + }*/ .font1 { - font-size: 60px; + font-size: 50px; } - +/* .detail3 { - grid-area: data; - margin-left: 80px; + grid-area: data; + margin-left: 80px; } .detail4 { - grid-area: summary; - padding: 1em; + grid-area: summary; + padding: 1em; } .detail5 { - grid-area: image; - margin-left: 250px; + /* grid-area: image; */ + /* margin-left: 250px; */ /* grid-area: 2 / 3 / 6 / 6; margin-bottom: 45px; margin-top: 80px; - margin-left: 250px; */ + margin-left: 250px; } .detail6{ - grid-area: favourite; - margin-left: 80px; - } + grid-area: favourite; + margin-left: 80px; + } */ .fontimg { border-radius: 4px; @@ -97,3 +104,19 @@ transform: translateY(-50%) translateX(-18px); transition: transform .25s cubic-bezier(0,0,.5,2); } +.buttonVote, .buttonCreatePost{ + color:#777777; + border-color:#dcdcdc; + font-weight:bold; + border-top-left-radius:6px; + border-top-right-radius:6px; + border-bottom-left-radius:6px; + border-bottom-right-radius:6px; + box-shadow:inset 0px 1px 0px 0px #ffffff; + text-shadow:inset 0px 1px 0px #ffffff; + background:linear-gradient(#ededed, #dfdfdf); +} + +.buttonVote, .buttonCreatePost:hover { + background: linear-gradient(#dfdfdf, #ededed); + } \ No newline at end of file diff --git a/client/src/components/recipes/detailrecipe/detailrecipe.js b/client/src/components/recipes/detailrecipe/detailrecipe.js index e0ecb98..6ab851c 100644 --- a/client/src/components/recipes/detailrecipe/detailrecipe.js +++ b/client/src/components/recipes/detailrecipe/detailrecipe.js @@ -1,131 +1,150 @@ -import React, { useState } from 'react'; +import React, { useState } from "react"; //import {spinner} from '../../utils/spinner/spinner.js'; -import { useDispatch, useSelector } from 'react-redux' -import { useEffect, //useState -} from 'react'; -import { getRecipeDetail, getRecipePost, getTotalRanking,} from '../../../redux/actions/recipeactions'; -import { useParams } from 'react-router-dom'; -import { NavBar } from '../../utils/nav/nav'; +import { useDispatch, useSelector } from "react-redux"; +import { + useEffect, //useState +} from "react"; +import { + getRecipeDetail, + getRecipePost, + getTotalRanking, +} from "../../../redux/actions/recipeactions"; +import { useParams } from "react-router-dom"; +import { NavBar } from "../../utils/nav/nav"; //import {check} from "./check.png" -import style from './detail.css' -import SelectFavList from '../../utils/SelectFavList/SelectFavList'; +import style from "./detail.css"; +import SelectFavList from "../../utils/SelectFavList/SelectFavList"; import { useModal } from "../../../hooks/useModal"; import Modal from "../../utils/Modal/Modal"; import Post from "./helper/Post"; import useUser from "../../../hooks/useUser"; -import { createPost, deletePost, updatePost } from "../../../redux/actions/postAction"; +import { + createPost, + deletePost, + updatePost, +} from "../../../redux/actions/postAction"; import NewPost from "./helper/NewPost"; -import RankingPost from './helper/RankingPost'; +import RankingPost from "./helper/RankingPost"; -const RecipeDetail =()=>{ - - const dispatch = useDispatch(); - const { id } = useParams(); - const [isOpen, openModal, closeModal] = useModal(); - const { isLogged, logout } = useUser(); - const recipe = useSelector((state) => state.recipes.detail); - const { detailPost } = useSelector((state) => state.recipes); - const rankingTotal = useSelector((state) => state.recipes.ranking) - //setRecipeDetail(recipe) +const RecipeDetail = () => { + const dispatch = useDispatch(); + const { id } = useParams(); + const [isOpen, openModal, closeModal] = useModal(); + const { isLogged, logout } = useUser(); + const recipe = useSelector((state) => state.recipes.detail); + const { detailPost } = useSelector((state) => state.recipes); + const rankingTotal = useSelector((state) => state.recipes.ranking); + //setRecipeDetail(recipe) - useEffect(() => { - dispatch(getRecipeDetail(id)); + useEffect(() => { + dispatch(getRecipeDetail(id)); + dispatch(getRecipePost(id)); + dispatch(getTotalRanking(id)); + }, []); + useEffect(() => { + dispatch(getTotalRanking(id)); + }, [rankingTotal]); + function handleUpdate(postId, value) { + try { + dispatch(updatePost(postId, value)); + setTimeout(() => { dispatch(getRecipePost(id)); - dispatch(getTotalRanking(id)) - },[]) - useEffect(() => { - dispatch(getTotalRanking(id)) - },[rankingTotal]) - function handleUpdate(postId, value) { - try { - dispatch(updatePost(postId, value)) - setTimeout(() => { - dispatch(getRecipePost(id)) - }, 100); - } catch (error) { - console.log(error); - } - } - function handleDelete(postId) { - try { - alert("Do you wanna delete this list?"); - dispatch(deletePost(postId)) - setTimeout(() => { - dispatch(getRecipePost(id)) - }, 100); - } catch (error) { - console.log(error); - } + }, 100); + } catch (error) { + console.log(error); } - function handleCreate(content) { - dispatch(createPost(content, id)); + } + function handleDelete(postId) { + try { + alert("Do you wanna delete this list?"); + dispatch(deletePost(postId)); setTimeout(() => { dispatch(getRecipePost(id)); }, 100); + } catch (error) { + console.log(error); } - - return( -
    - + } + function handleCreate(content) { + dispatch(createPost(content, id)); + setTimeout(() => { + dispatch(getRecipePost(id)); + }, 100); + } -
    + return ( +
    + - -
    +

    {recipe.name}

    -
    +
    +
    +
    +

    Diet/s

    + {recipe.createdInDB ? ( +

    {recipe.diets[0].name}

    + ) : ( +

    {recipe.diets}

    + )} -
    - -

    Diet/s

    - {recipe.createdInDB?(

    {recipe.diets[0].name}

    ):

    {recipe.diets}

    } - -
    Health Score
    -
  • {recipe.healthScore}
  • -
    -
    -

    Users calification

    - {

    {rankingTotal?rankingTotal:'No ranking'}

    } -
    - {isLogged? :null} +
    Health Score
    +
  • {recipe.healthScore}
  • +
    +
    + + + + +
    +
    +

    Users calification

    + {
    {rankingTotal ? rankingTotal : "No ranking"}
    } +
    + {isLogged ? : null} +
    +
    +
    +
    + recipe
    - -
    - - - - -
    -
    -
    Summary
    - {recipe.createdInDB?(

    {recipe.summary}

    ):(

    )} -

    - -
    - recipe +
    Summary
    + {recipe.createdInDB ? ( +

    {recipe.summary}

    + ) : ( +

    + )}

    coments

    {isLogged ? : null} {detailPost - ? detailPost.map((post) =>{ - return( ) - }):null - } + ? detailPost.map((post) => { + return ( + + ); + }) + : null}
    +
    -
    - ) -} - + ); +}; -export default RecipeDetail; \ No newline at end of file +export default RecipeDetail; diff --git a/client/src/components/recipes/detailrecipe/helper/NewPost.js b/client/src/components/recipes/detailrecipe/helper/NewPost.js index 461aa9a..ba69daa 100644 --- a/client/src/components/recipes/detailrecipe/helper/NewPost.js +++ b/client/src/components/recipes/detailrecipe/helper/NewPost.js @@ -22,7 +22,7 @@ const NewPost = ({ onCreate }) => { onChange={handleChange} value={newValue} /> - diff --git a/client/src/components/recipes/detailrecipe/helper/RankingPost.js b/client/src/components/recipes/detailrecipe/helper/RankingPost.js index 41eacd7..e59f11d 100644 --- a/client/src/components/recipes/detailrecipe/helper/RankingPost.js +++ b/client/src/components/recipes/detailrecipe/helper/RankingPost.js @@ -35,7 +35,7 @@ const dispatch = useDispatch() value={ranking} onChange={handleInputChange} /> - + ) } diff --git a/client/src/components/usersBoart/Info.js b/client/src/components/usersBoart/Info.js index 512a82d..728c0b0 100644 --- a/client/src/components/usersBoart/Info.js +++ b/client/src/components/usersBoart/Info.js @@ -4,7 +4,7 @@ const Info = (user) => { user = user.user return (
    -

    UserName : {user.username}

    +

    {user.username}

    ) } diff --git a/client/src/components/usersBoart/UserPost.js b/client/src/components/usersBoart/UserPost.js index 50b4571..0e89293 100644 --- a/client/src/components/usersBoart/UserPost.js +++ b/client/src/components/usersBoart/UserPost.js @@ -1,10 +1,17 @@ import React from 'react' const UserPost = ({post}) => { - console.log('post', post); return ( -
    -

    {post.content}

    +
    + +
    +
    {post.username}
    + {post.content} +
    ) } diff --git a/client/src/components/utils/SelectFavList/SelectFavList.css b/client/src/components/utils/SelectFavList/SelectFavList.css index 6f7eacb..3cd4819 100644 --- a/client/src/components/utils/SelectFavList/SelectFavList.css +++ b/client/src/components/utils/SelectFavList/SelectFavList.css @@ -3,6 +3,12 @@ grid-template-rows: 20% 80%; align-items: center; } +h3{ + padding: 15px; +} +.favList{ + overflow-y: scroll; +} .checked-item { background-color:rgb(84, 185, 89); padding:0.1em 0.2em; diff --git a/client/src/components/utils/SelectFavList/SelectFavList.js b/client/src/components/utils/SelectFavList/SelectFavList.js index 1b5ecdc..dd7191f 100644 --- a/client/src/components/utils/SelectFavList/SelectFavList.js +++ b/client/src/components/utils/SelectFavList/SelectFavList.js @@ -26,6 +26,7 @@ const SelectFavList = ({recipeId}) => { return (

    My favorite list

    +
    {favList? favList.map((f)=>{ return( @@ -34,7 +35,7 @@ const SelectFavList = ({recipeId}) => { {f.name}
    )}):null - } + }
    ) } diff --git a/client/src/index.css b/client/src/index.css index ec2585e..1074bc7 100644 --- a/client/src/index.css +++ b/client/src/index.css @@ -1,3 +1,5 @@ +@import url('https://fonts.googleapis.com/css2?family=Cabin:ital@1&family=Fraunces:opsz@9..144&family=Merriweather:ital,wght@0,300;1,300&family=Oswald:wght@300;400;700&family=Roboto+Serif:ital,opsz,wght@0,8..144,400;0,8..144,700;1,8..144,300&display=swap'); + body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', @@ -11,3 +13,21 @@ code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } +h1{ + color: rgb(64, 219, 64); +} +h2{ + color: rgb(82, 167, 82); + font-family: 'Merriweather', serif; +} +h3{ + color: rgb(38, 148, 38); + font-family: 'Cabin:ital', serif; +} +h4{ + color: rgb(59, 141, 59); + font-family: 'Cabin:ital', serif; +} +h5{ + word-wrap: break-word; +} \ No newline at end of file diff --git a/client/src/pages/userBoart.js/userProfile.css b/client/src/pages/userBoart.js/userProfile.css index 2499593..23ceb06 100644 --- a/client/src/pages/userBoart.js/userProfile.css +++ b/client/src/pages/userBoart.js/userProfile.css @@ -1,5 +1,6 @@ .userprofile { display: grid; + padding: 15px; grid-auto-flow: column; /* grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr; grid-template-rows: 1fr 1fr 0fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr; @@ -23,14 +24,14 @@ margin: 0 auto; padding: 1em; background: #f9f9f9; - border: 1px solid #c1c1c1; + border: 1px solid #c1c1c1;*/ } .username1 { - grid-area: username1; - margin-top: 50px; - margin-left: 170px; -}*/ - } + justify-content: center; + align-items: center; + display: flex; +} + .userimage { /* margin-top: 15px; grid-area: userimage; @@ -47,7 +48,6 @@ justify-content: space-around; } .list-container{ - background-color: beige; display: grid; grid-template-columns: 300px 450px; } @@ -95,6 +95,11 @@ .buttonListName,.ButtonNewLIst, .buttonEdit, .buttonDelete:hover { background: linear-gradient(#dfdfdf, #ededed); } +.post{ + display: grid; + justify-content: center; + padding-bottom: 15px; +} /* .list1 { diff --git a/client/src/pages/userBoart.js/userProfile.js b/client/src/pages/userBoart.js/userProfile.js index eef8fd8..da2f432 100644 --- a/client/src/pages/userBoart.js/userProfile.js +++ b/client/src/pages/userBoart.js/userProfile.js @@ -23,7 +23,6 @@ const UserProfile = () => { const {favList} = useSelector((state) => state.user) const {list} = useSelector((state) => state.user) - const [ image, setImage ] = useState("") const [ loading, setLoading ] = useState(false) @@ -107,10 +106,6 @@ return (
    -
    - -
    {loading ? (

    Loading picture...

    ) : ()} @@ -126,6 +121,11 @@ return ( >
    +
    + +
    +
    @@ -160,6 +160,7 @@ return (

    Your post

    +
    {userPost.length>0? userPost.map(post=>{ return( @@ -169,6 +170,7 @@ return ( ) }) :null}
    +
    From dd7e33e3ca59679fdac2f6437f959299960aacae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Duv=C3=A1n=20Merch=C3=A1n?= Date: Sun, 16 Oct 2022 22:45:58 -0500 Subject: [PATCH 19/38] css --- client/src/pages/userBoart.js/userProfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/pages/userBoart.js/userProfile.js b/client/src/pages/userBoart.js/userProfile.js index a34eee5..8ac85d3 100644 --- a/client/src/pages/userBoart.js/userProfile.js +++ b/client/src/pages/userBoart.js/userProfile.js @@ -22,7 +22,7 @@ const UserProfile = () => { const {userPost} =useSelector((state)=>state.user) const {favList} = useSelector((state) => state.user) const {list} = useSelector((state) => state.user) - + const {profile} = useSelector((state) => state.user) const [ image, setImage ] = useState("") const [ loading, setLoading ] = useState(false) From 54968307bdc3d013f55db5febb85805ddf3d09bc Mon Sep 17 00:00:00 2001 From: Leandro Espinasse <99082701+LEANDROESPINASSE@users.noreply.github.com> Date: Mon, 17 Oct 2022 05:42:45 -0300 Subject: [PATCH 20/38] finalcss --- client/src/components/recipes/cards/cards.css | 7 +- client/src/components/recipes/cards/cards.jsx | 6 +- .../recipes/detailrecipe/detail.css | 108 ++++++++++-------- .../recipes/detailrecipe/detailrecipe.js | 50 +++++--- 4 files changed, 97 insertions(+), 74 deletions(-) diff --git a/client/src/components/recipes/cards/cards.css b/client/src/components/recipes/cards/cards.css index fa92c2c..4f4ace2 100644 --- a/client/src/components/recipes/cards/cards.css +++ b/client/src/components/recipes/cards/cards.css @@ -3,9 +3,10 @@ h1{ font-family: Cutive, serif; + margin-top: 40px; text-align: center; - font-size: 35px; - color: rgb(6, 249, 75); + font-size: 60px; + color: rgb(125, 230, 155); text-shadow: rgba(0, 0, 0, 0.96) 2px 2px 2px; padding: 15px; } @@ -21,7 +22,6 @@ h1{ align-items:baseline; margin: auto; min-height: 700px; - } .OrdenRankingRecipes{ @@ -34,6 +34,7 @@ h1{ } .options-recipes{ + margin-bottom: 30px; display: flex; justify-content: space-between; padding: 5px; diff --git a/client/src/components/recipes/cards/cards.jsx b/client/src/components/recipes/cards/cards.jsx index 7146209..15c802f 100644 --- a/client/src/components/recipes/cards/cards.jsx +++ b/client/src/components/recipes/cards/cards.jsx @@ -75,10 +75,10 @@ const paginado = (pageNumber) => {
    -
    +
    */} -
    - -
    +
    + + +
    -
    + +
    + +
    + +
    { !profile.length?

    Peso: 0 Kg

    Height: 0 Cm

    @@ -167,9 +169,7 @@ return (

    Peso: {el.peso} Kg

    Height: {el.altura} Cm

    -

    IBM: {el.imc}

    - - +

    IBM: {el.imc}

    ) })} @@ -179,17 +179,12 @@ return ( Modify IBM
    -
    - - - -
    -
    -
    +
    -

    My Lists

    -
    +

    My Lists

    + +
    {(favList.length>0)? favList.map(f =>(<> - -
    +
    {(Object.entries(list).length>0)? select your list )}
    -
    -
    +

    Your post

    -
    +
    {userPost.length>0? userPost.map(post=>{ return( @@ -227,11 +220,13 @@ return ( ) }) :null}
    -
    +
    - +
    ) } export default UserProfile + + From 3a7576be8e603a077e59ddf68d6886ff41430554 Mon Sep 17 00:00:00 2001 From: Pedro Caloiero Date: Mon, 17 Oct 2022 16:48:35 -0300 Subject: [PATCH 24/38] asdas --- .../usersControllers/userfree.controller.js | 1 + api/src/models/Payment.js | 1 + .../components/utils/Stripe/checkoutForm.js | 1 + client/src/components/utils/Stripe/payment.js | 20 ------------------- 4 files changed, 3 insertions(+), 20 deletions(-) diff --git a/api/src/controllers/usersControllers/userfree.controller.js b/api/src/controllers/usersControllers/userfree.controller.js index b24abd4..87f0d20 100644 --- a/api/src/controllers/usersControllers/userfree.controller.js +++ b/api/src/controllers/usersControllers/userfree.controller.js @@ -63,6 +63,7 @@ const changeToPremium = async (userEmail, userName, paymentMethod) =>{ paymentNotification(userEmail,recibo) + return { message: 'Subscription successfully initiated', clientSecret: subscription.latest_invoice.payment_intent.client_secret, diff --git a/api/src/models/Payment.js b/api/src/models/Payment.js index 4d7bec4..e0f5ea8 100644 --- a/api/src/models/Payment.js +++ b/api/src/models/Payment.js @@ -1,6 +1,7 @@ const { DataTypes } = require('sequelize'); module.exports = (sequelize) => { + sequelize.define('payment', { paymenthID:{ type: DataTypes.STRING, diff --git a/client/src/components/utils/Stripe/checkoutForm.js b/client/src/components/utils/Stripe/checkoutForm.js index bb21ca6..b5423bf 100644 --- a/client/src/components/utils/Stripe/checkoutForm.js +++ b/client/src/components/utils/Stripe/checkoutForm.js @@ -15,6 +15,7 @@ const { REACT_APP_HOST } = export function PaymentForm() { + const navigate2 = useNavigate() useEffect(() => { diff --git a/client/src/components/utils/Stripe/payment.js b/client/src/components/utils/Stripe/payment.js index a35804b..4e3ddd7 100644 --- a/client/src/components/utils/Stripe/payment.js +++ b/client/src/components/utils/Stripe/payment.js @@ -6,26 +6,6 @@ import { PaymentForm } from './checkoutForm' const stripePromise = loadStripe("pk_test_51LpumKJocvWwgusfuIDgKMDWBBTXIYMiqNNp1I0a6FOuXMVVnNFrqUOuUmJzvONbAVs0Fc7NAGCCNGm4AumQptBV00bOAnI6rN") -// const appearance = { -// theme: 'night', -// labels: 'floating', - -// variables: { -// colorPrimary: '#0570de', -// colorBackground: '#ffffff', -// colorText: '#30313d', -// colorDanger: '#df1b41', -// fontFamily: 'Ideal Sans, system-ui, sans-serif', -// spacingUnit: '2px', -// borderRadius: '4px', -// // See all possible variables below -// } -// }; - -// const options = { -// appearance, -// clientSecret -// } export function Payment () { return( From 10ce22310ac76a0b41c03403beb31a7902eea627 Mon Sep 17 00:00:00 2001 From: Juan Martinez Date: Mon, 17 Oct 2022 17:15:33 -0300 Subject: [PATCH 25/38] falta terminar de revisar --- .../RecipesTable/EnhancedRecipesTableHead.js | 58 +++++++ .../EnhancedRecipesTableToolbar.js | 80 +++++++++ .../admin/RecipesTable/RecipeTable.js | 50 +++--- .../components/admin/RecipesTable/Recipes.js | 116 ------------- .../admin/RecipesTable/headCellsRecipe.js | 28 +-- .../admin/TableHelpers/TableHelpers.js | 12 +- .../EnhancedUsersTableHead.js} | 18 +- .../EnhancedUsersTableToolbar.js} | 9 +- .../src/components/admin/UsersTable/User.js | 160 ----------------- .../components/admin/UsersTable/UserTable.js | 42 +---- client/src/components/admin/admin_NavBar.js | 162 ------------------ client/src/redux/actions/adminAction.js | 16 ++ 12 files changed, 213 insertions(+), 538 deletions(-) create mode 100644 client/src/components/admin/RecipesTable/EnhancedRecipesTableHead.js create mode 100644 client/src/components/admin/RecipesTable/EnhancedRecipesTableToolbar.js delete mode 100644 client/src/components/admin/RecipesTable/Recipes.js rename client/src/components/admin/{TableHelpers/EnhancedTableHead.js => UsersTable/EnhancedUsersTableHead.js} (76%) rename client/src/components/admin/{TableHelpers/EnhancedTableToolbar.js => UsersTable/EnhancedUsersTableToolbar.js} (87%) delete mode 100644 client/src/components/admin/UsersTable/User.js delete mode 100644 client/src/components/admin/admin_NavBar.js diff --git a/client/src/components/admin/RecipesTable/EnhancedRecipesTableHead.js b/client/src/components/admin/RecipesTable/EnhancedRecipesTableHead.js new file mode 100644 index 0000000..b7f898a --- /dev/null +++ b/client/src/components/admin/RecipesTable/EnhancedRecipesTableHead.js @@ -0,0 +1,58 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import Box from '@mui/material/Box'; +import TableCell from '@mui/material/TableCell'; +import TableHead from '@mui/material/TableHead'; +import TableRow from '@mui/material/TableRow'; +import TableSortLabel from '@mui/material/TableSortLabel'; +import { visuallyHidden } from '@mui/utils'; +import { headCellsRecipe } from './headCellsRecipe'; + +function EnhancedRecipesTableHead(props) { + const { onSelectAllClick, order, orderBy, numSelected, rowCount, onRequestSort } = + props; + const createSortHandler = (property) => (event) => { + onRequestSort(event, property); + }; + + return ( + + + + banned + + {headCellsRecipe.map((headCell) => ( + + + {headCell.label} + {orderBy === headCell.id ? ( + + {order === 'desc' ? 'sorted descending' : 'sorted ascending'} + + ) : null} + + + ))} + + + ); +} +EnhancedRecipesTableHead.propTypes = { + numSelected: PropTypes.number.isRequired, + onRequestSort: PropTypes.func.isRequired, + onSelectAllClick: PropTypes.func.isRequired, + order: PropTypes.oneOf(['asc', 'desc']).isRequired, + orderBy: PropTypes.string.isRequired, + rowCount: PropTypes.number.isRequired, + }; + +export default EnhancedRecipesTableHead diff --git a/client/src/components/admin/RecipesTable/EnhancedRecipesTableToolbar.js b/client/src/components/admin/RecipesTable/EnhancedRecipesTableToolbar.js new file mode 100644 index 0000000..4c87484 --- /dev/null +++ b/client/src/components/admin/RecipesTable/EnhancedRecipesTableToolbar.js @@ -0,0 +1,80 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import { alpha } from '@mui/material/styles'; +import Box from '@mui/material/Box'; +import Table from '@mui/material/Table'; +import TableBody from '@mui/material/TableBody'; +import TableCell from '@mui/material/TableCell'; +import TableContainer from '@mui/material/TableContainer'; +import TableHead from '@mui/material/TableHead'; +import TablePagination from '@mui/material/TablePagination'; +import TableRow from '@mui/material/TableRow'; +import TableSortLabel from '@mui/material/TableSortLabel'; +import Toolbar from '@mui/material/Toolbar'; +import Typography from '@mui/material/Typography'; +import Paper from '@mui/material/Paper'; +import Checkbox from '@mui/material/Checkbox'; +import IconButton from '@mui/material/IconButton'; +import Tooltip from '@mui/material/Tooltip'; +import FormControlLabel from '@mui/material/FormControlLabel'; +import Switch from '@mui/material/Switch'; +import DeleteIcon from '@mui/icons-material/Delete'; +import FilterListIcon from '@mui/icons-material/FilterList'; +import { visuallyHidden } from '@mui/utils'; +import { headCellsRecipe } from './headCellsRecipe'; + +function EnhancedRecipesTableToolbar(props) { + const { numSelected } = props; + + return ( + 0 && { + bgcolor: (theme) => + alpha(theme.palette.primary.main, theme.palette.action.activatedOpacity), + }), + }} + > + {numSelected > 0 ? ( + + {numSelected} selected + + ) : ( + + Recipes Admin Panel + + )} + + {numSelected > 0 ? ( + + + + + + ) : ( + + + + + + )} + + ); +} +EnhancedRecipesTableToolbar.propTypes = { + numSelected: PropTypes.number.isRequired, + }; + +export default EnhancedRecipesTableToolbar diff --git a/client/src/components/admin/RecipesTable/RecipeTable.js b/client/src/components/admin/RecipesTable/RecipeTable.js index 1febd23..5963d49 100644 --- a/client/src/components/admin/RecipesTable/RecipeTable.js +++ b/client/src/components/admin/RecipesTable/RecipeTable.js @@ -10,14 +10,14 @@ import Paper from '@mui/material/Paper'; import Checkbox from '@mui/material/Checkbox'; import FormControlLabel from '@mui/material/FormControlLabel'; import Switch from '@mui/material/Switch'; -import EnhancedTableToolbar from '../TableHelpers/EnhancedTableToolbar'; -import EnhancedTableHead from '../TableHelpers/EnhancedTableHead'; -import { getComparator, stableSort} from '../TableHelpers/TableHelpers' +import EnhancedRecipesTableToolbar from './EnhancedRecipesTableToolbar'; +import EnhancedRecipesTableHead from './EnhancedRecipesTableHead'; +import { getComparator, stableSort } from '../TableHelpers/TableHelpers' import { NavBar } from '../../utils/nav/nav'; -import { getRecipes } from '../../../redux/actions/adminAction'; import { useDispatch, useSelector } from 'react-redux'; -// import { getUsers } from '../../redux/actions/adminAction'; -//import ResponsiveAppBar from '../admin_NavBar'; +import { getRecipes, banRecipeById } from '../../../redux/actions/adminAction'; + + export const RecipeTable = () => { @@ -31,7 +31,7 @@ const {recipesList} = useSelector((store) => store.admin) const [selected, setSelected] = React.useState([]); const [page, setPage] = React.useState(0); const [dense, setDense] = React.useState(false); - const [userPerPage, setuserPerPage] = React.useState(15); + const [recipesPerPage, setrecipesPerPage] = React.useState(15); React.useEffect(()=>{ @@ -55,6 +55,7 @@ const {recipesList} = useSelector((store) => store.admin) const handleClick = (event, name) => { const selectedIndex = selected.indexOf(name); + console.log(selectedIndex, "SELECTED INDEX") let newSelected = []; if (selectedIndex === -1) { @@ -77,8 +78,8 @@ const {recipesList} = useSelector((store) => store.admin) setPage(newPage); }; - const handleChangeuserPerPage = (event) => { - setuserPerPage(parseInt(event.target.value, 10)); + const handleChangerecipesPerPage = (event) => { + setrecipesPerPage(parseInt(event.target.value, 10)); setPage(0); }; @@ -88,22 +89,22 @@ const {recipesList} = useSelector((store) => store.admin) const isSelected = (name) => selected.indexOf(name) !== -1; - // Avoid a layout jump when reaching the last page with empty user. - const emptyuser = - page > 0 ? Math.max(0, (1 + page) * userPerPage - recipesList.length) : 0; + // Avoid a layout jump when reaching the last page with empty recipe. + const emptyrecipes = + page > 0 ? Math.max(0, (1 + page) * recipesPerPage - recipesList.length) : 0; return (<> - + - {/*ACA TENGO QUE VER COMO LE PASO EL ID PARA BANEARLO*/} + {/*ACA TENGO QUE VER COMO LE PASO EL ID PARA BANEARLO*/} - store.admin) /> {/* if you don't need to support IE11, you can replace the `stableSort` call with: - user.slice().sort(getComparator(order, orderBy)) */} + recipe.slice().sort(getComparator(order, orderBy)) */} {stableSort(recipesList, getComparator(order, orderBy)) - .slice(page * userPerPage, page * userPerPage + userPerPage) + .slice(page * recipesPerPage, page * recipesPerPage + recipesPerPage) .map((row, index) => { const isItemSelected = isSelected(row.name); const labelId = `enhanced-table-checkbox-${index}`; @@ -150,16 +151,17 @@ const {recipesList} = useSelector((store) => store.admin) {row.name} {row.healthScore} {row.createdInDB.toString()} - {row.banned.toString()} - {row.userId} + {console.log(row.banned, "BANNED")} + {/* {row.banned.toString()} */} + {/* {row.user_id} */} ); })} - {emptyuser > 0 && ( + {emptyrecipes > 0 && ( @@ -169,13 +171,13 @@ const {recipesList} = useSelector((store) => store.admin)
    descendingComparator(a, b, orderBy) : (a, b) => -descendingComparator(a, b, orderBy); - } +} - // This method is created for cross-browser compatibility, if you don't - // need to support IE11, you can use Array.prototype.sort() directly - export function stableSort(array, comparator) { +export function stableSort(array, comparator) { const stabilizedThis = array.map((el, index) => [el, index]); stabilizedThis.sort((a, b) => { const order = comparator(a[0], b[0]); @@ -26,4 +24,4 @@ export function descendingComparator(a, b, orderBy) { return a[1] - b[1]; }); return stabilizedThis.map((el) => el[0]); - } \ No newline at end of file +} \ No newline at end of file diff --git a/client/src/components/admin/TableHelpers/EnhancedTableHead.js b/client/src/components/admin/UsersTable/EnhancedUsersTableHead.js similarity index 76% rename from client/src/components/admin/TableHelpers/EnhancedTableHead.js rename to client/src/components/admin/UsersTable/EnhancedUsersTableHead.js index bde3a8c..49b6d7b 100644 --- a/client/src/components/admin/TableHelpers/EnhancedTableHead.js +++ b/client/src/components/admin/UsersTable/EnhancedUsersTableHead.js @@ -6,10 +6,9 @@ import TableHead from '@mui/material/TableHead'; import TableRow from '@mui/material/TableRow'; import TableSortLabel from '@mui/material/TableSortLabel'; import { visuallyHidden } from '@mui/utils'; -//import pruebaUsers from '../components/User'; //importar User de la DB -import { headCellsUser } from '../UsersTable/headCellsUser'; +import { headCellsUser } from './headCellsUser'; -function EnhancedTableHead(props) { +function EnhancedUsersTableHead(props) { const { onSelectAllClick, order, orderBy, numSelected, rowCount, onRequestSort } = props; const createSortHandler = (property) => (event) => { @@ -21,15 +20,6 @@ function EnhancedTableHead(props) { banned - {/* 0 && numSelected < rowCount} - checked={rowCount > 0 && numSelected === rowCount} - onChange={onSelectAllClick} - inputProps={{ - 'aria-label': 'select all desserts', - }} - /> */} {headCellsUser.map((headCell) => ( ); } -EnhancedTableHead.propTypes = { +EnhancedUsersTableHead.propTypes = { numSelected: PropTypes.number.isRequired, onRequestSort: PropTypes.func.isRequired, onSelectAllClick: PropTypes.func.isRequired, @@ -65,4 +55,4 @@ EnhancedTableHead.propTypes = { rowCount: PropTypes.number.isRequired, }; -export default EnhancedTableHead +export default EnhancedUsersTableHead diff --git a/client/src/components/admin/TableHelpers/EnhancedTableToolbar.js b/client/src/components/admin/UsersTable/EnhancedUsersTableToolbar.js similarity index 87% rename from client/src/components/admin/TableHelpers/EnhancedTableToolbar.js rename to client/src/components/admin/UsersTable/EnhancedUsersTableToolbar.js index 88e75a2..6855b28 100644 --- a/client/src/components/admin/TableHelpers/EnhancedTableToolbar.js +++ b/client/src/components/admin/UsersTable/EnhancedUsersTableToolbar.js @@ -7,11 +7,10 @@ import IconButton from '@mui/material/IconButton'; import Tooltip from '@mui/material/Tooltip'; import DeleteIcon from '@mui/icons-material/Delete'; import FilterListIcon from '@mui/icons-material/FilterList'; -//import pruebaUsers from '../components/User'; //importar User de la DB -function EnhancedTableToolbar(props) { + +function EnhancedUsersTableToolbar(props) { const { numSelected } = props; - //const handleDelete = () => {} //AQUI VA EL DELETE return ( ); } -EnhancedTableToolbar.propTypes = { +EnhancedUsersTableToolbar.propTypes = { numSelected: PropTypes.number.isRequired, }; -export default EnhancedTableToolbar +export default EnhancedUsersTableToolbar diff --git a/client/src/components/admin/UsersTable/User.js b/client/src/components/admin/UsersTable/User.js deleted file mode 100644 index 82d1dc7..0000000 --- a/client/src/components/admin/UsersTable/User.js +++ /dev/null @@ -1,160 +0,0 @@ -const pruebaUsers = [ - { - id: '1', - username: 'Juan', - email: 'juan@email.com', - password: '123456', - banned: false, - admin: false, - premium: true, - nutricionist: false, - free: false, - logged: true, - }, - { - id: '2', - username: 'Pedro', - email: 'pedro@email.com', - password: '144456', - banned: true, - admin: false, - premium: false, - nutricionist: true, - free: false, - logged: false, - }, - { - id: '3', - username: 'Tito', - email: 'tito@email.com', - password: '744455', - banned: false, - admin: true, - premium: false, - nutricionist: false, - free: false, - logged: false, - }, - { - id: '4', - username: 'Toto', - email: 'toto@email.com', - password: '743355', - banned: false, - admin: false, - premium: false, - nutricionist: false, - free: true, - logged: true, - }, - { - id: '5', - username: 'Hugo', - email: 'hugo@email.com', - password: '943355', - banned: true, - admin: false, - premium: false, - nutricionist: false, - free: true, - logged: false, - }, - { - id: '6', - username: 'Juanito', - email: 'juanito@email.com', - password: '123456', - banned: false, - admin: false, - premium: true, - nutricionist: false, - free: false, - logged: true, - }, - { - id: '7', - username: 'Pedrovich', - email: 'pedrov@email.com', - password: '144456', - banned: true, - admin: false, - premium: false, - nutricionist: true, - free: false, - logged: false, - }, - { - id: '8', - username: 'Titon', - email: 'titon@email.com', - password: '744455', - banned: false, - admin: true, - premium: false, - nutricionist: false, - free: false, - logged: false, - }, - { - id: '9', - username: 'Totoloco', - email: 'totol@email.com', - password: '743355', - banned: false, - admin: false, - premium: false, - nutricionist: false, - free: true, - logged: true, - }, - { - id: '10', - username: 'Hugovius', - email: 'hugov@email.com', - password: '943355', - banned: true, - admin: false, - premium: false, - nutricionist: false, - free: true, - logged: false, - }, - { - id: '11', - username: 'Titonegro', - email: 'titon@email.com', - password: '744455', - banned: false, - admin: true, - premium: false, - nutricionist: false, - free: false, - logged: false, - }, - { - id: '12', - username: 'Totololo', - email: 'totol@email.com', - password: '743355', - banned: false, - admin: false, - premium: false, - nutricionist: false, - free: true, - logged: true, - }, - { - id: '13', - username: 'Hugon', - email: 'hugov@email.com', - password: '943355', - banned: true, - admin: false, - premium: false, - nutricionist: false, - free: true, - logged: false, - } -] - -export default pruebaUsers \ No newline at end of file diff --git a/client/src/components/admin/UsersTable/UserTable.js b/client/src/components/admin/UsersTable/UserTable.js index 1b32568..f4f26b6 100644 --- a/client/src/components/admin/UsersTable/UserTable.js +++ b/client/src/components/admin/UsersTable/UserTable.js @@ -10,8 +10,8 @@ import Paper from '@mui/material/Paper'; import Checkbox from '@mui/material/Checkbox'; import FormControlLabel from '@mui/material/FormControlLabel'; import Switch from '@mui/material/Switch'; -import EnhancedTableToolbar from '../TableHelpers/EnhancedTableToolbar'; -import EnhancedTableHead from '../TableHelpers/EnhancedTableHead'; +import EnhancedUsersTableToolbar from './EnhancedUsersTableToolbar'; +import EnhancedUsersTableHead from './EnhancedUsersTableHead'; import { getComparator, stableSort} from '../TableHelpers/TableHelpers' import { NavBar } from '../../utils/nav/nav'; import { useDispatch, useSelector } from 'react-redux'; @@ -21,34 +21,9 @@ import { banUserById } from '../../../redux/actions/adminAction'; export const UserTable = () => { -// const getAllUsers = /*async*/() => { //PASAR A ASYNC AWAIT CUANDO MIGRE AL PF -// try { -// let userData = /*await*/pruebaUsers.map(e => { -// return { -// id: e.id, -// username: e.username, -// email: e.email, -// password: e.password, -// banned: e.banned, -// admin: e.admin, -// premium: e.premium, -// nutricionist: e.nutricionist, -// free: e.free, -// logged: e.logged, -// } -// }) -// return userData -// } catch (error) { -// console.log(error) -// } -// } - - const {usersList} = useSelector((store) => store.admin) - - const dispatch = useDispatch() - + const dispatch = useDispatch() const [order, setOrder] = React.useState('asc'); const [orderBy, setOrderBy] = React.useState('calories'); @@ -71,9 +46,7 @@ const {usersList} = useSelector((store) => store.admin) const handleSelectAllClick = (event) => { if (event.target.checked) { const newSelected = usersList.map((n) => n.banned); - setSelected(newSelected); - return; } setSelected([]); @@ -113,7 +86,7 @@ const {usersList} = useSelector((store) => store.admin) setDense(event.target.checked); }; - const handleClick2 = (event, user, estado) => { + const handleClick2 = (event, user, estado) => { //ESTO ES PARA BANEAR console.log(user, "ESTE ES USER ID") console.log(estado, "ESTE ES EL ESTADO") @@ -123,7 +96,6 @@ const {usersList} = useSelector((store) => store.admin) const isSelected = (name) => selected.indexOf(name) !== -1; - // Avoid a layout jump when reaching the last page with empty user. const emptyuser = page > 0 ? Math.max(0, (1 + page) * userPerPage - usersList.length) : 0; @@ -131,14 +103,14 @@ const {usersList} = useSelector((store) => store.admin) - {/*ACA TENGO QUE VER COMO LE PASO EL ID PARA BANEARLO*/} + {/*ACA TENGO QUE VER COMO LE PASO EL ID PARA BANEARLO*/} - store.admin) rowCount={usersList.length} /> - {/* if you don't need to support IE11, you can replace the `stableSort` call with: - user.slice().sort(getComparator(order, orderBy)) */} {stableSort(usersList, getComparator(order, orderBy)) .slice(page * userPerPage, page * userPerPage + userPerPage) .map((row, index) => { diff --git a/client/src/components/admin/admin_NavBar.js b/client/src/components/admin/admin_NavBar.js deleted file mode 100644 index a54455f..0000000 --- a/client/src/components/admin/admin_NavBar.js +++ /dev/null @@ -1,162 +0,0 @@ -import * as React from 'react'; -import AppBar from '@mui/material/AppBar'; -import Box from '@mui/material/Box'; -import Toolbar from '@mui/material/Toolbar'; -import IconButton from '@mui/material/IconButton'; -import Typography from '@mui/material/Typography'; -import Menu from '@mui/material/Menu'; -import MenuIcon from '@mui/icons-material/Menu'; -import Container from '@mui/material/Container'; -import Avatar from '@mui/material/Avatar'; -import Button from '@mui/material/Button'; -import Tooltip from '@mui/material/Tooltip'; -import MenuItem from '@mui/material/MenuItem'; -//import AdbIcon from '@mui/icons-material/Adb'; - -const pages = ['Recipes', 'Users']; -const settings = ['Dashboard', 'Logout']; - -const ResponsiveAppBar = () => { - const [anchorElNav, setAnchorElNav] = React.useState(null); - const [anchorElUser, setAnchorElUser] = React.useState(null); - - const handleOpenNavMenu = (event) => { - setAnchorElNav(event.currentTarget); - }; - const handleOpenUserMenu = (event) => { - setAnchorElUser(event.currentTarget); - }; - - const handleCloseNavMenu = () => { - setAnchorElNav(null); - }; - - const handleCloseUserMenu = () => { - setAnchorElUser(null); - }; - - return ( - - - - {/* */} - - Nutri-U - - - - - - - - {pages.map((page) => ( - - {page} - - ))} - - - {/* */} - - Nutri-U - - - {pages.map((page) => ( - - ))} - - - - - - - - - - {settings.map((setting) => ( - - {setting} - - ))} - - - - - - ); -}; -export default ResponsiveAppBar; diff --git a/client/src/redux/actions/adminAction.js b/client/src/redux/actions/adminAction.js index 8747e20..1a7e395 100644 --- a/client/src/redux/actions/adminAction.js +++ b/client/src/redux/actions/adminAction.js @@ -101,6 +101,22 @@ export const banUserById = (id,banned) => async (dispatch) => { } +// export const banRecipeById = (id,banned) => async (dispatch) => { +// try{ +// let token = JSON.parse(sessionStorage.getItem('token')) +// let res = await axios.post(`${url}/recipe/admin/${id}`,{banned},{ +// headers:{ +// 'Authorization': `Bearer ${token}`, +// 'Accept' : 'application/json', +// 'Content-Type': 'application/json' +// } +// }) +// //dispatch(banRecipe(res.data)) +// }catch(e){ +// console.log(e) +// } + + // export const banRecipeById = (id) => async (dispatch) => { // try{ let token = JSON.parse(sessionStorage.getItem('token')) From 170a1c0fa3a4f168e29be040825999ec6bcc865e Mon Sep 17 00:00:00 2001 From: facoogle Date: Mon, 17 Oct 2022 20:28:47 -0300 Subject: [PATCH 26/38] profile imagen, falta --- client/src/pages/userBoart.js/userProfile.js | 37 ++++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/client/src/pages/userBoart.js/userProfile.js b/client/src/pages/userBoart.js/userProfile.js index 09d05db..0c45711 100644 --- a/client/src/pages/userBoart.js/userProfile.js +++ b/client/src/pages/userBoart.js/userProfile.js @@ -26,9 +26,9 @@ const UserProfile = () => { const {list} = useSelector((state) => state.user) const {profile} = useSelector((state) => state.user) - const [ image, setImage ] = useState("") + const [ image, setImage ] = useState("https://d500.epimg.net/cincodias/imagenes/2016/07/04/lifestyle/1467646262_522853_1467646344_noticia_normal.jpg") const [ loading, setLoading ] = useState(false) - + const ImgProfile = "https://d500.epimg.net/cincodias/imagenes/2016/07/04/lifestyle/1467646262_522853_1467646344_noticia_normal.jpg" const uploadImage = async (e) => { const files = e.target.files; @@ -44,9 +44,11 @@ const UserProfile = () => { } ) const file = await res.json(); + setImage(file.secure_url) console.log(file.secure_url) setLoading(false) + } const navigate2 = useNavigate() @@ -62,8 +64,6 @@ const UserProfile = () => { },[]) useEffect(()=>{ dispatch(getProfileData(userId)) - - },[dispatch]) console.log("hola soy getProfileData", profile) function handleUpdate(id, value){ @@ -116,9 +116,13 @@ const UserProfile = () => { const postImg = (e) => { e.preventDefault() + dispatch(uploadImg({userId,image})) } + + + return (
    @@ -129,11 +133,30 @@ return (
    - + +
    + { !profile.length?
    +
    {loading ? (

    Loading picture...

    ) : ()}
    +
    : + profile.map((el) => { + + return ( +
    +
    + {loading ? (

    Loading picture...

    ) : ()} +
    + +
    + ) + })} +
    + + + {/*
    */}
    - - + +
    From 63046cc91bf90899bb8600a87389a7412ee64bef Mon Sep 17 00:00:00 2001 From: facoogle Date: Tue, 18 Oct 2022 09:02:55 -0300 Subject: [PATCH 27/38] Mod recipe in db --- api/index.js | 4 +- api/src/controllers/recipescontrollers.js | 62 +++++++++++------------ api/src/getApiRecipes/getApiRecipe.js | 39 ++++++++++++++ 3 files changed, 73 insertions(+), 32 deletions(-) create mode 100644 api/src/getApiRecipes/getApiRecipe.js diff --git a/api/index.js b/api/index.js index 2a68ec0..1dc3ea2 100644 --- a/api/index.js +++ b/api/index.js @@ -2,7 +2,7 @@ const server = require('./src/app.js'); const { conn, Diet } = require('./src/db.js'); const {DB_PORT} = process.env const dietTypes = require('./src/utils/apispoon') - +const { getApi } = require("./src/getApiRecipes/getApiRecipe") // import dietTypes from './src/utils/apispoon' // Syncing all the models at once. @@ -26,4 +26,6 @@ conn.sync({ alter: true }).then(() => { }) }); + + getApi() }); \ No newline at end of file diff --git a/api/src/controllers/recipescontrollers.js b/api/src/controllers/recipescontrollers.js index f4dbd71..1d5c872 100644 --- a/api/src/controllers/recipescontrollers.js +++ b/api/src/controllers/recipescontrollers.js @@ -5,36 +5,36 @@ const { Recipe, Diet } = require("../db.js") const uuid = require('uuid'); -const getApiRecipes = async() => { - try { - - const axiosResponse = await axios.get(`https://api.spoonacular.com/recipes/complexSearch?apiKey=${API_KEY}&addRecipeInformation=true&number=100`) - const { results } = axiosResponse.data; - - if(results !== 0 ) { - let dishRecipe = await results?.map((e) => { - return { - //id: uuid.v4(), - id: e.id, - name: e.title, - healthScore: e.healthScore, - image: e.image, - banned: e.banned, - summary: e.summary, - //cuisines: e.cuisines?.map(ele => ele), - //dishTypes: e.dishTypes?.map(ele => ele), - diets: e.diets?.map(ele => ele), - createdInDB: false - //ingredients: e.analyzedInstructions[0].steps?.map(ele => ele.ingredients.name): "does not have any ingredient" - } - }) - return dishRecipe - } - - } catch(error) { - console.log(error) - } -} +// const getApiRecipes = async() => { +// try { + +// const axiosResponse = await axios.get(`https://api.spoonacular.com/recipes/complexSearch?apiKey=${API_KEY}&addRecipeInformation=true&number=100`) +// const { results } = axiosResponse.data; + +// if(results !== 0 ) { +// let dishRecipe = await results?.map((e) => { +// return { +// //id: uuid.v4(), +// id: e.id, +// name: e.title, +// healthScore: e.healthScore, +// image: e.image, +// banned: e.banned, +// summary: e.summary, +// //cuisines: e.cuisines?.map(ele => ele), +// //dishTypes: e.dishTypes?.map(ele => ele), +// diets: e.diets?.map(ele => ele), +// createdInDB: false +// //ingredients: e.analyzedInstructions[0].steps?.map(ele => ele.ingredients.name): "does not have any ingredient" +// } +// }) +// return dishRecipe +// } + +// } catch(error) { +// console.log(error) +// } +// } const getDBRecipes = async() => { @@ -126,7 +126,7 @@ const getDBNameRecipes = async(name) => { const getAllInfo = async() => { try { - let data = await getApiRecipes() + let data //await getApiRecipes() let dbData = await getDBRecipes() if(!dbData || dbData.length === 0) { diff --git a/api/src/getApiRecipes/getApiRecipe.js b/api/src/getApiRecipes/getApiRecipe.js new file mode 100644 index 0000000..6095523 --- /dev/null +++ b/api/src/getApiRecipes/getApiRecipe.js @@ -0,0 +1,39 @@ +const {Recipe} = require('../db') +const axios = require('axios'); +const { API_KEY } = process.env; + + + + + + + + +async function getApi(){ + const RecipesAllDb = await Recipe.findAll() + if(!RecipesAllDb.length){ + const apiAll = await axios.get(`https://api.spoonacular.com/recipes/complexSearch?apiKey=${API_KEY}&addRecipeInformation=true&number=100`) //apiAll.data <= .data .data + const apiInfo = await apiAll.data.results.map((e)=>{ + return { + apiId: e.id, + name: e.title, + healthScore: e.healthScore, + image: e.image, + banned: false, + summary: e.summary, + //cuisines: e.cuisines?.map(ele => ele), + //dishTypes: e.dishTypes?.map(ele => ele), + diets: e.diets?.map(ele => ele), + createdInDB: false + + } + + }) + + await Recipe.bulkCreate(apiInfo); +} + + +} + +module.exports = { getApi }; \ No newline at end of file From 50bd81098539e4b216135d702d98a7a6be19a57c Mon Sep 17 00:00:00 2001 From: Juan Martinez Date: Tue, 18 Oct 2022 09:06:18 -0300 Subject: [PATCH 28/38] falta terminar --- api/src/controllers/recipecontrollers.js | 11 +++++++++++ api/src/controllers/recipescontrollers.js | 2 +- api/src/routes/recipe.js | 14 +++++++++++++- .../components/admin/RecipesTable/RecipeTable.js | 2 +- client/src/redux/actions/adminAction.js | 1 + 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/api/src/controllers/recipecontrollers.js b/api/src/controllers/recipecontrollers.js index 44af5f9..6c3e332 100644 --- a/api/src/controllers/recipecontrollers.js +++ b/api/src/controllers/recipecontrollers.js @@ -82,10 +82,21 @@ const updateRecipe = async (id) => { } } +const recipeBanned =async(id,banned) =>{ + try { + let recipe = await Recipe.findByPk(id) + await recipe.update({banned: banned}) + return recipe + } catch (error) { + console.log(error) + } +} + module.exports = { getApiRecipeByID, createRecipe, deleteRecipe, updateRecipe, + recipeBanned }; diff --git a/api/src/controllers/recipescontrollers.js b/api/src/controllers/recipescontrollers.js index f4dbd71..c2b4cf9 100644 --- a/api/src/controllers/recipescontrollers.js +++ b/api/src/controllers/recipescontrollers.js @@ -19,7 +19,7 @@ const getApiRecipes = async() => { name: e.title, healthScore: e.healthScore, image: e.image, - banned: e.banned, + banned: false, summary: e.summary, //cuisines: e.cuisines?.map(ele => ele), //dishTypes: e.dishTypes?.map(ele => ele), diff --git a/api/src/routes/recipe.js b/api/src/routes/recipe.js index 2817218..9192471 100644 --- a/api/src/routes/recipe.js +++ b/api/src/routes/recipe.js @@ -1,7 +1,7 @@ const { Router } = require("express"); const router = Router(); const Recipe = require("../db"); -const { getApiRecipeByID, createRecipe, deleteRecipe, updateRecipe } = require("../controllers/recipecontrollers"); +const { getApiRecipeByID, createRecipe, deleteRecipe, updateRecipe, recipeBanned } = require("../controllers/recipecontrollers"); const auth = require('../middlewares/auth'); const { countRanking, getRecipePost } = require("../controllers/usersControllers/PostRanking.controllers"); @@ -88,5 +88,17 @@ router.put("/:id",auth, async (req, res) => { } }); +router.put("/banned/:id",auth, async (req, res) => { + let { id } = req.params; + let {banned} = req.body + try { + let recipe = await recipeBanned(id,banned) + res.send(`Recipe ${id} banned successfully`); + } catch (e) { + res.send(e.message); + } +}); + + module.exports = router; \ No newline at end of file diff --git a/client/src/components/admin/RecipesTable/RecipeTable.js b/client/src/components/admin/RecipesTable/RecipeTable.js index 5963d49..696e616 100644 --- a/client/src/components/admin/RecipesTable/RecipeTable.js +++ b/client/src/components/admin/RecipesTable/RecipeTable.js @@ -152,7 +152,7 @@ const {recipesList} = useSelector((store) => store.admin) {row.healthScore} {row.createdInDB.toString()} {console.log(row.banned, "BANNED")} - {/* {row.banned.toString()} */} + {row.banned.toString()} {/* {row.user_id} */} diff --git a/client/src/redux/actions/adminAction.js b/client/src/redux/actions/adminAction.js index 2801def..3a03d67 100644 --- a/client/src/redux/actions/adminAction.js +++ b/client/src/redux/actions/adminAction.js @@ -22,6 +22,7 @@ export const getRecipes = ()=> async (dispatch) => { 'Content-Type': 'application/json' } }) + console.log(res.data, "RECIPES") dispatch(getAllRecipes(res.data)) }catch(e){ console.log(e.message) From 9c2c3726314400c1005973420476f7ce7e5f4420 Mon Sep 17 00:00:00 2001 From: Juan Martinez Date: Tue, 18 Oct 2022 09:44:47 -0300 Subject: [PATCH 29/38] falta terminar --- api/src/controllers/recipecontrollers.js | 11 +---------- .../usersControllers/admin.controllers.js | 15 +++++++++++++-- api/src/routes/recipe.js | 14 +++----------- api/src/routes/users/admin.js | 14 ++++++++++++++ client/src/redux/actions/adminAction.js | 2 +- 5 files changed, 32 insertions(+), 24 deletions(-) diff --git a/api/src/controllers/recipecontrollers.js b/api/src/controllers/recipecontrollers.js index 6c3e332..0cd6d42 100644 --- a/api/src/controllers/recipecontrollers.js +++ b/api/src/controllers/recipecontrollers.js @@ -82,15 +82,7 @@ const updateRecipe = async (id) => { } } -const recipeBanned =async(id,banned) =>{ - try { - let recipe = await Recipe.findByPk(id) - await recipe.update({banned: banned}) - return recipe - } catch (error) { - console.log(error) - } -} + module.exports = { @@ -98,5 +90,4 @@ module.exports = { createRecipe, deleteRecipe, updateRecipe, - recipeBanned }; diff --git a/api/src/controllers/usersControllers/admin.controllers.js b/api/src/controllers/usersControllers/admin.controllers.js index 211cd0a..5562ca5 100644 --- a/api/src/controllers/usersControllers/admin.controllers.js +++ b/api/src/controllers/usersControllers/admin.controllers.js @@ -1,4 +1,4 @@ -const { User, Favorites } = require("../../db.js"); +const { User, Favorites, Recipe } = require("../../db.js"); const bcrypt = require('bcrypt'); const jwt = require('jsonwebtoken'); const authConfig = require('../config/auth.js') @@ -89,6 +89,16 @@ const userBanned =async(id,banned) =>{ } } +const recipeBanned =async(id,banned) =>{ + try { + let recipe = await Recipe.findByPk(id) + await recipe.update({banned: banned}) + return recipe + } catch (error) { + console.log(error) + } + } + const defaultList = async (user) =>{ let defList = await Favorites.create({ userId: user.id @@ -103,5 +113,6 @@ module.exports = { usersList, userByid, userByName, - userBanned + userBanned, + recipeBanned } \ No newline at end of file diff --git a/api/src/routes/recipe.js b/api/src/routes/recipe.js index 9192471..cae5518 100644 --- a/api/src/routes/recipe.js +++ b/api/src/routes/recipe.js @@ -1,7 +1,8 @@ const { Router } = require("express"); const router = Router(); const Recipe = require("../db"); -const { getApiRecipeByID, createRecipe, deleteRecipe, updateRecipe, recipeBanned } = require("../controllers/recipecontrollers"); +const { getApiRecipeByID, createRecipe, deleteRecipe, updateRecipe } = require("../controllers/recipecontrollers"); +const { recipeBanned } = require ("../controllers/usersControllers/admin.controllers") const auth = require('../middlewares/auth'); const { countRanking, getRecipePost } = require("../controllers/usersControllers/PostRanking.controllers"); @@ -88,16 +89,7 @@ router.put("/:id",auth, async (req, res) => { } }); -router.put("/banned/:id",auth, async (req, res) => { - let { id } = req.params; - let {banned} = req.body - try { - let recipe = await recipeBanned(id,banned) - res.send(`Recipe ${id} banned successfully`); - } catch (e) { - res.send(e.message); - } -}); + diff --git a/api/src/routes/users/admin.js b/api/src/routes/users/admin.js index 04158f3..65d54b7 100644 --- a/api/src/routes/users/admin.js +++ b/api/src/routes/users/admin.js @@ -7,6 +7,7 @@ const { userByName, userByid, userBanned, + recipeBanned, } = require("../../controllers/usersControllers/admin.controllers"); //Middleware @@ -77,4 +78,17 @@ router.post('/search/:id', auth, async(req,res)=>{ } }) + +router.post("/search/:id",auth, async (req, res) => { + let { id } = req.params; + let {banned} = req.body + try { + let recipe = await recipeBanned(id,banned) + res.send(`Recipe ${id} banned successfully`); + } catch (e) { + res.send(e.message); + } +}); + + module.exports = router; diff --git a/client/src/redux/actions/adminAction.js b/client/src/redux/actions/adminAction.js index 3a03d67..2c0b93b 100644 --- a/client/src/redux/actions/adminAction.js +++ b/client/src/redux/actions/adminAction.js @@ -120,7 +120,7 @@ export const banUserById = (id,banned) => async (dispatch) => { // export const banRecipeById = (id) => async (dispatch) => { // try{ - let token = JSON.parse(sessionStorage.getItem('token')) +// let token = JSON.parse(sessionStorage.getItem('token')) // let res = await axios.put(`http://${url}/recipe/admin/search/${id}`,{ // headers:{ // 'Authorization': `Bearer ${token}`, From 61c34d23ef68b758791daf0af4ce20ed267e4a8c Mon Sep 17 00:00:00 2001 From: facoogle Date: Tue, 18 Oct 2022 10:24:22 -0300 Subject: [PATCH 30/38] add route ban recipe --- .../usersControllers/notifications/notifications.js | 4 ++-- api/src/routes/users/admin.js | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/api/src/controllers/usersControllers/notifications/notifications.js b/api/src/controllers/usersControllers/notifications/notifications.js index a560317..fede68b 100644 --- a/api/src/controllers/usersControllers/notifications/notifications.js +++ b/api/src/controllers/usersControllers/notifications/notifications.js @@ -18,7 +18,7 @@ if(banned.toString() == "false"){ from: "nutri.u.contact@gmail.com", to: email, subject:"Your nutri-u account has been unbanned", - html:`

    Your account has been unbanned for administratornutri.u.contact@gmail.com

    `, + html:`

    Your account has been unbanned for administrator nutri.u.contact@gmail.com

    `, }) } @@ -27,7 +27,7 @@ if(banned.toString() == "true") { from: "nutri.u.contact@gmail.com", to: email, subject:"Your nutri-u account has been banned", - html:`

    You were blocked by a Nutri-u administrator, if you see that this was an error, contact this emailnutri.u.contact@gmail.com

    `, + html:`

    You were blocked by a Nutri-u administrator, if you see that this was an error, contact this email nutri.u.contact@gmail.com

    `, }) } diff --git a/api/src/routes/users/admin.js b/api/src/routes/users/admin.js index 65d54b7..1ad9452 100644 --- a/api/src/routes/users/admin.js +++ b/api/src/routes/users/admin.js @@ -79,12 +79,16 @@ router.post('/search/:id', auth, async(req,res)=>{ }) -router.post("/search/:id",auth, async (req, res) => { +router.post("/ban/:id",auth, async (req, res) => { let { id } = req.params; let {banned} = req.body + console.log(banned, "soy banned") try { let recipe = await recipeBanned(id,banned) - res.send(`Recipe ${id} banned successfully`); + + res.send(`Recipe ${id} banned or unbanned SUCCESS`); + + } catch (e) { res.send(e.message); } From 76ecc562d288e93664911bd893ffc738bd8658ed Mon Sep 17 00:00:00 2001 From: Pedro Caloiero Date: Tue, 18 Oct 2022 11:00:50 -0300 Subject: [PATCH 31/38] anda ponele --- client/src/components/admin/UsersTable/UserTable.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/client/src/components/admin/UsersTable/UserTable.js b/client/src/components/admin/UsersTable/UserTable.js index f4f26b6..ba604ca 100644 --- a/client/src/components/admin/UsersTable/UserTable.js +++ b/client/src/components/admin/UsersTable/UserTable.js @@ -31,11 +31,12 @@ const {usersList} = useSelector((store) => store.admin) const [page, setPage] = React.useState(0); const [dense, setDense] = React.useState(false); const [userPerPage, setuserPerPage] = React.useState(15); + const [banned, setBanned] = React.useState(false) React.useEffect(()=>{ dispatch(getUsers()) - },[]) + },[banned]) const handleRequestSort = (event, property) => { const isAsc = orderBy === property && order === 'asc'; @@ -91,7 +92,8 @@ const {usersList} = useSelector((store) => store.admin) console.log(user, "ESTE ES USER ID") console.log(estado, "ESTE ES EL ESTADO") dispatch(banUserById(user,estado)) - + if(banned === true) setBanned(false) + else setBanned(true) } const isSelected = (name) => selected.indexOf(name) !== -1; @@ -137,7 +139,7 @@ const {usersList} = useSelector((store) => store.admin) > handleClick2(event, row.id, isItemSelected)} + onChange={(event) => handleClick2(event, row.id, isItemSelected)} color="primary" checked={isItemSelected} inputProps={{ From 7be973eec07cdc02ecb94640000290756fbe63a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Duv=C3=A1n=20Merch=C3=A1n?= Date: Tue, 18 Oct 2022 15:27:07 -0500 Subject: [PATCH 32/38] dietas frot-back --- api/src/getApiRecipes/getApiRecipe.js | 44 +++++++++++-------- api/src/routes/recipes.js | 1 + .../recipes/detailrecipe/detailrecipe.js | 11 ++--- 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/api/src/getApiRecipes/getApiRecipe.js b/api/src/getApiRecipes/getApiRecipe.js index 6095523..dfc6748 100644 --- a/api/src/getApiRecipes/getApiRecipe.js +++ b/api/src/getApiRecipes/getApiRecipe.js @@ -1,7 +1,7 @@ -const {Recipe} = require('../db') +const {Recipe , Diet} = require('../db') const axios = require('axios'); const { API_KEY } = process.env; - +const uuid = require('uuid'); @@ -13,24 +13,32 @@ async function getApi(){ const RecipesAllDb = await Recipe.findAll() if(!RecipesAllDb.length){ const apiAll = await axios.get(`https://api.spoonacular.com/recipes/complexSearch?apiKey=${API_KEY}&addRecipeInformation=true&number=100`) //apiAll.data <= .data .data - const apiInfo = await apiAll.data.results.map((e)=>{ - return { - apiId: e.id, - name: e.title, - healthScore: e.healthScore, - image: e.image, - banned: false, - summary: e.summary, - //cuisines: e.cuisines?.map(ele => ele), - //dishTypes: e.dishTypes?.map(ele => ele), - diets: e.diets?.map(ele => ele), - createdInDB: false - - } + const apiInfo = await apiAll.data.results + Promise.allSettled( + await apiInfo.map(async(e)=>{ + + let recipe= await Recipe.create({ + id: uuid.v4(), + apiId: e.id, + name: e.title, + healthScore: e.healthScore, + image: e.image, + banned: false, + summary: e.summary, + //cuisines: e.cuisines?.map(ele => ele), + //dishTypes: e.dishTypes?.map(ele => ele), + //diets: e.diets?.map(ele => ele), + createdInDB: false - }) + }) + + let diet = await Diet.findAll({ + where:{name:e.diets} + }) - await Recipe.bulkCreate(apiInfo); + await recipe.addDiet(diet) + }) + ) } diff --git a/api/src/routes/recipes.js b/api/src/routes/recipes.js index b949a5d..c01cf1f 100644 --- a/api/src/routes/recipes.js +++ b/api/src/routes/recipes.js @@ -14,6 +14,7 @@ router.get("/", async (req, res) => { } else { let allInfo =await getAllInfo() + return res.status(201).json(allInfo) } diff --git a/client/src/components/recipes/detailrecipe/detailrecipe.js b/client/src/components/recipes/detailrecipe/detailrecipe.js index 96c0595..0d6e4fa 100644 --- a/client/src/components/recipes/detailrecipe/detailrecipe.js +++ b/client/src/components/recipes/detailrecipe/detailrecipe.js @@ -89,11 +89,12 @@ const RecipeDetail = () => {

    Diet/s

    - {recipe.createdInDB ? ( -

    {recipe.diets[0].name}

    - ) : ( -

    {recipe.diets}

    - )} + {console.log(recipe.diets)} + {recipe.diets? recipe.diets.map(r=>{ + return

    {r.name}

    + } + + ) : null}
    Health Score
  • {recipe.healthScore}
  • From f6b72501b6a8dd11ea356c8aaf4201f29c047f92 Mon Sep 17 00:00:00 2001 From: Pedro Caloiero Date: Tue, 18 Oct 2022 19:40:24 -0300 Subject: [PATCH 33/38] spinner en el payment --- client/src/components/utils/Stripe/checkoutForm.js | 12 +++++++++--- .../spinner/{spinner.module.css => spinner.css} | 3 ++- client/src/components/utils/spinner/spinner.js | 12 ++++++------ 3 files changed, 17 insertions(+), 10 deletions(-) rename client/src/components/utils/spinner/{spinner.module.css => spinner.css} (89%) diff --git a/client/src/components/utils/Stripe/checkoutForm.js b/client/src/components/utils/Stripe/checkoutForm.js index b5423bf..2b938b3 100644 --- a/client/src/components/utils/Stripe/checkoutForm.js +++ b/client/src/components/utils/Stripe/checkoutForm.js @@ -9,6 +9,7 @@ import { import swal from 'sweetalert'; import { NavBar } from "../nav/nav"; import { useNavigate } from "react-router-dom" +import { Spinner } from '../spinner/spinner' import './checkoutForm.css' const { REACT_APP_HOST } = process.env; @@ -31,6 +32,7 @@ export function PaymentForm() { const [user, setUser] = useState('') + const [loader, setLoader] = useState(true) const stripe = useStripe(); const elements = useElements(); @@ -39,6 +41,8 @@ export function PaymentForm() { const createSubscription = async () => { try { + + setLoader(false) const paymentMethod = await stripe.createPaymentMethod({ card: elements.getElement("cardNumber"), @@ -64,7 +68,9 @@ export function PaymentForm() { // console.log('ESTIIIII', data.respuesta) const confirm = await stripe.confirmCardPayment(data.respuesta.clientSecret); + console.log('estoo',confirm) if (confirm.error) return alert("Payment unsuccessful!"); + if (confirm) setLoader(true) swal("Payment Successful! Subscription active.").then(navigate2('/home')) @@ -94,12 +100,12 @@ export function PaymentForm() {

    BE PREMIUM NOW!

    + { + loader === false ? : <> + }

    - {/* -
    - */}
    diff --git a/client/src/components/utils/spinner/spinner.module.css b/client/src/components/utils/spinner/spinner.css similarity index 89% rename from client/src/components/utils/spinner/spinner.module.css rename to client/src/components/utils/spinner/spinner.css index 60d96a4..1bdd354 100644 --- a/client/src/components/utils/spinner/spinner.module.css +++ b/client/src/components/utils/spinner/spinner.css @@ -8,7 +8,8 @@ } .spinnerContainer { - position: relative; + position: absolute; + padding-bottom: 120px; width: 100vw; height: 60vh; display: flex; diff --git a/client/src/components/utils/spinner/spinner.js b/client/src/components/utils/spinner/spinner.js index 12f719e..f7c48e7 100644 --- a/client/src/components/utils/spinner/spinner.js +++ b/client/src/components/utils/spinner/spinner.js @@ -1,11 +1,11 @@ import React from 'react'; -import style from './Spinner.module.css'; - -export default function Spinner(){ +import './spinner.css'; +export function Spinner(){ return( -
    -
    +
    +
    ); -} \ No newline at end of file +} + From 11e959f3c109db45af394d2a75d5878ff9d8ff07 Mon Sep 17 00:00:00 2001 From: Pedro Caloiero Date: Tue, 18 Oct 2022 19:45:48 -0300 Subject: [PATCH 34/38] listo --- client/src/components/utils/Stripe/checkoutForm.js | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/components/utils/Stripe/checkoutForm.js b/client/src/components/utils/Stripe/checkoutForm.js index 2b938b3..6cbfa8b 100644 --- a/client/src/components/utils/Stripe/checkoutForm.js +++ b/client/src/components/utils/Stripe/checkoutForm.js @@ -77,6 +77,7 @@ export function PaymentForm() { } catch (err) { // console.error(err); swal("Payment failed! Please checkout the given information", `Error message: ${err.message}` ); + setLoader(true) } }; From e8d59e8a6c7244e8f5701417a8f45a6d79603a7b Mon Sep 17 00:00:00 2001 From: Leandro Espinasse <99082701+LEANDROESPINASSE@users.noreply.github.com> Date: Tue, 18 Oct 2022 20:30:41 -0300 Subject: [PATCH 35/38] your post reviewed css --- .../usersControllers/userfree.controller.js | 2 +- api/src/models/Payment.js | 6 ++++++ client/src/components/usersBoart/UserPost.css | 20 +++++++++++++++++++ client/src/components/usersBoart/UserPost.js | 14 ++++++++----- client/src/pages/userBoart.js/userProfile.js | 2 +- 5 files changed, 37 insertions(+), 7 deletions(-) create mode 100644 client/src/components/usersBoart/UserPost.css diff --git a/api/src/controllers/usersControllers/userfree.controller.js b/api/src/controllers/usersControllers/userfree.controller.js index 87f0d20..5d3e499 100644 --- a/api/src/controllers/usersControllers/userfree.controller.js +++ b/api/src/controllers/usersControllers/userfree.controller.js @@ -54,7 +54,7 @@ const changeToPremium = async (userEmail, userName, paymentMethod) =>{ paymenthID: subscription.id, }) - // console.log('facturaa',factura) + //console.log('facturaa',factura) await user.addPayment(factura) user.update({ premium: true }) diff --git a/api/src/models/Payment.js b/api/src/models/Payment.js index e0f5ea8..ecf5629 100644 --- a/api/src/models/Payment.js +++ b/api/src/models/Payment.js @@ -3,6 +3,12 @@ const { DataTypes } = require('sequelize'); module.exports = (sequelize) => { sequelize.define('payment', { + // id: { + // type: DataTypes.INTEGER, + // autoIncrement: true, + // primaryKey: true, + // allowNull: false + // }, paymenthID:{ type: DataTypes.STRING, allowNull: false diff --git a/client/src/components/usersBoart/UserPost.css b/client/src/components/usersBoart/UserPost.css new file mode 100644 index 0000000..6ca96cc --- /dev/null +++ b/client/src/components/usersBoart/UserPost.css @@ -0,0 +1,20 @@ +.postcontainer { + padding: 1em; +} + +.profilepostimage { + border-radius: 4%; +} + +.postcoment { + border-radius: 3%; + margin-right: 30%; + margin-bottom: 1%; + padding: 0.6em; + background: #f9f9f9; + border: 1px solid #c1c1c1; +} + +.postname { + margin-top: 2%; +} \ No newline at end of file diff --git a/client/src/components/usersBoart/UserPost.js b/client/src/components/usersBoart/UserPost.js index 0e89293..e2c8e7c 100644 --- a/client/src/components/usersBoart/UserPost.js +++ b/client/src/components/usersBoart/UserPost.js @@ -1,16 +1,20 @@ import React from 'react' +import "./UserPost.css" const UserPost = ({post}) => { return (
    -
    +
    +
    - recipeImg -

    {post.recipeName}

    + recipeImg +
    +

    {post.recipeName}

    -
    {post.username}
    - {post.content} +
    {post.username}:
    +
    {post.content}
    +
    ) diff --git a/client/src/pages/userBoart.js/userProfile.js b/client/src/pages/userBoart.js/userProfile.js index 0c45711..11048f5 100644 --- a/client/src/pages/userBoart.js/userProfile.js +++ b/client/src/pages/userBoart.js/userProfile.js @@ -232,7 +232,7 @@ return (
    -

    Your post

    +

    The post you Reviewed

    {userPost.length>0? userPost.map(post=>{ From b3bd031f6593220a0f368776c4dfacfcf950a1ba Mon Sep 17 00:00:00 2001 From: Juan Martinez Date: Tue, 18 Oct 2022 22:49:57 -0300 Subject: [PATCH 36/38] FUNCIONAAAAAA GRACIAS JALU --- .../components/admin/UsersTable/UserTable.js | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/client/src/components/admin/UsersTable/UserTable.js b/client/src/components/admin/UsersTable/UserTable.js index 1b32568..a702643 100644 --- a/client/src/components/admin/UsersTable/UserTable.js +++ b/client/src/components/admin/UsersTable/UserTable.js @@ -47,7 +47,7 @@ export const UserTable = () => { const {usersList} = useSelector((store) => store.admin) - const dispatch = useDispatch() + const dispatch = useDispatch() const [order, setOrder] = React.useState('asc'); @@ -56,7 +56,12 @@ const {usersList} = useSelector((store) => store.admin) const [page, setPage] = React.useState(0); const [dense, setDense] = React.useState(false); const [userPerPage, setuserPerPage] = React.useState(15); + const [click, setClick] = React.useState(false) + React.useEffect(() => { + dispatch(getUsers()) + },[click]) + React.useEffect(()=>{ dispatch(getUsers()) @@ -114,14 +119,18 @@ const {usersList} = useSelector((store) => store.admin) }; const handleClick2 = (event, user, estado) => { - + console.log(event.target.checked, "ESTE ES EL EVENT") console.log(user, "ESTE ES USER ID") console.log(estado, "ESTE ES EL ESTADO") - dispatch(banUserById(user,estado)) - + click ? setClick(false) : setClick(true) + dispatch(banUserById(user,event.target.checked)) + dispatch(getUsers()) } - const isSelected = (name) => selected.indexOf(name) !== -1; + const isSelected = (id) => { + let usuario = usersList.find((user) => user.id === id) + return usuario.banned + } // Avoid a layout jump when reaching the last page with empty user. const emptyuser = @@ -131,7 +140,7 @@ const {usersList} = useSelector((store) => store.admin) - {/*ACA TENGO QUE VER COMO LE PASO EL ID PARA BANEARLO*/} +
    store.admin) {stableSort(usersList, getComparator(order, orderBy)) .slice(page * userPerPage, page * userPerPage + userPerPage) .map((row, index) => { - const isItemSelected = isSelected(row.username); + const isItemSelected = isSelected(row.id); const labelId = `enhanced-table-checkbox-${index}`; return ( From 1b22072ec266c2445a4491d1496e54fd2dd19d8e Mon Sep 17 00:00:00 2001 From: facoogle Date: Tue, 18 Oct 2022 23:59:00 -0300 Subject: [PATCH 37/38] Modificacion Calculator --- .../utils/imcalculator/images/flaquito.png | Bin 0 -> 10324 bytes .../utils/imcalculator/images/gordito.png | Bin 0 -> 10497 bytes .../utils/imcalculator/images/gordo.png | Bin 0 -> 10102 bytes .../utils/imcalculator/images/normal.png | Bin 0 -> 10335 bytes .../utils/imcalculator/images/rellenito.png | Bin 0 -> 10699 bytes .../utils/imcalculator/images/status.png | Bin 0 -> 8346 bytes .../utils/imcalculator/imcalculator.css | 46 +++++++-- .../utils/imcalculator/imcalculator.js | 92 ++++++++++++------ 8 files changed, 98 insertions(+), 40 deletions(-) create mode 100644 client/src/components/utils/imcalculator/images/flaquito.png create mode 100644 client/src/components/utils/imcalculator/images/gordito.png create mode 100644 client/src/components/utils/imcalculator/images/gordo.png create mode 100644 client/src/components/utils/imcalculator/images/normal.png create mode 100644 client/src/components/utils/imcalculator/images/rellenito.png create mode 100644 client/src/components/utils/imcalculator/images/status.png diff --git a/client/src/components/utils/imcalculator/images/flaquito.png b/client/src/components/utils/imcalculator/images/flaquito.png new file mode 100644 index 0000000000000000000000000000000000000000..f2c83d5f94bb8115ca64fe3f1474b62c9b8e772a GIT binary patch literal 10324 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 DKsBtF literal 0 HcmV?d00001 diff --git a/client/src/components/utils/imcalculator/images/gordo.png b/client/src/components/utils/imcalculator/images/gordo.png new file mode 100644 index 0000000000000000000000000000000000000000..74cfdd0a470ad0ce3c60b33aa65c98dcc8a238dc GIT binary patch literal 10102 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 T5&zJ?ojE{VSx2ct5gGD7IW*_( literal 0 HcmV?d00001 diff --git a/client/src/components/utils/imcalculator/images/normal.png b/client/src/components/utils/imcalculator/images/normal.png new file mode 100644 index 0000000000000000000000000000000000000000..b09bb9f428bfdaa72bc87009ede29a9fe17f3c45 GIT binary patch literal 10335 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 literal 0 HcmV?d00001 diff --git a/client/src/components/utils/imcalculator/images/status.png b/client/src/components/utils/imcalculator/images/status.png new file mode 100644 index 0000000000000000000000000000000000000000..5c6550d9712b2e5d3dc3436f9562fcbfe84894a8 GIT binary patch literal 8346 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 @@ -12,6 +21,7 @@ export const CalculatorIMC= ()=>{ const [peso, setPeso] = useState(""); const [altura, setAltura] = useState(""); + const [imgEjemplo, setImgEjemplo] = useState(status) const user = window.sessionStorage.getItem("user") let userLogged @@ -25,47 +35,60 @@ export const CalculatorIMC= ()=>{ function calcularIMC (){ + const alt = altura / 100; const imc = peso / (alt * alt); if(altura === "" && peso === ""){ - swal("Debes insertar ambos datos, Peso y Altura"); - }else if(!alt){ - swal("Por favor, rellene el peso y la altura correctamente !"); + swal("Please insert your weight and height"); + } + else if (isNaN(altura) && isNaN(peso)) { + swal('You must enter the data correctly'); + } + else if(!alt){ + swal("You must enter only numbers !"); }else if (imc < 16.9){ - setMensagem(`Estas muy bajo de peso!`); - setEfeitos(`Efectos secundarios: pérdida de cabello, infertilidad, períodos menstruales perdidos.`); - setImcMessage(`Su IMC : ${imc.toFixed(2)}`); + setMensagem(`You are very underweight!`); + setEfeitos(`Side effects: hair loss, infertility, missed menstrual periods.`); + setImcMessage(`Your IBM is : ${imc.toFixed(2)}`); + setImgEjemplo(flaquito) + }else if(imc >= 17 && imc < 18.4){ - setMensagem(`Estas bajo de peso !`); - setEfeitos(`Efectos secundarios: fatiga, estrés, ansiedad.`); - setImcMessage(`Su IMC es: ${imc.toFixed(2)}`); + setMensagem(`you are underweight !`); + setEfeitos(`Side effects: fatigue, stress, anxiety.`); + setImcMessage(`Your BMI is: ${imc.toFixed(2)}`); + setImgEjemplo(flaquito) }else if (imc >= 18.5 && imc < 24.9){ - setMensagem(`Eres de peso normal !`); - setEfeitos(`Efectos secundarios: menor riesgo de enfermedades cardíacas y vasculares.`); - setImcMessage(`Su IMC es: ${imc.toFixed(2)}`); + setMensagem(`You are normal weight !`); + setEfeitos(`Side effects: lower risk of heart and vascular diseases.`); + setImcMessage(`Your BMI is: ${imc.toFixed(2)}`); + setImgEjemplo(normal) }else if(imc >= 25 && imc < 29.9){ - setMensagem(`¿Tienes sobrepeso? !`); - setEfeitos(`Efectos secundarios: menor riesgo de enfermedades cardíacas y vasculares.`); - setImcMessage(`Su IMC es: ${imc.toFixed(2)}`); + setMensagem(`Are you overweight? !`); + setEfeitos(`Side effects: lower risk of heart and vascular diseases.`); + setImcMessage(`Your BMI is: ${imc.toFixed(2)}`); + setImgEjemplo(rellenito) }else if(imc >= 30 && imc < 34.9){ - setMensagem(`Tienes Obesidad Grado I!`); - setEfeitos(`Efectos secundarios: apnea del sueño, dificultad para respirar.`); - setImcMessage(`Su IMC es: ${imc.toFixed(2)}`); + setMensagem(`You have Obesity Grade I!`); + setEfeitos(`Side effects: sleep apnea, shortness of breath.`); + setImcMessage(`Your BMI is: ${imc.toFixed(2)}`); + setImgEjemplo(gordito) }else if(imc >= 35 && imc < 40){ - setMensagem(`Tienes Obesidad Grado II!`); - setEfeitos(`Efectos secundarios: diabetes, angina de pecho, infarto de miocardio, aterosclerosis`); - setImcMessage(`Su IMC es: ${imc.toFixed(2)}`); + setMensagem(`You have Obesity Grade II!`); + setEfeitos(`Side effects: diabetes, angina pectoris, myocardial infarction, atherosclerosis`); + setImcMessage(`Your BMI is: ${imc.toFixed(2)}`); + setImgEjemplo(gordo) }else if(imc >= 40){ - setMensagem(`Tienes Obesidad Grado III !`); - setEfeitos(`Efectos secundarios: reflujo, dificultad para moverse, úlceras de decúbito, diabetes, ataque cardíaco, accidente cerebrovascular.`); - setImcMessage(`Su IMC es: ${imc.toFixed(2)}`); + setMensagem(`You have Grade III Obesity !`); + setEfeitos(`Side effects: reflux, difficulty moving, bedsores, diabetes, heart attack, stroke.`); + setImcMessage(`Your BMI is: ${imc.toFixed(2)}`); + setImgEjemplo(gordo) } } @@ -84,15 +107,17 @@ export const CalculatorIMC= ()=>{ return( +
    +
    -

    Calculadora de IMC

    - Vamos Calcular su IMC ? +

    BMI calculator

    + Let's Calculate your BMI ? setPeso(e.target.value) } /> @@ -100,15 +125,15 @@ export const CalculatorIMC= ()=>{ setAltura(e.target.value) } /> - +

    {mensagem}
    {efeitos}
    @@ -117,15 +142,18 @@ export const CalculatorIMC= ()=>{

    {imcMessage}

    +
    +
    - - Go to Profile! + + GoToProfile!
    +
    ); } From d9f533af6085cfafcf48d919f2943978eca7be83 Mon Sep 17 00:00:00 2001 From: Juan Martinez Date: Wed, 19 Oct 2022 00:30:17 -0300 Subject: [PATCH 38/38] bug fixed --- client/src/components/admin/UsersTable/UserTable.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/components/admin/UsersTable/UserTable.js b/client/src/components/admin/UsersTable/UserTable.js index 37f34a8..e559254 100644 --- a/client/src/components/admin/UsersTable/UserTable.js +++ b/client/src/components/admin/UsersTable/UserTable.js @@ -42,7 +42,7 @@ const {usersList} = useSelector((store) => store.admin) React.useEffect(()=>{ dispatch(getUsers()) - },[banned]) + },[]) const handleRequestSort = (event, property) => { const isAsc = orderBy === property && order === 'asc'; @@ -114,7 +114,7 @@ const {usersList} = useSelector((store) => store.admin) - +