Compare commits

..

10 Commits

Author SHA1 Message Date
Fernando 4d394338ef Agregado express a la configuracion de Vue y WebPack 2018-11-02 20:44:48 -05:00
Fernando 2639d6303a Inicio de desarrollo de funcionalidad Facturas/Boletas y backup. 2018-11-02 18:37:08 -05:00
Fernando 65d434b5fa Mejoras en el inicio de sesion. 2018-11-02 11:39:33 -05:00
Fernando 1b65d4af33 Finalizada gestion de usuarios con google. 2018-10-30 10:20:02 -05:00
Fernando a389ae269f Agregado un Backend provisional para la gestion de usuarios.
Agregada una BBDD MySQL en remoto con Google Cloud
2018-10-29 12:36:33 -05:00
Fernando e51e687c57 Agregado el carrito. 2018-10-28 17:35:22 -05:00
Fernando a24e3f2600 Requerimientos 2018-10-14 13:05:06 -05:00
Fernando 8681fd255b Cambio a Vue Cli 2018-10-13 21:20:15 -05:00
Fernando ab5793e322 Limpieza 2018-10-13 20:58:41 -05:00
Fernando 3ba30efacc - Nuevo componente Tienda que lista los productos
- Cambios menores
2018-10-08 20:41:33 -05:00
76 changed files with 15105 additions and 11898 deletions

27
.gcloudignore Normal file
View File

@ -0,0 +1,27 @@
# This file specifies files that are *not* uploaded to Google Cloud Platform
# using gcloud. It follows the same syntax as .gitignore, with the addition of
# "#!include" directives (which insert the entries of the given .gitignore-style
# file at that point).
#
# For more information, run:
# $ gcloud topic gcloudignore
#
.gcloudignore
# If you would like to upload your .git directory, .gitignore file or files
# from your .gitignore file, remove the corresponding line
# below:
.git
.gitignore
# Node.js dependencies:
node_modules/
# Archivos de desarrollo
src/
public/
# Archivos de JetBrains
.idea/
# Archivos de TypeScript
*.ts

27
.gitignore vendored
View File

@ -1,3 +1,24 @@
/node_modules
/idea
**.map
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*
# Archivos js (ya que estoy usando ts)
/Backend/*.js

View File

@ -1,19 +0,0 @@
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /ihc/index.php [L]
</IfModule>
## Desabilitar cache de Apache
<FilesMatch "\.(html|htm|js|css)$">
FileETag None
<IfModule mod_headers.c>
Header unset ETag
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "Wed, 12 Jan 1980 05:00:00 GMT"
</IfModule>
</FilesMatch>

View File

@ -0,0 +1,47 @@
const obtenerPedidosActuales = (req:any, res:any) => {
res.header('Access-Control-Allow-Origin', 'http://localhost:8081');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
const USER_ID = req.body.USER_ID;
const storedUserId = req.session.USER_ID.toString();
console.log(`La comparacion: ${USER_ID} === ${storedUserId}. ${typeof USER_ID} y ${typeof storedUserId}`);
if (USER_ID === storedUserId) {
const SQL_CONNECT_DATA = require('../VARIABLES').sqlConnectData;
const con = require('mysql').createConnection(SQL_CONNECT_DATA);
con.connect((err:any) => {
if (err) {
console.log(`Error al conectarse a la base de datos en obtenerPedidosActuales.ts 13.\n${err}`);
res.send(`{"error": "Error al conectarse a la base de datos."}`);
return;
}
con.query(
`SELECT BOLETA_ID, transacciones, horaEntrega FROM boletas WHERE USER_ID='${USER_ID}'
ORDER BY BOLETA_ID DESC `,
(err:any, response:any) => {
if (err) {
console.log(`Error al obtener las boletas del usuario ${USER_ID} en obtenerPedidosActuales.ts \
23.\n${err}`);
res.send("");
return;
}
res.send(JSON.stringify(response));
res.end();
}
);
});
} else {
res.send(`{"error": "El usuario que envia la peticion y el usuario logeado no coinciden."}`);
}
};
module.exports.obtenerPedido = obtenerPedidosActuales;

8
Backend/VARIABLES.ts Normal file
View File

@ -0,0 +1,8 @@
const SQL_CONNECT_DATA:object = {
host: '35.193.16.64',
user: 'Araozu',
password: 'xsakah4b',
database: 'Usuarios_DB'
};
module.exports.sqlConnectData = SQL_CONNECT_DATA;

View File

@ -0,0 +1,16 @@
declare var module:any;
declare var require:any;
const {OAuth2Client} = require('google-auth-library');
const CLIENT_ID:string = "443321715214-9joe4c9l00osc6qcc4l0i2k3420jvb7q.apps.googleusercontent.com";
const client = new OAuth2Client(CLIENT_ID);
async function verify(token:string) {
const ticket = await client.verifyIdToken({
idToken: token,
audience: CLIENT_ID
});
return ticket.getPayload();
}
module.exports.validator = verify;

View File

@ -0,0 +1,89 @@
const exec = (nombre:string, email:string, pass:string, sesion:any) =>
new Promise((resolve, reject) => {
const mysql = require('mysql');
const SQL_CONNECT_DATA = require('./VARIABLES').sqlConnectData;
const con = mysql.createConnection(SQL_CONNECT_DATA);
con.connect((err:any) => {
if (err) reject("Error al conectarse a la BBDD. registrarUsuarios.ts 10.\n" + err);
con.query(
`SELECT email FROM usuarios WHERE email='${email}'`,
(err:any, respuesta:any) => {
const data = JSON.stringify(respuesta);
if (data === "[]") {
con.query(
`INSERT INTO usuarios (GOOGLE_ID, nombre, email, img, carritoActual, contrasena, ROL)
VALUES ('0','${nombre}', '${email}', '/img/usuario.png', '{}', '${pass}', 'user' )`,
(err:any, respuesta:any) => {
if (err) reject ('Error al ejecutar SQL. registrarUsuario.ts 21\n' + err);
/* El servidor me obligo a hacer esto en vez de usar SELECT LAST_INSERT_ID() */
con.query(
`SELECT USER_ID FROM usuarios WHERE email='${email}'`,
(err:any, respuesta:any) => {
if (err) reject ('Error al ejecutar SQL. registrarUsuario.ts 27\n' + err);
/* Crea la variable de sesion */
sesion.nombre = nombre;
sesion.email = email;
sesion.img = '/img/usuario.png';
sesion.carritoActual = '{}';
sesion.USER_ID = respuesta[0]["USER_ID"];
sesion.ROL = 'user';
sesion.save((err:any) => {
if (err) console.log(`Error :c\n${err}`);
console.log("En teoria ya guarde la sesion....");
});
const datos = {
nombre,
email,
img: '/img/usuario.png',
carritoActual: '{}',
'USER_ID': respuesta[0]["USER_ID"],
ROL: 'user',
logged: true
};
resolve(`{ "existe": false, "creado": true, "data": ${JSON.stringify(datos)} }`);
}
);
}
);
} else {
resolve(`{ "existe": true }`);
}
}
);
});
});
const registrar = (req:any, res:any) => {
res.header('Access-Control-Allow-Origin', 'http://localhost:8081');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
const sesion = req.session;
const nombre:string = req.body.nombre;
const email:string = req.body.email;
const pass:string = req.body.pass;
if (nombre && email && pass) {
exec(nombre, email, pass, sesion)
.then(respuesta => {
res.send(respuesta);
})
.catch(reason => console.log("Ups. Un error.\n" + reason));
} else {
res.send("Error, datos insuficientes.");
}
};
module.exports.registrar = registrar;

117
Backend/revisarUsuarioG.ts Normal file
View File

@ -0,0 +1,117 @@
const validator = require('./google_validation.js').validator;
const crearUsuario = (con:any, data:object) =>
new Promise((resolve, reject) => {
con.query (
`INSERT INTO usuarios (nombre, email, img, carritoActual, GOOGLE_ID, ROL)\
VALUES ('${(data as any)["nombreUsuario"]}', '${(data as any)["emailUsuario"]}',
'${(data as any)["imagenUsuario"]}', '{}', '${(data as any)["googleID"]}', 'user')`,
(err:any, res:string) => {
if (err) {
reject("Error al ejecutar query SQL (revisarUsuarioG.ts fila 11))...\n" + err);
}
/* Luego de insertar el usuario, como GET_LAST_INDEX no funciona, otra query obtiene el num de usuario */
con.query(
`SELECT USER_ID FROM usuarios WHERE GOOGLE_ID='${(data as any)["googleID"]}'`,
(err:any, res:any) => {
if (err) reject(`Error al ejecutar query SQL en revisarUsuarios.ts 18.\n${err}`);
resolve(res[0]["USER_ID"]);
}
);
}
);
});
const revisarUsuarioG = (usuario:object, sesion:any) => {
return new Promise((resolve, reject) => {
const mysql = require('mysql');
const SQL_CONNECT_DATA = require('./VARIABLES').sqlConnectData;
const con = mysql.createConnection(SQL_CONNECT_DATA);
con.connect( (err:any) => {
if (err) {
reject("Error al conectarse a la BBDD.");
}
const nombreUsuario:string = (usuario as any)["name"];
const emailUsuario:string = (usuario as any)["email"];
const imagenUsuario:string = (usuario as any)["picture"];
const googleID:number = (usuario as any)["sub"];
con.query (`SELECT nombre, email, img, carritoActual, USER_ID, ROL FROM usuarios WHERE GOOGLE_ID='${googleID}'`,
(err:any, response:any) => {
if (err) {
reject("Error al ejecutar query SQL");
}
const respuestaBD:string = JSON.stringify(response);
if (respuestaBD === '[]') {
/* El usuario no existe :D */
crearUsuario(con, {nombreUsuario, emailUsuario, imagenUsuario, googleID})
.then( (res:any) => {
/* Almacenar la sesion :c */
sesion.nombre = nombreUsuario;
sesion.email = emailUsuario;
sesion.img = imagenUsuario;
sesion.USER_ID = res[0]["USER_ID"];
sesion.ROL = "user";
sesion.carritoActual = "{}";
sesion.save((err:any) => {
if (err)
console.log(`Error al guardar sesion :c\n${err}`)
});
resolve(`{ "nombre": "${nombreUsuario}", "email": "${emailUsuario}", "img": "${imagenUsuario}",
"carrito": {}, "rol": "user", "USER_ID": "${res}"}`);
})
.catch((msg:string) => {
reject("Error al crear el usuario...\n" + msg);
})
} else {
/* Almacenar la sesion :c */
sesion.nombre = nombreUsuario;
sesion.email = emailUsuario;
sesion.img = imagenUsuario;
sesion.USER_ID = response[0]["USER_ID"];
sesion.ROL = response[0]["ROL"];
sesion.carritoActual = response[0]["carritoActual"];
sesion.save((err:any) => {
if (err)
console.log(`Error :c\n${err}`)
});
console.log(`Respuesta servidor:\n${respuestaBD}`);
resolve(JSON.stringify(response[0]));
}
});
});
});
};
const revisarUsuario = (req:any, res:any) => {
res.header('Access-Control-Allow-Origin', 'http://localhost:8081');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
const token:string = req.body.idtoken;
validator(token)
.then( (usuario:object) => {
revisarUsuarioG(usuario, req.session)
.then(response => res.send(response.toString()))
.catch(err => res.send(err))
})
.catch(console.error);
};
module.exports.revisarUsuarioG = revisarUsuario;

View File

@ -0,0 +1,35 @@
function revisarSesion(req:any, res:any) {
res.header('Access-Control-Allow-Origin', 'http://localhost:8081');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
const sesion = req.session;
const USER_ID = sesion.USER_ID;
if (USER_ID) {
console.log("Recorde el usuario :3");
const nombre = sesion.nombre;
const email = sesion.email;
const img = sesion.img;
const carritoActual = sesion.carritoActual;
const ROL = sesion.ROL;
const data = {
nombre,
email,
img,
carritoActual: JSON.parse(carritoActual),
ROL,
USER_ID,
logged: true
};
res.send(JSON.stringify(data));
} else {
console.log("Hmmph, no hay nadie logeado....");
res.send(`{ "logged": false }`);
}
}
module.exports.revisarSesion = revisarSesion;

41
Backend/usuarios.ts Normal file
View File

@ -0,0 +1,41 @@
/* Metodo que obtiene los usuarios que existen. */
const obtenerUsuarios = () => {
return new Promise((resolve, reject) => {
const con = require('mysql').createConnection({
host: '35.193.16.64',
user: 'Araozu',
password: 'xsakah4b',
database: 'Usuarios_DB'
});
con.connect( (err:any) => {
if (err) {
console.log("Error en usuarios.ts 13.\n" + err);
reject("Error :c");
}
con.query(
`SELECT USER_ID, GOOGLE_ID, nombre, ROL FROM usuarios WHERE ROL='user'`,
(err:any, response:any) => {
if (err) {
console.log("Error en usuarios.ts 21.\n" + err);
reject("Error :c");
}
resolve(response);
}
);
});
});
};
const procesar = (req:any, res:any) => {
res.header('Access-Control-Allow-Origin', 'http://localhost:8081');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
obtenerUsuarios()
.then((resultado:object) => res.send(JSON.stringify(resultado)))
.catch(reason => res.send(reason));
};
module.exports.usuarios = procesar;

26
README.md Normal file
View File

@ -0,0 +1,26 @@
# ihc-router
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Run your tests
```
npm run test
```
### Lints and fixes files
```
npm run lint
```

28
app.ts Normal file
View File

@ -0,0 +1,28 @@
require('@google-cloud/debug-agent').start();
const expressr = require('express');
const apuri = expressr();
const session = require('express-session');
apuri.use(expressr.json());
apuri.use(expressr.urlencoded());
apuri.use(expressr.static('dist'));
apuri.use(session({
secret: 'azopotamadre we v:',
resave: false,
saveUninitialized: false
}));
/* PUERTO NECESARIO PARA DEPLOYAR EN GOOGLE CLOUD!!! */
const puerto = 8080;
apuri.post('/log-inG', require('./Backend/revisarUsuarioG.js').revisarUsuarioG);
apuri.post('/usuarios', require('./Backend/usuarios.js').usuarios);
apuri.post('/registro', require('./Backend/registrarUsuario.js').registrar);
apuri.post('/sesion', require('./Backend/usuarioLogueado').revisarSesion);
apuri.post('/pedidos/actual', require('./Backend/Pedidos/obtenerPedidosActuales').obtenerPedido);
apuri.get('/');
apuri.listen(puerto, () => console.log(`Estoy escuchando el puerto ${puerto} we v:`));

6
app.yaml Normal file
View File

@ -0,0 +1,6 @@
runtime: nodejs8
instance_class: F2
env_variables:
BUCKET_NAME: "example-gcs-bucket"

5
babel.config.js Normal file
View File

@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/app'
]
};

1
dist/css/base.css vendored

File diff suppressed because one or more lines are too long

10947
dist/dependencias/vue.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

1
dist/js/app.js vendored

File diff suppressed because one or more lines are too long

1
dist/js/base.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
const topBar=document.createElement("div");topBar.style.position="fixed",topBar.style.minHeight="3px",topBar.style.backgroundColor="red",topBar.style.zIndex="1";const transitionD=500;topBar.style.transition="min-width 500ms, opacity 250ms",topBar.style.minWidth="0";let promesaActual,widthDestino=0;document.body.appendChild(topBar);const cambiarProgreso=t=>(widthDestino=t,promesaActual=new Promise((o,i)=>{topBar.style.minWidth=`${t}%`,setTimeout(()=>o(),500)})),cancelarTransicion=()=>{const t=topBar.style.transition;topBar.style.transition="",topBar.style.minWidth=`${widthDestino}%`,topBar.style.transition=t},ocultarTopBar=()=>{topBar.style.opacity="0",setTimeout(()=>{topBar.style.minWidth="0%"},250)},reiniciarTopBar=()=>{const t=topBar.style.transition;topBar.style.transition="",topBar.style.minWidth="0",topBar.style.opacity="1",topBar.style.transition=t};

129
index.php
View File

@ -1,129 +0,0 @@
<!DOCTYPE HTML>
<html lang="es">
<head>
<title>Cocina Francesa</title>
<link rel="stylesheet" href="/ihc/dist/css/base.css?v=2" type="text/css"/>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<script src="/ihc/dist/js/topbar.min.js"></script>
<div id="vueApp">
<router-view></router-view>
</div>
<!-- Vue y Vuerouter -->
<!--<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>-->
<script src="/ihc/dist/dependencias/vuerouter.min.js"></script>
<script src="/ihc/dist/dependencias/vue.js"></script>
<script>
Vue.use(VueRouter);
const carritoUsuario = [];
const footer = {
template: `<?php include "./src/componentes/mi-footer.vue" ?>`
};
const navBar = {
template: `<?php include "./src/componentes/navBar.vue" ?>`
};
const headerMin = {
template: `<?php include "./src/componentes/headerMin.vue" ?>`
};
const inicio = {
template: `<?php include "./src/componentes/inicio.vue" ?>`,
components: {
'mi-footer': footer,
'header-min': headerMin,
'nav-bar': navBar
}
};
const carrito = {
template: `<?php include "./src/componentes/carrito.vue"?>`,
components: {
'mi-footer': footer,
'header-min': headerMin,
'nav-bar': navBar
},
data: function () {
return {
item: carritoUsuario,
descuento: 0
};
},
computed: {
cantidadItems: function () {
let items = 0;
for (const i in this.item)
items++;
return items;
},
subTotal: function () {
let subT = 0;
for (const itemI in this.item ) {
if (this.item.hasOwnProperty(itemI)){
const item = this.item[itemI];
subT += (item["precio"] * item["cantidad"]);
}
}
return subT;
},
total: function () {
return this.subTotal - this.descuento;
},
noEstaVacio: function () {
for (const i in this.item) {
return true;
}
return false;
},
},
methods: {
restarCantidad: function (elem) {
const cantidad = parseInt(elem.cantidad);
if (cantidad > 0)
elem.cantidad = cantidad -1;
},
aumentarCantidad: function (elem) {
const cantidad = parseInt(elem.cantidad);
if (cantidad >= 0)
elem.cantidad = cantidad+1;
}
}
};
const routes = [
{path: '/ihc/',component: inicio},
{path: '/ihc/carrito/', component: carrito}
];
const router = new VueRouter({
mode: 'history',
routes: routes
});
const vm = new Vue({
el: '#vueApp',
router: router
})
.$mount('#vueApp');
</script>
<!-- Logica principal -->
<!--<script src="./dist/js/base.min.js?v=2"></script>-->
</body>
</html>

View File

@ -1,67 +0,0 @@
<div class="contenedor inicio_registro">
<div class="center">
Inicia Sesión.
</div>
<br />
<br />
<br />
<div class="row">
<div class="col-7 center">
<br>
<br>
<br>
<br>
<br>
<br>
<img src="https://www.sbs.com.au/food/sites/sbs.com.au.food/files/styles/full/public/nicoise-salad.jpg?itok=MK0Y7QKN&mtime=1499834368"
alt="plato de comida" class="image">
</div>
<div class="col-5 center">
<br />
<br />
<button type="button" class="google-button" style="width: 213px">
<span class="google-button__icon">
<svg viewBox="0 0 366 372" xmlns="http://www.w3.org/2000/svg">
<path d="M125.9 10.2c40.2-13.9 85.3-13.6 125.3 1.1 22.2 8.2 42.5 21 59.9 37.1-5.8 6.3-12.1 12.2-18.1 18.3l-34.2 34.2c-11.3-10.8-25.1-19-40.1-23.6-17.6-5.3-36.6-6.1-54.6-2.2-21 4.5-40.5 15.5-55.6 30.9-12.2 12.3-21.4 27.5-27 43.9-20.3-15.8-40.6-31.5-61-47.3 21.5-43 60.1-76.9 105.4-92.4z" id="Shape" fill="#EA4335"/><path d="M20.6 102.4c20.3 15.8 40.6 31.5 61 47.3-8 23.3-8 49.2 0 72.4-20.3 15.8-40.6 31.6-60.9 47.3C1.9 232.7-3.8 189.6 4.4 149.2c3.3-16.2 8.7-32 16.2-46.8z" id="Shape" fill="#FBBC05"/><path d="M361.7 151.1c5.8 32.7 4.5 66.8-4.7 98.8-8.5 29.3-24.6 56.5-47.1 77.2l-59.1-45.9c19.5-13.1 33.3-34.3 37.2-57.5H186.6c.1-24.2.1-48.4.1-72.6h175z" id="Shape" fill="#4285F4"/><path d="M81.4 222.2c7.8 22.9 22.8 43.2 42.6 57.1 12.4 8.7 26.6 14.9 41.4 17.9 14.6 3 29.7 2.6 44.4.1 14.6-2.6 28.7-7.9 41-16.2l59.1 45.9c-21.3 19.7-48 33.1-76.2 39.6-31.2 7.1-64.2 7.3-95.2-1-24.6-6.5-47.7-18.2-67.6-34.1-20.9-16.6-38.3-38-50.4-62 20.3-15.7 40.6-31.5 60.9-47.3z" fill="#34A853"/>
</svg>
</span>
<span class="google-button__text">Iniciar con Google</span>
</button>
<br />
<br />
<button style="background-color: #4064ad; height: 40px; border: none; box-shadow: 1px 1px 2px black;
border-radius: 3px">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"
id="Capa_1" x="0px" y="0px" width="20px" viewBox="0 0 96.124 96.123"
style="max-height: 18px" xml:space="preserve">
<g>
<path d="M72.089,0.02L59.624,0C45.62,0,36.57,9.285,36.57,23.656v10.907H24.037c-1.083,0-1.96,0.878-1.96,1.961v15.803 c0,1.083,0.878,1.96,1.96,1.96h12.533v39.876c0,1.083,0.877,1.96,1.96,1.96h16.352c1.083,0,1.96-0.878,1.96-1.96V54.287h14.654 c1.083,0,1.96-0.877,1.96-1.96l0.006-15.803c0-0.52-0.207-1.018-0.574-1.386c-0.367-0.368-0.867-0.575-1.387-0.575H56.842v-9.246 c0-4.444,1.059-6.7,6.848-6.7l8.397-0.003c1.082,0,1.959-0.878,1.959-1.96V1.98C74.046,0.899,73.17,0.022,72.089,0.02z" style="fill: rgb(255, 255, 255);"></path>
</g>
</svg>
<span class="google-button__text" style="color: white; padding: 0 13px">Iniciar con Facebook</span>
</button>
<br />
<br />
O inicia sesión con tu correo:<br />
<br />
<br />
<form method="post" onsubmit="return false">
Correo Electrónico:<br />
<input type="text" placeholder="Tu correo Electrónico"><br />
<br />
Contraseña:<br />
<input type="password" placeholder="Contraseña"><br />
<br />
<input class="botonEnviarForm" type="submit" value="Iniciar Sesión">
</form>
<br />
<br />
¿No tienes una cuenta?<br />
<a href="./#registro" id="botonRegistro" class="boton">
Regístrate
</a>
</div>
</div>
<br />
<br />
</div>

12864
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +1,39 @@
{
"name": "ihc",
"version": "1.0.0",
"description": "A simple meb application for a 'French Restaurant'",
"main": "index.php",
"name": "ihc-router",
"version": "0.1.0",
"private": true,
"scripts": {
"uglify": "uglifyjs src/js/*.js -m -c -o dist/js/app.js",
"sass": "sass -s compressed src/sass:dist/css"
"serve": "vue-cli-service serve --port 8081",
"build": "vue-cli-service build",
"start": "node app.js"
},
"repository": {
"type": "git",
"url": "git+https://gitlab.com/Araozu/ihc-proyect.git"
"dependencies": {
"@google-cloud/debug-agent": "^3.0.0",
"@types/express": "^4.16.0",
"@types/mysql": "^2.15.5",
"@types/node": "^10.12.1",
"express": "^4.16.3",
"express-session": "^1.15.6",
"google-auth-library": "^2.0.0",
"mysql": "^2.16.0",
"vue": "^2.5.17",
"vue-router": "^3.0.1"
},
"keywords": [
"ihc",
"unsa",
"2018"
],
"author": "Fernando Araoz Morales",
"license": "MIT",
"bugs": {
"url": "https://gitlab.com/Araozu/ihc-proyect/issues"
"devDependencies": {
"@vue/cli-plugin-babel": "^3.0.5",
"@vue/cli-service": "^3.0.5",
"node-sass": "^4.9.0",
"sass-loader": "^7.0.1",
"vue-template-compiler": "^2.5.17"
},
"homepage": "https://gitlab.com/Araozu/ihc-proyect#readme"
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
public/img/usuario.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

21
public/index.html Normal file
View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<script src="https://apis.google.com/js/platform.js" async defer></script>
<meta name="google-signin-client_id" content="443321715214-9joe4c9l00osc6qcc4l0i2k3420jvb7q.apps.googleusercontent.com">
<title>L'Assiete</title>
</head>
<body>
<noscript>
<strong>Ups. La página de L'Assiete no se puede mostrar si tienes el JavaScript desactivado :c <br>
Actívalo y recarga la página.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

View File

@ -1,69 +0,0 @@
<div class="contenedor inicio_registro">
<div class="center">
Registrate para tener lo mejor de la cocina francesa en la comodida de tu casa.<br />
</div>
<br />
<br />
<div class="row">
<div class="col-7 center">
<br />
<button type="button" class="google-button" style="width: 213px">
<span class="google-button__icon">
<svg viewBox="0 0 366 372" xmlns="http://www.w3.org/2000/svg">
<path d="M125.9 10.2c40.2-13.9 85.3-13.6 125.3 1.1 22.2 8.2 42.5 21 59.9 37.1-5.8 6.3-12.1 12.2-18.1 18.3l-34.2 34.2c-11.3-10.8-25.1-19-40.1-23.6-17.6-5.3-36.6-6.1-54.6-2.2-21 4.5-40.5 15.5-55.6 30.9-12.2 12.3-21.4 27.5-27 43.9-20.3-15.8-40.6-31.5-61-47.3 21.5-43 60.1-76.9 105.4-92.4z" id="Shape" fill="#EA4335"/><path d="M20.6 102.4c20.3 15.8 40.6 31.5 61 47.3-8 23.3-8 49.2 0 72.4-20.3 15.8-40.6 31.6-60.9 47.3C1.9 232.7-3.8 189.6 4.4 149.2c3.3-16.2 8.7-32 16.2-46.8z" id="Shape" fill="#FBBC05"/><path d="M361.7 151.1c5.8 32.7 4.5 66.8-4.7 98.8-8.5 29.3-24.6 56.5-47.1 77.2l-59.1-45.9c19.5-13.1 33.3-34.3 37.2-57.5H186.6c.1-24.2.1-48.4.1-72.6h175z" id="Shape" fill="#4285F4"/><path d="M81.4 222.2c7.8 22.9 22.8 43.2 42.6 57.1 12.4 8.7 26.6 14.9 41.4 17.9 14.6 3 29.7 2.6 44.4.1 14.6-2.6 28.7-7.9 41-16.2l59.1 45.9c-21.3 19.7-48 33.1-76.2 39.6-31.2 7.1-64.2 7.3-95.2-1-24.6-6.5-47.7-18.2-67.6-34.1-20.9-16.6-38.3-38-50.4-62 20.3-15.7 40.6-31.5 60.9-47.3z" fill="#34A853"/>
</svg>
</span>
<span class="google-button__text">Regístrate con Google</span>
</button>
<br />
<br />
<button style="background-color: #4064ad; height: 40px; border: none; box-shadow: 1px 1px 2px black;
border-radius: 3px">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"
id="Capa_1" x="0px" y="0px" width="20px" viewBox="0 0 96.124 96.123"
style="max-height: 18px" xml:space="preserve">
<g>
<path d="M72.089,0.02L59.624,0C45.62,0,36.57,9.285,36.57,23.656v10.907H24.037c-1.083,0-1.96,0.878-1.96,1.961v15.803 c0,1.083,0.878,1.96,1.96,1.96h12.533v39.876c0,1.083,0.877,1.96,1.96,1.96h16.352c1.083,0,1.96-0.878,1.96-1.96V54.287h14.654 c1.083,0,1.96-0.877,1.96-1.96l0.006-15.803c0-0.52-0.207-1.018-0.574-1.386c-0.367-0.368-0.867-0.575-1.387-0.575H56.842v-9.246 c0-4.444,1.059-6.7,6.848-6.7l8.397-0.003c1.082,0,1.959-0.878,1.959-1.96V1.98C74.046,0.899,73.17,0.022,72.089,0.02z" style="fill: rgb(255, 255, 255);"></path>
</g>
</svg>
<span class="google-button__text" style="color: white; padding: 0 13px">Regístrate con Facebook</span>
</button>
<br />
<br />
<br />
O crea tu cuenta con tu correo electrónico:
<br />
<br />
<br />
<form method="post" onsubmit="return false">
Nombre:<br />
<input placeholder="Tu nombre" name="userName"><br />
<br />
Correo Electrónico:<br />
<input placeholder="Tu correo Electrónico" name="userEmail"><br />
<br />
Contraseña<br />
<input type="password" placeholder="Contraseña" name="userPass"><br />
<br />
<input class="botonEnviarForm" type="submit" value="¡Crear mi cuenta!">
</form>
<br />
<br />
¿Ya tienes una cuenta?<br />
<a href="./#iniciar-sesion" id="botonInicioSesion" class="boton">
Inicia Sesion
</a>
</div>
<div class="col-5 center">
<br>
<br>
<img class="image" alt="Torre Eiffel" src="https://kids.nationalgeographic.com/content/dam/kids/photos/Countries/A-G/france-eiffel-tower.ngsversion.1396531559251.adapt.1900.1.jpg">
<br>
<br>
<img class="image" src="https://www.slh.com/globalassets/country-pages/hero-images/france3.jpg" alt="Vista de francia">
</div>
</div>
<br />
<br />
</div>

30
src/App.vue Normal file
View File

@ -0,0 +1,30 @@
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
import conexion from './variables'
export default {
name: 'App',
// Revisa si existe una variable de sesion con el usuario
created: function () {
const xhr = new XMLHttpRequest();
xhr.open("POST",`${conexion}/sesion`);
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xhr.onload = () => {
const data = JSON.parse(xhr.responseText);
if (data["logged"]) {
window.usuarioActual.pop();
window.usuarioActual.push(data);
}
};
xhr.send();
}
}
</script>
<style>
</style>

BIN
src/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -1,94 +0,0 @@
<div>
<header-min></header-min>
<nav-bar></nav-bar>
<section id="sectionCarrito" class="contenedor mySeccion" data-collapsed="false">
<br/>
<br/>
<div class="center">
<div id="carrito--tituloprincipal">
Carrito de compras
</div>
<br/>
<a id="carrito--boton--seguircomprando" href="./#usuarios/">Seguir comprando</a>
<br/>
<br/>
<div id="carrito" class="row carrito">
<div id="carrito--elementos" class="col-8">
<div id="carrito--elementos--contenido" class="caja">
<template v-if="noEstaVacio">
<template v-for="producto in item">
<div class="carritoElem">
<img class="carritoElem--img" v-bind:src="producto.imgUrl">
<div class="plato--Titulo">{{ producto.nombre }}</div>
<br>
<div class="plato--Precio">{{ producto.precio }}</div>
<div class="plato--Cantidad">Cantidad:
<i class="material-icons plato--Cantidad--Icon" v-on:click="restarCantidad(producto)">remove</i>
<span>{{ producto.cantidad }}</span>
<i class="material-icons plato--Cantidad--Icon" v-on:click="aumentarCantidad(producto)">add</i>
</div>
<br>
<div class="carrito--subTotal">{{ producto.precio * producto.cantidad }}</div>
<hr>
</div>
</template>
</template>
<template v-else>
No hay nada en tu carrito de compras :c
</template>
</div>
</div>
<div id="carrito--precio" class="col-4">
<div id="carrito--precio--contenido" class="caja">
<template v-if="noEstaVacio">
<div id="pagos">
<div style="display: inline-block;">
{{ cantidadItems }} Producto{{ (cantidadItems>1 || cantidadItems === 0) ? 's': '' }}
</div>
<div style="display: inline-block; float: right; clear: both">
{{ subTotal }} S/.
</div>
</div>
<div>
<div style="display: inline-block;">
Descuentos:
</div>
<div style="display: inline-block; float: right; clear: both">
{{ descuento }} S/.
</div>
</div>
<br>
<br>
<div>
<div class="carrito--precio--contenido--titulo" style="display: inline-block;">
Total:
</div>
<div class="carrito--precio--contenido--titulo"
style="display: inline-block; float: right; clear: both">
{{ total }} S/.
</div>
</div>
<br>
<br>
<a class="carrito--precio--contenido--botonPagar">
Completar Transaccion
</a>
</template>
<template v-else>
No hay nada en tu carrito de compras :c
</template>
</div>
</div>
</div>
</div>
<br/>
<br/>
</section>
<mi-footer></mi-footer>
</div>

View File

@ -1,10 +0,0 @@
<header id="header">
<div class="contenedor">
<div id="tituloP" class="center">
<a href="./#" style="color: white; text-decoration: none">Le goût</a>
<div id="tituloP--descripcion">
Descubre un nuevo sabor
</div>
</div>
</div>
</header>

View File

@ -1,23 +0,0 @@
<header id="header">
<div class="contenedor">
<div id="tituloP" class="center">
<a href="./#" style="color: white; text-decoration: none">L'Assiette</a>
<div id="tituloP--descripcion">
Descubre un nuevo sabor
</div>
</div>
</div>
<div id="contenedorInicio-Registro" class="center mySeccion" data-collapsed="false">
<a href="./#registro" id="botonRegistro" class="boton">
Registrarse
</a>
<a href="./#iniciar-sesion" id="botonInicioSesion" class="boton">
Iniciar Sesion
</a>
<br/>
<br/>
<br/>
</div>
<div id="inicio_registro" class="mySeccion" data-collapsed="true" style="height: 0"></div>
</header>

View File

@ -1,44 +0,0 @@
<div>
<header-min></header-min>
<nav-bar></nav-bar>
<section id="sectionP" class="contenedor mySeccion" data-collapsed="false">
<div class="row contenido">
<div class="col-5">
<img class="image" src="http://www.saintjacquesfrenchcuisine.com/images/MenuSlide5.jpg"
alt="Plato Francés"/>
</div>
<div class="col-7">
<div class="descripcionComida">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia
deserunt mollit anim id est laborum.
</div>
</div>
</div>
<br/>
<div class="row">
<div class="col-7 center">
<div class="descripcionComida">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua. Congue quisque egestas diam in arcu cursus euismod quis. Mi tempus imperdiet nulla
malesuada pellentesque elit eget gravida. Tempus imperdiet nulla malesuada pellentesque elit eget
gravida
cum. Commodo elit at imperdiet dui accumsan sit amet. In nulla posuere sollicitudin aliquam ultrices
sagittis.
</div>
</div>
<div class="col-5">
<img src="https://upload.wikimedia.org/wikipedia/commons/6/6a/Jacques_Lameloise%2C_escab%C3%A8che_d%27%C3%A9crevisses_sur_gaspacho_d%27asperge_et_cresson.jpg"
alt="Plato Francés" class="image">
</div>
</div>
<br/>
</section>
<mi-footer></mi-footer>
</div>

View File

@ -1,11 +0,0 @@
<div>
<footer id="footer">
<div class="contenedor">
Cocina Francesa.<br/>
Una Single Page Application para el curso de IHC, UNSA, 2018.<br/>
Se utilizaron: Vue.js, BEM, Sass, npm, y PHP.<br>
<br/>
Desarrollado por Fernando Araoz, 20173373.
</div>
</footer>
</div>

View File

@ -1,10 +0,0 @@
<div>
<nav id="navBar" class="mySeccion" data-collapsed="true">
<ul class="linksNavBar">
<li><router-link to="/ihc/">Inicio</router-link></li>
<li><router-link to="/ihc/usuarios/">Comprar</router-link></li>
<li><router-link to="/ihc/usuarios/mi-cuenta">Mi cuenta</router-link></li>
<li><router-link to="/ihc/carrito/">Carrito</router-link></li>
</ul>
</nav>
</div>

View File

@ -0,0 +1,15 @@
<template>
<div>
Mirame we, soy un empleado :3
</div>
</template>
<script>
export default {
name: "Empleados"
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,53 @@
<template>
<div class="usuarios">
<div class="usuarios--titulos">
Usuarios <br>
</div>
<usuario v-for="user in usuarios" :key="user['USER_ID']"
:nombre="user['nombre']"
:rol="user['ROL']"
:googleId="user['GOOGLE_ID']"
:userId="user['USER_ID']"
/>
</div>
</template>
<script>
// const conexion = require('../../variables').conexion;
import conexion from '../../variables';
export default {
name: "Usuarios",
components: {
'usuario': () => import('./Usuarios/Usuario')
},
data: function () {
return {
usuarios: []
}
},
created: function () {
let vm = this;
let xhr = new XMLHttpRequest();
xhr.onload = () => {
console.log("Ya cargué we v':\n" + xhr.responseText);
vm.usuarios = JSON.parse(xhr.responseText);
};
xhr.open("POST",`${conexion}/usuarios`);
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send();
}
}
</script>
<style scoped lang="sass">
.usuarios
margin: 20px 0
.usuarios--titulos
text-align: center
font:
size: x-large
</style>

View File

@ -0,0 +1,27 @@
<template>
<div class="usuario hoverable">
Nombre: {{ nombre }}<br>
rol: {{ rol }}<br>
ID de Google: {{ googleId }}<br>
ID de usuario: {{ (99999999999 - userId).toString(16).toUpperCase() }} ({{ userId }})
</div>
</template>
<script>
export default {
name: "Usuario",
props: {
nombre: String,
rol: String,
googleId: String,
userId: Number
}
}
</script>
<style scoped lang="sass">
.usuario
margin: 10px
padding: 10px
border-radius: 3px
</style>

62
src/components/Inicio.vue Normal file
View File

@ -0,0 +1,62 @@
<template>
<div>
<header-min></header-min>
<nav-bar></nav-bar>
<section id="sectionP" class="contenedor mySeccion" data-collapsed="false">
<div class="row contenido">
<div class="col-5">
<img class="image" src="http://www.saintjacquesfrenchcuisine.com/images/MenuSlide5.jpg"
alt="Plato Francés"/>
</div>
<div class="col-7">
<div class="descripcionComida">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia
deserunt mollit anim id est laborum.
</div>
</div>
</div>
<br/>
<div class="row">
<div class="col-7 center">
<div class="descripcionComida">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua. Congue quisque egestas diam in arcu cursus euismod quis. Mi tempus imperdiet nulla
malesuada pellentesque elit eget gravida. Tempus imperdiet nulla malesuada pellentesque elit eget
gravida
cum. Commodo elit at imperdiet dui accumsan sit amet. In nulla posuere sollicitudin aliquam ultrices
sagittis.
</div>
</div>
<div class="col-5">
<img src="https://upload.wikimedia.org/wikipedia/commons/6/6a/Jacques_Lameloise%2C_escab%C3%A8che_d%27%C3%A9crevisses_sur_gaspacho_d%27asperge_et_cresson.jpg"
alt="Plato Francés" class="image">
</div>
</div>
<br/>
</section>
<mi-footer></mi-footer>
</div>
</template>
<script>
import HeaderMin from './headerMin'
import NavBar from './navBar'
import MiFooter from './mi-footer'
export default {
name: 'Inicio',
components: {
'header-min': HeaderMin,
'nav-bar': NavBar,
'mi-footer': MiFooter
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,33 @@
<template>
<a v-on:click.prevent="cerrarSesion" title="Cerrar Sesion">Cerrar Sesion</a>
</template>
<script>
export default {
name: "botonCerrarSesion",
methods: {
cerrarSesion: function () {
const scriptGAPI = document.getElementById("googleGAPI");
try {
gapi.auth2.getAuthInstance().signOut()
.then(() =>
console.log('User signed out.')
);
} catch (e) {
let scr = document.createElement("script");
scr.src = "https://apis.google.com/js/platform.js";
scr.onload = renderButton;
scr.defer = true;
document.head.appendChild(scr);
this.cerrarSesion();
}
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,57 @@
<template>
<header>
<div>
<div id="tituloP" class="center">
<router-link to="/"><h1 class="titulo--link">L'Assiette</h1></router-link>
<div id="tituloP--descripcion">
Descubre un nuevo sabor
</div>
</div>
</div>
<div v-if="musuarioNoLogeado" id="contenedorInicio-Registro" class="center mySeccion" data-collapsed="false">
<router-link to="/iniciar-sesion/" id="botonRegistro" class="boton">
Registrarse
</router-link>
<router-link to="/iniciar-sesion/" id="botonInicioSesion" class="boton">
Iniciar Sesion
</router-link>
<br/>
<br/>
<br/>
</div>
<div v-else class="inicio--usuario-registrado">
Bienvenido, {{ nombreDeUsuario }}<br/>
<router-link v-if="esAdmin" to="/a/" class="inicio--usuario-registrado--link">Ir a la zona administrativa.</router-link>
<br>
<br>
</div>
</header>
</template>
<script>
export default {
name: 'HeaderMin',
data: function () {
return {
usuario: window.usuarioActual
}
},
computed: {
musuarioNoLogeado: function () {
return !this.usuario[0].logged;
},
nombreDeUsuario: function () {
return this.usuario[0].nombre;
},
esAdmin: function () {
return this.usuario[0].ROL === "admin"
}
}
}
</script>
<style scoped lang="sass">
.inicio--usuario-registrado--link
color: white
text-decoration: underline
</style>

View File

@ -0,0 +1,18 @@
<template>
<header id="header">
<div>
<div id="tituloP" class="center tituloP--mini">
<router-link to="/" class="titulo--link">L'Assiette</router-link>
</div>
</div>
</header>
</template>
<script>
export default {
name: 'HeaderMini'
}
</script>
<style>
</style>

View File

@ -0,0 +1,29 @@
<template>
<footer id="footer">
<div class="container row mi-footer transparent">
<div class="col l6 m6">
Cocina Francesa.<br/>
Una Single Page Application para el curso de IHC, UNSA, 2018.<br/>
Con lo último en tecnología: Vue.js, BEM, Sass, TypeScript, y nodejs.<br>
<br/>
Desarrollado por Fernando Araoz, 20173373.
</div>
<div class="col l6 m6">
<div class="hide-on-med-and-up"><hr></div>
Contacto: <br>
<br>
<i class="material-icons white-text">local_phone</i>&nbsp;&nbsp;&nbsp;999 - 888 - 777 <br>
<i class="material-icons white-text">email</i>&nbsp;&nbsp;&nbsp;soporte@l-assiete.com
</div>
</div>
</footer>
</template>
<script>
export default {
name: 'MiFooter'
}
</script>
<style>
</style>

32
src/components/navBar.vue Normal file
View File

@ -0,0 +1,32 @@
<template>
<nav id="navBar" class="mySeccion">
<ul class="linksNavBar">
<li><router-link to="/">Inicio</router-link></li>
<li><router-link to="/platos/">Platos</router-link></li>
<li>|</li>
<li><router-link to="/mi-cuenta/">Mi cuenta</router-link></li>
<li><router-link to="/carrito/">Mi carrito</router-link></li>
<li><router-link to="/mi-pedido/">Mis pedidos</router-link></li>
<li class="right" v-if="usuarioLogeado"><boton-cerrar-sesion /></li>
</ul>
</nav>
</template>
<script>
import BotonCerrarSesion from './botonCerrarSesion'
export default {
name: 'HeaderMini',
components: {
'boton-cerrar-sesion': BotonCerrarSesion
},
computed: {
usuarioLogeado: function () {
return window.usuarioActual[0]["logged"];
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,26 @@
<template>
<nav v-if="usuarioNoLogeado" class="mi-nav-bar">
<ul class="linksNavBar">
<li><router-link to="/iniciar-sesion/">Inicia Sesion</router-link></li>
<li><router-link to="/iniciar-sesion/">Regístrate</router-link></li>
</ul>
</nav>
</template>
<script>
export default {
name: "navBarInicioSesion",
computed: {
usuarioNoLogeado: function () {
return !window.usuarioActual[0].logged;
}
}
}
</script>
<style scoped lang="sass">
.mi-nav-bar ul li
background-color: #3d3d7b
height: auto
</style>

16
src/components/pedido.vue Normal file
View File

@ -0,0 +1,16 @@
<template>
<div class="pedido">
Este es un pedido we v:
</div>
</template>
<script>
export default {
name: "pedido"
}
</script>
<style scoped lang="sass">
.pedido
padding: 20px
</style>

View File

@ -1,137 +0,0 @@
const carritoUsuario = [];
/* Height Transition by CSS Tricks. Returns a Promise */
const collapseSection = element => {
return new Promise((resolve, reject) => {
// get the height of the element's inner content, regardless of its actual size
let sectionHeight = element.scrollHeight;
// temporarily disable all css transitions
let elementTransition = element.style.transition;
element.style.transition = '';
// on the next frame (as soon as the previous style change has taken effect),
// explicitly set the element's height to its current pixel height, so we
// aren't transitioning out of 'auto'
requestAnimationFrame(function () {
element.style.height = sectionHeight + 'px';
element.style.transition = elementTransition;
// on the next frame (as soon as the previous style change has taken effect),
// have the element transition to height: 0
requestAnimationFrame(function () {
element.style.height = 0 + 'px';
setTimeout(() => {
resolve("Termine de ocultar we v':");
}, 160);
});
});
// mark the section as "currently collapsed"
element.setAttribute('data-collapsed', 'true');
});
};
const expandSection = element => {
return new Promise((resolve, reject) => {
// get the height of the element's inner content, regardless of its actual size
let sectionHeight = element.scrollHeight;
// have the element transition to the height of its inner content
element.style.height = sectionHeight + 'px';
// when the next css transition finishes (which should be the one we just triggered)
element.addEventListener('transitionend', function (e) {
// remove this event listener so it only gets triggered once
element.removeEventListener('transitionend', arguments.callee);
// remove "height" from the element's inline styles, so it can return to its initial value
element.style.height = null;
setTimeout(() => {
resolve("Termine de ampliar we v':");
}, 0);
});
// mark the section as "currently not collapsed"
element.setAttribute('data-collapsed', 'false');
});
};
const abrirElemF = (element, midF, postF) => {
if (element.getAttribute("data-collapsed") === "true") {
if (midF !== undefined)
midF();
expandSection(element).then(() => {
if (postF !== undefined)
postF();
});
} else {
collapseSection(element).then(() => {
if (midF !== undefined)
midF();
expandSection(element).then(() => {
if (postF !== undefined)
postF();
});
});
}
};
const cerrarElemF = (element, postF) => {
if (element.getAttribute("data-collapsed") === "false") {
collapseSection(element).then(() => {
if (postF !== undefined)
postF();
});
}
};
const carrito = new Vue({
el: "#carrito",
data: {
item: carritoUsuario,
descuento: 0
},
computed: {
cantidadItems: function () {
let items = 0;
for (const i in this.item)
items++;
return items;
},
subTotal: function () {
let subT = 0;
for (const itemI in this.item ) {
if (this.item.hasOwnProperty(itemI)){
const item = this.item[itemI];
subT += (item["precio"] * item["cantidad"]);
}
}
return subT;
},
total: function () {
return this.subTotal - this.descuento;
},
noEstaVacio: function () {
for (const i in this.item) {
return true;
}
return false;
},
},
methods: {
restarCantidad: function (elem) {
const cantidad = parseInt(elem.cantidad);
if (cantidad > 0)
elem.cantidad = cantidad -1;
},
aumentarCantidad: function (elem) {
const cantidad = parseInt(elem.cantidad);
if (cantidad >= 0)
elem.cantidad = cantidad+1;
}
}
});

View File

@ -1,46 +0,0 @@
const topBar = document.createElement("div");
topBar.style.position = "fixed";
topBar.style.minHeight = "3px";
topBar.style.backgroundColor = "red";
topBar.style.zIndex = "1";
const transitionD = 500;
topBar.style.transition = `min-width ${transitionD}ms, opacity 250ms`;
topBar.style.minWidth = "0";
let widthDestino = 0;
document.body.appendChild(topBar);
let promesaActual;
const cambiarProgreso = progreso => {
widthDestino = progreso;
promesaActual = new Promise((resolve, reject) => {
topBar.style.minWidth = `${progreso}%`;
setTimeout(() => resolve(),transitionD);
});
return promesaActual;
};
const cancelarTransicion = () => {
const transiciones = topBar.style.transition;
topBar.style.transition = "";
topBar.style.minWidth = `${widthDestino}%`;
topBar.style.transition = transiciones;
};
const ocultarTopBar = () => {
topBar.style.opacity = "0";
setTimeout(() => {
topBar.style.minWidth = "0%";
},250);
};
const reiniciarTopBar = () => {
const transiciones = topBar.style.transition;
topBar.style.transition = "";
topBar.style.minWidth = `0`;
topBar.style.opacity = "1";
topBar.style.transition = transiciones;
};

32
src/main.js Normal file
View File

@ -0,0 +1,32 @@
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
require('@/materialize/css/materialize.min.css');
require('@/sass/base.sass');
require('@/material-icons/material-icons.css');
require('@/materialize/js/materialize.min.js');
require('./typescript/main.js');
(() => {
window.carritoUsuario = [];
window.usuarioActual = [
{
nombre: 'Usuario',
email: 'ejemplo@l-assiete.com',
historial: {},
logged: false
}
];
window.elRouter = router
})();
new Vue({
data: {
carritoUsuario: []
},
router,
render: h => h(App)
}).$mount('#app')

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,36 @@
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: url(MaterialIcons-Regular.eot); /* For IE6-8 */
src: local('Material Icons'),
local('MaterialIcons-Regular'),
url(MaterialIcons-Regular.woff2) format('woff2'),
url(MaterialIcons-Regular.woff) format('woff'),
url(MaterialIcons-Regular.ttf) format('truetype');
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px; /* Preferred icon size */
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
/* Support for all WebKit browsers. */
-webkit-font-smoothing: antialiased;
/* Support for Safari and Chrome. */
text-rendering: optimizeLegibility;
/* Support for Firefox. */
-moz-osx-font-smoothing: grayscale;
/* Support for IE. */
font-feature-settings: 'liga';
}

13
src/materialize/css/materialize.min.css vendored Normal file

File diff suppressed because one or more lines are too long

6
src/materialize/js/materialize.min.js vendored Normal file

File diff suppressed because one or more lines are too long

54
src/router.js Normal file
View File

@ -0,0 +1,54 @@
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
Vue.use(Router);
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/platos/',
name: 'Platos',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ './views/Platos.vue')
},
{
path: '/carrito/',
name: 'Carrito',
component: () => import('./views/carrito')
},
{
path: '/iniciar-sesion/',
name: 'IniciarSesion',
component: () => import('./views/Login-Registro')
},
{
path: '/mi-cuenta/',
name: 'MiCuenta',
component: () => import('./views/MiCuenta')
},
{
path: '/mi-pedido/',
name: 'MiPedido',
component: () => import('./views/MiPedido')
},
{
path: '/a/',
name: 'Administracion',
component: () => import('./views/Administracion/Inicio'),
children: [
{ path: 'usuarios', component: () => import('./components/Admin/Usuarios') },
{ path: 'empleados', component: () => import('./components/Admin/Empleados') }
]
}
]
})

View File

@ -3,13 +3,18 @@
$fuenteTitulos: 'Muli'
$fuentePrincipal: 'Open Sans'
$colorPrincipalOscuro: #3d3d7c
*
box-sizing: border-box
html, body
margin: 0
padding: 0
font-family: $fuentePrincipal, sans-serif
background-color: #F5F5F5
font:
family: $fuentePrincipal, sans-serif
size: large
header
background-color: #44A
@ -30,57 +35,13 @@ footer
box-shadow: inset 0 5px 5px #999999
padding: 40px
.contenedor
max-width: 1200px
width: 80%
margin: auto
.container
margin-top: 10px
margin-bottom: 10px
padding: 10px
.col-1
width: 8.33%
.col-2
width: 16.66%
.col-3
width: 25%
.col-4
width: 33.33%
.col-5
width: 41.66%
.col-6
width: 50%
.col-7
width: 58.33%
.col-8
width: 66.66%
.col-9
width: 75%
.col-10
width: 83.33%
.col-11
width: 91.66%
.col-12
width: 100%
[class*="col-"]
float: left
.row::after
content: ""
clear: both
display: table
.center
text-align: center
.fondoBlanco
background-color: white
#tituloP
padding: 30px
@ -95,6 +56,17 @@ footer
size: large
family: $fuentePrincipal
.tituloP--mini
padding: 10px !important
font:
size: 40px !important
.titulo--link
color: white
text-decoration: none
font-size: 50px
margin: 0
.center
text-align: center
@ -124,6 +96,7 @@ footer
#botonInicioSesion
background-color: white
font-size: large
transition: transform 200ms, box-shadow 200ms
#botonInicioSesion:hover
@ -250,10 +223,11 @@ input
list-style: none
float: left
transition: background-color 250ms
line-height: 50px
a
cursor: pointer
display: inline-block
padding: 15px
padding: 0 15px
color: white
text-decoration: none
&:after
@ -363,4 +337,78 @@ input
weight: 900
margin: 10px 0
.responsive-image
padding: 0 20px
width: 100%
height: auto
.tienda--titulo
text-align: center
font:
family: $fuenteTitulos, sans-serif
size: xx-large
weight: 900
margin: 10px 0
.tienda--tarjeta
padding: 10px
margin: 20px 5px
border-radius: 3px
.tienda--tarjeta--titulo
font:
size: x-large
family: $fuenteTitulos, sans-serif
color: $colorPrincipalOscuro
.tienda--tarjeta--descripcion
.tienda--tarjeta--precio
&:before
content: "Precio unitario: "
color: green
&:after
content: " S/."
.tienda--tarjeta--cantidad
&:before
content: "Cantidad "
.tienda--tarjeta--botonComprar
background-color: white
color: $colorPrincipalOscuro
padding: 10px
cursor: pointer
border-radius: 3px
transition: color 100ms, background-color 100ms
font:
size: large
weight: bold
family: $fuenteTitulos
&:hover
background-color: $colorPrincipalOscuro
color: white
&:focus
background-color: white
color: $colorPrincipalOscuro
.img-inicio
height: 90px
margin: 0 20px
.mi-cuenta--usuario-no-logeado
text-align: center
margin: 20px 0
font:
size: x-large
.inicio--usuario-registrado
text-align: center
color: white
font-size: large
.irAlCarrito
text-decoration: underline
color: white
cursor: pointer

18
src/typescript/main.ts Normal file
View File

@ -0,0 +1,18 @@
function onSignIn(googleUser:any) {
console.log("Mirame we, estoy iniciando sesion v:");
let id_token = googleUser.getAuthResponse().id_token;
let xhr = new XMLHttpRequest();
xhr.open('POST', 'https://yourbackend.example.com/tokensignin');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onload = function() {
console.log('Signed in as: ' + xhr.responseText);
};
xhr.send('idtoken=' + id_token);
}
// @ts-ignore
window.irAlCarro = () => {
// @ts-ignore
window.elRouter.push('/carrito/');
};

8
src/variables.ts Normal file
View File

@ -0,0 +1,8 @@
const conexion_backend = "http://localhost:8080";
const conexion_gcloud = "https://lassiete-unsa.appspot.com/";
/* De este estilo porque por alguna razon a babel no le agrado module.exports en este archivo. */
export default conexion_gcloud;
// module.exports.conexion = conexion_backend;

View File

@ -0,0 +1,64 @@
<template>
<div style="background-color: #f5f5f5">
<header-mini />
<div class="container caja inicio">
<div class="inicio--titulo">
Administración de recursos
</div>
<div class="inicio--desc">
Selecciona un campo para empezar: <br>
<router-link to="/a/usuarios" class="inicio--desc--boton hoverable">Usuarios</router-link>
<router-link to="/a/empleados" class="inicio--desc--boton hoverable">Empleados</router-link>
</div>
<hr>
<router-view />
</div>
</div>
</template>
<script>
import Header from '../../components/headerMini'
import Usuarios from '../../components/Admin/Usuarios'
import Empleados from '../../components/Admin/Empleados'
export default {
name: "Inicio",
data: function () {
return {
componenteAct: 'header-mini'
}
},
components: {
'header-mini': Header,
'usuarios-comp': Usuarios,
'empleados-comp': Empleados
}
}
</script>
<style scoped lang="sass">
.inicio
background-color: white
.inicio--titulo
text-align: center
font:
family: Muli, "Open Sans", sans-serif
weight: bold
size: x-large
.inicio--desc
text-align: center
font:
family: Muli, "Open Sans", sans-serif
size: large
.inicio--desc--boton
display: inline-block
margin: 10px 20px
background-color: #4444aa
color: white
padding: 10px
border-radius: 3px
</style>

83
src/views/Home.vue Normal file
View File

@ -0,0 +1,83 @@
<template>
<div>
<header-min></header-min>
<nav-bar></nav-bar>
<section id="sectionP" class="container mySeccion" data-collapsed="false">
<div class="row contenido">
<div class="col l5">
<img class="image" src="http://www.saintjacquesfrenchcuisine.com/images/MenuSlide5.jpg"
alt="Plato Francés"/>
</div>
<div class="col l7">
<div class="descripcionComida">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia
deserunt mollit anim id est laborum.
</div>
</div>
</div>
<br/>
<div class="row">
<div class="col l7 center">
<div class="descripcionComida">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua. Congue quisque egestas diam in arcu cursus euismod quis. Mi tempus imperdiet nulla
malesuada pellentesque elit eget gravida. Tempus imperdiet nulla malesuada pellentesque elit eget
gravida
cum. Commodo elit at imperdiet dui accumsan sit amet. In nulla posuere sollicitudin aliquam ultrices
sagittis.
</div>
</div>
<div class="col l5">
<img src="https://upload.wikimedia.org/wikipedia/commons/6/6a/Jacques_Lameloise%2C_escab%C3%A8che_d%27%C3%A9crevisses_sur_gaspacho_d%27asperge_et_cresson.jpg"
alt="Plato Francés" class="image">
</div>
</div>
<br/>
Implementado con lo último en tecnología <br>
<br>
<br>
<div style="text-align: center">
<a href="https://vuejs.org/" title="Vuejs" target="_blank">
<img src="https://vuejs.org/images/logo.png" alt="vuejs" class="img-inicio hoverable">
</a>
<a href="http://getbem.com/" title="BEM" target="_blank">
<img src="http://getbem.com/assets/b_.svg" alt="bem" class="img-inicio hoverable" style="background-color: black">
</a>
<a href="https://sass-lang.com/" title="Sass" target="_blank">
<img src="https://sass-lang.com/assets/img/logos/logo-b6e1ef6e.svg" class="img-inicio hoverable" alt="sass">
</a>
<a href="https://www.typescriptlang.org/" title="TypeScript" target="_blank">
<img src="https://cdn-images-1.medium.com/max/1187/1*JsyV8lXMuTbRVLQ2FPYWAg.png" class="img-inicio hoverable" alt="typescript">
</a>
<a href="https://nodejs.org/es/" title="nodejs" target="_blank">
<img src="https://pluralsight.imgix.net/paths/path-icons/nodejs-601628d09d.png" alt="nodejs" class="img-inicio hoverable">
</a>
</div>
</section>
<mi-footer></mi-footer>
</div>
</template>
<script>
import HeaderMin from '@/components/headerMin'
import NavBar from '@/components/navBar'
import MiFooter from '@/components/mi-footer'
export default {
name: 'home',
components: {
'header-min': HeaderMin,
'nav-bar': NavBar,
'mi-footer': MiFooter
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,326 @@
<template>
<div>
<header>
<div>
<div id="tituloP" class="center">
<router-link to="/"><h1 class="titulo--link">L'Assiette</h1></router-link>
<div id="tituloP--descripcion">
Descubre un nuevo sabor
</div>
</div>
</div>
<div class="container">
<div class="login--google">
Ingresa con Google: <br>
<br>
<div id="my-signin2"></div>
</div>
<br>
<br>
<div class="row login">
<div class="col l6 m6 s12 login--descripcion center-align">
Inicia sesión con tu email: <br>
<br>
<div class="center">
<form name="form-inicio-sesion" class="login--form"
v-on:submit.prevent="iniciarSesion('form-inicio-sesion')">
<label class="login--form--label">Email:</label>
<input class="login--form--input" type="email" placeholder="Tu email" name="email"
required><br>
<br>
<label class="login--form--label">Contraseña</label>
<input class="login--form--input" type="password" placeholder="Contraseña" required><br>
<br>
<button class="btn waves-effect waves-light" type="submit" name="action">Inicia Sesión
</button>
</form>
</div>
<br>
</div>
<div class="col l6 m6 s12 login--registro center-align" id="bordeIzq">
Regístrate con tu email: <br>
<br>
<div class="center">
<form name="form-registro" class="login--form"
v-on:submit.prevent="registrar('form-registro')">
<label class="login--form--label">Nombre</label>
<input class="login--form--input" type="text" placeholder="Tu nombre" name="nombre"
required><br>
<br>
<label class="login--form--label">Email:</label>
<input class="login--form--input" type="email" placeholder="Tu email" name="email"
required><br>
<br>
<label class="login--form--label">Contraseña</label>
<input class="login--form--input" type="password" placeholder="Contraseña" name="pass"
required><br>
<br>
<button class="btn waves-effect waves-light" type="submit" name="action">Regístrame
</button>
</form>
</div>
</div>
</div>
<br>
</div>
<div id="pantalla-carga" pantalla-activa="false">
Iniciando Sesión...<br>
<br>
<div class="preloader-wrapper active center" id="esfera-carga">
<div class="spinner-layer spinner-blue">
<div class="circle-clipper left">
<div class="circle"></div>
</div>
<div class="gap-patch">
<div class="circle"></div>
</div>
<div class="circle-clipper right">
<div class="circle"></div>
</div>
</div>
<div class="spinner-layer spinner-red">
<div class="circle-clipper left">
<div class="circle"></div>
</div>
<div class="gap-patch">
<div class="circle"></div>
</div>
<div class="circle-clipper right">
<div class="circle"></div>
</div>
</div>
<div class="spinner-layer spinner-yellow">
<div class="circle-clipper left">
<div class="circle"></div>
</div>
<div class="gap-patch">
<div class="circle"></div>
</div>
<div class="circle-clipper right">
<div class="circle"></div>
</div>
</div>
<div class="spinner-layer spinner-green">
<div class="circle-clipper left">
<div class="circle"></div>
</div>
<div class="gap-patch">
<div class="circle"></div>
</div>
<div class="circle-clipper right">
<div class="circle"></div>
</div>
</div>
</div>
</div>
<br>
</header>
</div>
</template>
<script>
import MiFooter from '@/components/mi-footer.vue'
/* Cambiado porque a Babel no le gusto es sistema con module.exports/require */
// const conex_backend = require('../variables.js').conexion;
import conex_backend from '../variables';
const procesarUsuario = data => {
try {
const obj = JSON.parse(data);
obj["logged"] = true;
console.log(JSON.stringify(obj));
window.usuarioActual.pop();
window.usuarioActual.push(obj);
window.elRouter.push('/platos/');
} catch (e) {
cambiarPantallaCarga();
}
};
function onSuccess(googleUser) {
cambiarPantallaCarga();
let id_token = googleUser.getAuthResponse().id_token;
let xhr = new XMLHttpRequest();
console.log(`Conexion backend es ${conex_backend}`);
xhr.open('POST', `${conex_backend}/log-inG`);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onload = function () {
console.log('Sesión iniciada. Servidor:\n' + xhr.responseText);
procesarUsuario(xhr.responseText);
};
xhr.send('idtoken=' + id_token);
}
function onFailure(error) {
console.log(error);
}
function renderButton() {
gapi.signin2.render('my-signin2', {
'scope': 'profile email',
'width': 240,
'height': 50,
'longtitle': true,
'theme': 'dark',
'onsuccess': onSuccess,
'onfailure': onFailure
});
}
const crearUsuario = data =>
new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open("POST", `${conex_backend}/registro`);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.onload = () => {
const resultado = JSON.parse(xhr.responseText);
if (!resultado["existe"] && resultado["creado"]) {
resolve(JSON.stringify(resultado["data"]));
} else {
reject();
}
};
xhr.send(`nombre=${data['nombreUsuario']}&email=${data['emailUsuario']}&pass=${data['passUsuario']}`);
});
const cambiarPantallaCarga = () => {
const elem = document.getElementById("pantalla-carga");
const pantallaActiva = elem.getAttribute("pantalla-activa") === "true";
// La pantalla de carga es visible y hay que ocultarla
if (pantallaActiva) {
elem.setAttribute("pantalla-activa", "false");
elem.style.opacity = "0";
setTimeout(() => {
elem.style.display = "none";
}, 250);
} else {
// Aqui activamos la pantalla
elem.setAttribute("pantalla-activa", "true");
elem.style.display = "inline-table";
setTimeout(() => {
elem.style.opacity = "0.7";
}, 10);
}
};
/* Inserta el script para el inicio de sesion de gugel */
(() => {
let scr = document.createElement("script");
scr.src = "https://apis.google.com/js/platform.js";
scr.onload = renderButton;
scr.defer = true;
document.head.appendChild(scr);
})();
export default {
name: 'IniciarSesion',
components: {
'mi-footer': MiFooter
},
methods: {
registrar: function (nombre) {
cambiarPantallaCarga();
const nombreUsuario = document.forms[nombre]['nombre'].value;
const emailUsuario = document.forms[nombre]['email'].value;
const passUsuario = document.forms[nombre]['pass'].value;
crearUsuario({nombreUsuario, emailUsuario, passUsuario})
.then(respuesta => procesarUsuario(respuesta))
.catch(() => {
alert("Ya existe un usuario con este email");
});
},
iniciarSesion: function (nombre) {
const emailUsuario = document.forms[nombre]['email'].value;
const nombreUsuario = emailUsuario.substring(0, emailUsuario.search("@"));
window.usuarioActual[0].nombre = nombreUsuario;
window.usuarioActual[0].email = emailUsuario;
window.usuarioActual[0].logged = true;
window.elRouter.push("/");
}
}
}
</script>
<style scoped lang="sass">
#my-signin2
display: inline-block
#bordeIzq
border-left: solid 1px white
.login
color: white
.login--google
text-align: center
color: white
.login--boton
border: none
padding: 10px 50px
cursor: pointer
border-radius: 3px
.login--botonGoogle
background-color: white
.login--botonFacebook
background-color: #3b5998
color: white
.login--form
width: 80%
display: inline-block
.login--form--input
color: white
font-size: large !important
text-shadow: 1px 1px 2px black
.login--form--label
color: white
#pantalla-carga
background-color: black
opacity: 0
z-index: 2
position: fixed
top: 0
width: 100%
height: 100%
transition: opacity 250ms
display: none
text-align: center
padding-top: 20%
color: white
#esfera-carga
text-align: center
width: 100px
height: 100px
@media only screen and (max-width: 800px)
#pantalla-carga
padding-top: 40%
@media only screen and (max-width: 450px)
#pantalla-carga
padding-top: 70%
.lol
</style>

114
src/views/MiCuenta.vue Normal file
View File

@ -0,0 +1,114 @@
<template>
<div>
<header-mini />
<nav-bar-inicio-sesion />
<nav-bar />
<section>
<div class="container fondoBlanco">
<h2 class="tienda--titulo">Mi cuenta</h2>
<br>
<div v-if="usuarioNoLogeado" class="mi-cuenta--usuario-no-logeado">
¡Ups! Parece que no iniciaste sesión.<br>
Obtén acceso a más de 7 platos
gourmet en la comodida de tu hogar:
<br>
<br>
<div id="contenedorInicio-Registro" class="center mySeccion" data-collapsed="false">
<router-link to="/iniciar-sesion/" id="botonRegistro" class="boton">
Registrarse
</router-link>
<router-link to="/iniciar-sesion/" id="botonInicioSesion" class="boton">
Iniciar Sesion
</router-link>
<br/>
<br/>
<br/>
</div>
</div>
<div v-else class="row">
<div class="col l6 m6">
<div class="datos-usuario">
<img :src="usuario.img" alt="Imagen del Usuario" class="left datos-usuario--imagen">
<div class="datos-usuario--descr">
{{ usuario.nombre }}, desde aquí puedes acceder a todos tus datos, y modificarlos
si deseas.
</div>
<div style="clear: left;"></div>
</div>
<br>
<div class="datos-editar">
<form action="">
<label for="nombre-usuario">Tu nombre</label>
<input id="nombre-usuario" placeholder="Tu nombre" :value="usuario.nombre"/><br>
<label for="email-usuario">Tu email</label>
<input id="email-usuario" placeholder="Tu email" :value="usuario.email"/><br>
<label for="id-usuario">Tu ID de usuario</label>
<input id="id-usuario" disabled :value="(99999999999 - parseInt(usuario['USER_ID'])).toString(16).toUpperCase()">
</form>
</div>
</div>
<div class="col l6 m6">
Tu historial de Compras <br>
<br>
<div v-if="historialVacio">
Tu historial de compras está vacio. ¡Compra algo y lo verás aquí!
</div>
<div v-else>
<template v-for="(plato, key) in usuario.historial">
</template>
</div>
</div>
</div>
</div>
</section>
<mi-footer></mi-footer>
</div>
</template>
<script>
import HeaderMini from '@/components/headerMini'
import NavBar from '@/components/navBar'
import MiFooter from '@/components/mi-footer'
import NavBarInicioSesion from '../components/navBarInicioSesion.vue';
export default {
name: "MiCuenta",
components: {
NavBarInicioSesion,
'header-mini': HeaderMini,
'nav-bar': NavBar,
'mi-footer': MiFooter,
'nav-bar-inicio-sesion': NavBarInicioSesion
},
data: function () {
return {
usuario: window.usuarioActual[0]
}
},
computed: {
historialVacio: function () {
for (let i in this.usuario.historial) {
return false
}
return true
},
usuarioNoLogeado: function () {
return !this.usuario.logged;
}
}
}
</script>
<style scoped lang="sass">
.datos-usuario--imagen
margin: 10px
.datos-usuario--descr
padding: 5px
.datos-editar
</style>

116
src/views/MiPedido.vue Normal file
View File

@ -0,0 +1,116 @@
<template>
<div>
<header-mini />
<login-bar v-if="usuarioNoLogeado" />
<nav-bar />
<div class="container fondoBlanco pedidos">
<h2 class="pedidos__titulo">Mis pedidos</h2>
<br>
<br>
<div v-if="usuarioNoLogeado" class="pedidos__usuario-no-logeado">
¡Ups! Parece que no iniciaste sesión.<br>
Inicia sesión y controla fácilmente tus pedidos y entregas a domicilio. <br>
<br>
<div id="contenedorInicio-Registro" class="center mySeccion" data-collapsed="false">
<router-link to="/iniciar-sesion/" id="botonRegistro" class="boton">
Registrarse
</router-link>
<router-link to="/iniciar-sesion/" id="botonInicioSesion" class="boton">
Iniciar Sesion
</router-link>
<br/>
<br/>
<br/>
</div>
</div>
<div v-else>
<pedido v-for="pedido in pedidos"/>
</div>
</div>
<mi-footer />
</div>
</template>
<script>
import HeaderMini from '../components/headerMini'
import NavBar from '../components/navBar'
import LoginBar from '../components/navBarInicioSesion'
import MiFooter from '../components/mi-footer'
import Pedido from '../components/pedido'
import conexion from '../variables';
export default {
name: "MiPedido",
data: function () {
return {
usuario: window.usuarioActual[0],
pedidos: []
}
},
components: {
'header-mini': HeaderMini,
'nav-bar': NavBar,
'login-bar': LoginBar,
'mi-footer': MiFooter,
'pedido': Pedido
},
computed: {
usuarioNoLogeado: function () {
return !this.usuario.logged;
}
},
methods: {
obtenerPedidos: function () {
let vm = this;
const usuarioLogueado = !this.usuario.logged;
return new Promise((resolve, reject) => {
if ( usuarioLogueado ) {
reject("Usuario no logeado.");
return;
}
const xhr = new XMLHttpRequest();
xhr.open("POST",`${conexion}/pedidos/actual`);
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xhr.onload = () => {
console.log(`Esta es mi respuesta we :3\n${xhr.responseText}`);
resolve(xhr.responseText);
};
xhr.send(`USER_ID=${vm.usuario["USER_ID"]}`);
});
}
},
created: function () {
let vm = this;
this.obtenerPedidos()
.then(response => {
while (vm.pedidos.pop() !== 0);
const data = JSON.parse(response);
for (item of data) {
vm.pedidos.push(item);
}
})
.catch(reason => console.log(`Obtener pedidos desde el servidor rechazado. Razón: ${reason}`));
}
}
</script>
<style scoped lang="sass">
.pedidos__titulo
text-align: center
font:
size: xx-large
weight: bold
family: Muli, "Open Sans", sans-serif
margin: 10px 0
.pedidos__usuario-no-logeado
font-size: x-large
text-align: center
.pedidos
</style>

151
src/views/Platos.vue Normal file
View File

@ -0,0 +1,151 @@
<template>
<div>
<header-mini />
<nav-bar-inicio-sesion />
<nav-bar />
<section class="tienda container mySeccion fondoBlanco" data-collapsed="false">
<h2 class="tienda--titulo">Platos</h2>
<br>
<template v-for="(item,key) in platos">
<div v-bind:key="key" class="row tienda--tarjeta hoverable">
<div class="col l4">
<img class="responsive-image" :src="item.imgUrl"/>
</div>
<div class="col l8">
<div class="tienda--tarjeta--titulo">
{{ item.nombre }}
</div>
<br>
<div class="tienda--tarjeta--descripcion">
{{ item.descripcion }}
</div>
<br>
<div class="tienda--tarjeta--precio">
{{ item.precio }}
</div>
<br>
<div class="tienda--tarjeta--cantidad">
<i class='material-icons plato--Cantidad--Icon' v-on:click="disminuirCantidad('itemNum' + key)">
remove
</i>
<span :id=" 'itemNum' + key ">1</span>
<i class='material-icons plato--Cantidad--Icon' v-on:click="aumentarCantidad('itemNum' + key)">
add
</i>
</div>
<br/>
<button class="tienda--tarjeta--botonComprar" v-on:click="addAlCarro(item, 'itemNum' + key)">
<i class='material-icons'>add_shopping_cart</i> Añadir al carrito
</button>
</div>
</div>
</template>
</section>
<mi-footer />
</div>
</template>
<script>
import MiFooter from "../components/mi-footer.vue";
import HeaderMini from '../components/headerMini.vue';
import NavBar from '../components/navBar.vue';
import NavBarInicioSesion from '../components/navBarInicioSesion.vue';
export default {
name: 'Platos',
components: {
'mi-footer': MiFooter,
'header-mini': HeaderMini,
'nav-bar': NavBar,
'nav-bar-inicio-sesion': NavBarInicioSesion
},
data: function () {
return {
platos: [
{
"nombre": "Soupe à l'oignon",
"descripcion": "Sopa tradicional hecha con cebolla y carne.",
"imgUrl": "https://www.expatica.com/media/upload/714571.jpg",
"precio": 20
},
{
"nombre": "Coq au vin",
"descripcion": "Pollo cocinado con vino, hongos, carne de cerdo y ajo",
"imgUrl": "https://www.expatica.com/media/upload/714572.jpg",
"precio": 50
},
{
"nombre": "Beef bourguignon",
"descripcion": "Filete cocinado en vino, sasonado con especias",
"imgUrl": "https://www.expatica.com/media/upload/714573.jpg",
"precio": 30
},
{
"nombre": "Cassoulet",
"descripcion": "Guiso parecido a las habichuelas típicas españolas que se hace con alubias blancas o frijoles acompañadas de carne de diferentes animales",
"imgUrl": "https://www.viajejet.com/wp-content/viajes/Cassoulet-570x320.jpg",
"precio": 22
},
{
"nombre": "Fondue de queso",
"descripcion": "Crema que se puede tomar bien como acompañante de otros ingredientes o bien mojando trozos de pan en él.",
"imgUrl": "https://www.viajejet.com/wp-content/viajes/Fondue-570x321.jpg",
"precio": 5
},
{
"nombre": "Ratatouille",
"descripcion": "Elaborado con diversas hortalizas, es un plato natural de Niza y la región de Provenza, al sureste de Francia.",
"imgUrl": "https://www.viajejet.com/wp-content/viajes/Ratatouille-570x320.jpg",
"precio": 35
},
{
"nombre": "Magret de canard",
"descripcion": "Un filete de carne magra, que suele provenir de un ganso o pato cebado",
"imgUrl": "https://www.viajejet.com/wp-content/viajes/Magret-de-Canard-570x320.jpg",
"precio": 17
},
{
"nombre": "Merluza al beurre blanc",
"descripcion": "Este plato consiste en troncos o lomos de merluza que se sirven en salsa beurre blanc.",
"imgUrl": "https://www.viajejet.com/wp-content/viajes/Merluza-a-la-beurre-blanc-570x320.jpg",
"precio": 22
}
]
};
},
methods: {
addAlCarro: function (plato, id) {
const cantidad = parseInt(document.getElementById(id).innerText);
const obj = JSON.parse(JSON.stringify(plato));
obj["cantidad"] = cantidad;
carritoUsuario.push(obj);
M.toast({html: `Añadido al carrito.&nbsp;&nbsp;<span onclick="window.irAlCarro()" class="irAlCarrito">Ir al carrito</span>`})
},
aumentarCantidad: function (id) {
const elem = document.getElementById(id);
const valorActual = parseInt(elem.innerText);
if (valorActual > 0) {
elem.innerText = valorActual + 1;
} else {
elem.innerText = 1;
}
},
disminuirCantidad: function (id) {
const elem = document.getElementById(id);
const valorActual = parseInt(elem.innerText);
if (valorActual > 1) {
elem.innerText = valorActual - 1;
} else {
elem.innerText = 1;
}
}
}
}
</script>
<style scoped lang="sass">
</style>

174
src/views/carrito.vue Normal file
View File

@ -0,0 +1,174 @@
<template>
<div>
<header-mini />
<nav-bar-inicio-sesion />
<nav-bar />
<section id="sectionCarrito" class="container mySeccion fondoBlanco">
<div class="center">
<div id="carrito--tituloprincipal">
Carrito de compras
</div>
<br/>
<router-link id="carrito--boton--seguircomprando" to="/platos/" class="hoverable">Seguir comprando</router-link>
<br/>
<br/>
<div id="carrito" class="row carrito">
<div id="carrito--elementos" class="col l8">
<div id="carrito--elementos--contenido" class="caja">
<template v-if="noEstaVacio">
<template v-for="(producto,key) in carrito">
<div v-bind:key="key" class="carritoElem">
<img class="carritoElem--img" v-bind:src="producto.imgUrl">
<div class="plato--Titulo">{{ producto.nombre }}</div>
<br>
<div class="plato--Precio">{{ producto.precio }}</div>
<div class="plato--Cantidad">Cantidad:
<i class="material-icons plato--Cantidad--Icon" v-on:click="restarCantidad(producto)">remove</i>
<span>{{ producto.cantidad }}</span>
<i class="material-icons plato--Cantidad--Icon" v-on:click="aumentarCantidad(producto)">add</i>
</div>
<br>
<div class="carrito--subTotal">{{ producto.precio * producto.cantidad }}</div>
<hr>
</div>
</template>
</template>
<template v-else>
No hay nada en tu carrito de compras :c
</template>
</div>
</div>
<div id="carrito--precio" class="col l4">
<div id="carrito--precio--contenido" class="caja">
<template v-if="noEstaVacio">
<div id="pagos">
<div style="display: inline-block;">
{{ cantidadItems }} Producto{{ (cantidadItems>1 || cantidadItems === 0) ? 's': '' }}
</div>
<div style="display: inline-block; float: right; clear: both">
{{ subTotal }} S/.
</div>
</div>
<div>
<div style="display: inline-block;">
Descuentos:
</div>
<div style="display: inline-block; float: right; clear: both">
{{ descuento }} S/.
</div>
</div>
<br>
<br>
<div>
<div class="carrito--precio--contenido--titulo" style="display: inline-block;">
Total:
</div>
<div class="carrito--precio--contenido--titulo"
style="display: inline-block; float: right; clear: both">
{{ total }} S/.
</div>
</div>
<br>
<br>
<div style="text-align: center">
<a class="carrito--precio--contenido--botonPagar" v-if="usuarioLogeado">
Completar Transaccion
</a>
<router-link to="/iniciar-sesion/" v-else class="carrito__precio__usuarioNoLogeado hoverable">
Inicia Sesion o Regístrate para continuar.
</router-link>
</div>
</template>
<template v-else>
No hay nada en tu carrito de compras :c
</template>
</div>
</div>
</div>
</div>
<br/>
<br/>
</section>
<mi-footer></mi-footer>
</div>
</template>
<script>
import HeaderMini from '@/components/headerMini'
import NavBar from '@/components/navBar'
import MiFooter from '@/components/mi-footer'
import NavBarInicioSesion from '../components/navBarInicioSesion.vue';
export default {
name: 'Carrito',
components: {
'header-mini': HeaderMini,
'nav-bar': NavBar,
'mi-footer': MiFooter,
'nav-bar-inicio-sesion': NavBarInicioSesion
},
data: function () {
return {
carrito: window.carritoUsuario,
descuento: 0
}
},
computed: {
cantidadItems: function () {
let items = 0;
for (const i in this.item)
items++;
return items;
},
subTotal: function () {
let subT = 0;
for (const itemI in this.carrito ) {
if (this.carrito.hasOwnProperty(itemI)){
const item = this.carrito[itemI];
subT += (item["precio"] * item["cantidad"]);
}
}
return subT;
},
total: function () {
return this.subTotal - this.descuento;
},
noEstaVacio: function () {
for (const i in this.carrito) {
return true;
}
return false;
},
usuarioLogeado: function () {
return window.usuarioActual[0]["logged"];
}
},
methods: {
restarCantidad: function (elem) {
const cantidad = parseInt(elem.cantidad);
if (cantidad > 0)
elem.cantidad = cantidad -1;
},
aumentarCantidad: function (elem) {
const cantidad = parseInt(elem.cantidad);
if (cantidad >= 0)
elem.cantidad = cantidad+1;
}
}
}
</script>
<style scoped lang="sass">
.carrito__precio__usuarioNoLogeado
display: inline-block
background-color: green
color: white
border-radius: 3px
padding: 10px
</style>

0
srv/index.ts Normal file
View File

View File

@ -1,13 +0,0 @@
<br />
<br />
<div class="center">
Personal<br />
<br />
<br />
<a href="./#usuarios/">Volver a la carta</a>
<br />
<br />
</div>
<br />
<br />

17
tsconfig.json Normal file
View File

@ -0,0 +1,17 @@
{
"compilerOptions": {
// this aligns with Vue's browser support
"target": "es6",
// this enables stricter inference for data properties on `this`
"strict": true,
// if using webpack 2+ or rollup, to leverage tree shaking:
"module": "es2015",
"moduleResolution": "node",
"types": [
"node"
],
"typeRoots": [
"node_modules/@types"
]
}
}

View File

@ -1,13 +0,0 @@
<br />
<br />
<div class="center">
Pedidos<br />
<br />
<a href="./#usuarios/mi-cuenta">Ver mi cuenta</a><br />
<br />
<br />
<div id="productos">
</div>
</div>
<br />
<br />

View File

@ -1,53 +0,0 @@
<br/>
<br/>
<div class="center" style="font-size: large">
Mi cuenta<br/>
<br/>
<a href="./#usuarios/">Seguir comprando</a>
<br/>
<br/>
<div class="row">
<div class="col-6">
Mis datos:<br/>
<br/>
<div style="text-align: left">
Nombre: {{ userName }}<br/>
Correo electrónico: {{ userEmail }}<br/>
Métodos de pago: {{ userPaymentMethods }}<br/>
</div>
</div>
<div class="col-6">
Historial de compras:<br/>
<br/>
<div class="row">
<div class="col-3 unseen">.</div>
<div class="col-6">
<img class="image" src="https://www.expatica.com/media/upload/714571.jpg">
<div>Soupe à l'oignon</div>
<br>
<div>Sopa tradicional hecha con cebolla y carne.</div>
<div class="center">20 S/.</div>
<div>Fecha de compra: 17/09/18</div>
<br>
</div>
<div class="col-3 unseen">.</div>
</div>
<br />
<div class="row">
<div class="col-3 unseen">.</div>
<div class="col-6">
<img class="image" src="https://www.expatica.com/media/upload/714573.jpg">
<div>Cassoulet</div>
<br>
<div>Plato de habas con carne y especies.</div>
<div class="center">5 S/.</div>
<div>Fecha de compra: 15/09/18</div>
<br>
</div>
<div class="col-3 unseen">.</div>
</div>
</div>
</div>
</div>
<br/>
<br/>

View File

@ -1,84 +0,0 @@
<br/>
<br/>
<div class="center">
<div id="carrito--tituloprincipal">
Carrito de compras
</div>
<br/>
<a id="carrito--boton--seguircomprando" href="./#usuarios/">Seguir comprando</a>
<br/>
<br/>
<div id="carrito" class="row carrito">
<div id="carrito--elementos" class="col-8">
<div id="carrito--elementos--contenido" class="caja">
<template v-if="noEstaVacio">
<template v-for="producto in item">
<div class="carritoElem">
<img class="carritoElem--img" v-bind:src="producto.imgUrl">
<div class="plato--Titulo">{{ producto.nombre }}</div>
<br>
<div class="plato--Precio">{{ producto.precio }}</div>
<div class="plato--Cantidad">Cantidad:
<i class="material-icons plato--Cantidad--Icon" v-on:click="restarCantidad(producto)">remove</i>
<span>{{ producto.cantidad }}</span>
<i class="material-icons plato--Cantidad--Icon" v-on:click="aumentarCantidad(producto)">add</i>
</div>
<br>
<div class="carrito--subTotal">{{ producto.precio * producto.cantidad }}</div>
<hr>
</div>
</template>
</template>
<template v-else>
No hay nada en tu carrito de compras :c
</template>
</div>
</div>
<div id="carrito--precio" class="col-4">
<div id="carrito--precio--contenido" class="caja">
<template v-if="noEstaVacio">
<div id="pagos">
<div style="display: inline-block;">
{{ cantidadItems }} Producto{{ (cantidadItems>1 || cantidadItems === 0) ? 's': '' }}
</div>
<div style="display: inline-block; float: right; clear: both">
{{ subTotal }} S/.
</div>
</div>
<div>
<div style="display: inline-block;">
Descuentos:
</div>
<div style="display: inline-block; float: right; clear: both">
{{ descuento }} S/.
</div>
</div>
<br>
<br>
<div>
<div class="carrito--precio--contenido--titulo" style="display: inline-block;">
Total:
</div>
<div class="carrito--precio--contenido--titulo"
style="display: inline-block; float: right; clear: both">
{{ total }} S/.
</div>
</div>
<br>
<br>
<a class="carrito--precio--contenido--botonPagar">
Completar Transaccion
</a>
</template>
<template v-else>
No hay nada en tu carrito de compras :c
</template>
</div>
</div>
</div>
</div>
<br/>
<br/>

View File

@ -1,50 +0,0 @@
[
{
"nombre": "Soupe à l'oignon",
"descripcion": "Sopa tradicional hecha con cebolla y carne.",
"imgUrl": "https://www.expatica.com/media/upload/714571.jpg",
"precio": 20
},
{
"nombre": "Coq au vin",
"descripcion": "Pollo cocinado con vino, hongos, carne de cerdo y ajo",
"imgUrl": "https://www.expatica.com/media/upload/714572.jpg",
"precio": 50
},
{
"nombre": "Beef bourguignon",
"descripcion": "Filete cocinado en vino, sasonado con especias",
"imgUrl": "https://www.expatica.com/media/upload/714573.jpg",
"precio": 30
},
{
"nombre": "Cassoulet",
"descripcion": "Guiso parecido a las habichuelas típicas españolas que se hace con alubias blancas o frijoles acompañadas de carne de diferentes animales",
"imgUrl": "https://www.viajejet.com/wp-content/viajes/Cassoulet-570x320.jpg",
"precio": 22
},
{
"nombre": "Fondue de queso",
"descripcion": "Crema que se puede tomar bien como acompañante de otros ingredientes o bien mojando trozos de pan en él.",
"imgUrl": "https://www.viajejet.com/wp-content/viajes/Fondue-570x321.jpg",
"precio": 5
},
{
"nombre": "Ratatouille",
"descripcion": "Elaborado con diversas hortalizas, es un plato natural de Niza y la región de Provenza, al sureste de Francia.",
"imgUrl": "https://www.viajejet.com/wp-content/viajes/Ratatouille-570x320.jpg",
"precio": 35
},
{
"nombre": "Magret de canard",
"descripcion": "Un filete de carne magra, que suele provenir de un ganso o pato cebado",
"imgUrl": "https://www.viajejet.com/wp-content/viajes/Magret-de-Canard-570x320.jpg",
"precio": 17
},
{
"nombre": "Merluza al beurre blanc",
"descripcion": "Este plato consiste en troncos o lomos de merluza que se sirven en salsa beurre blanc.",
"imgUrl": "https://www.viajejet.com/wp-content/viajes/Merluza-a-la-beurre-blanc-570x320.jpg",
"precio": 22
}
]

8
vue.config.js Normal file
View File

@ -0,0 +1,8 @@
module.exports = {
pluginOptions: {
express: {
shouldServeApp: true,
serverDir: './srv'
}
}
}