se avanza con login usando jwt
|
@ -10,7 +10,7 @@ services:
|
|||
- 3000:3000
|
||||
environment:
|
||||
- VITE_PORT=3000
|
||||
- VITE_BACKEND="http://localhost:4000/api"
|
||||
- VITE_BACKEND=http://localhost:4000/api
|
||||
working_dir: /app
|
||||
command: sh -c "
|
||||
[ ! -d node_modules ] && npm install ;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + Svelte</title>
|
||||
<title>Gestión de Transporte</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
|
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 36 KiB |
|
@ -0,0 +1,19 @@
|
|||
|
||||
.sidebar, .sidebar-content {
|
||||
background: steelblue;
|
||||
}
|
||||
|
||||
.sidebar-item.active .sidebar-link:hover, .sidebar-item.active>.sidebar-link {
|
||||
background: linear-gradient(90deg,rgba(45, 94, 167, 0.5),rgba(59,125,221,.088) 50%,transparent);
|
||||
border-left-color: orange;
|
||||
color: #e9ecef;
|
||||
}
|
||||
|
||||
.sidebar-link, a.sidebar-link {
|
||||
background: steelblue;
|
||||
}
|
||||
|
||||
|
||||
a.sidebar-link:hover {
|
||||
background: steelblue;
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
<div class="d-table-cell align-middle">
|
||||
|
||||
<div class="text-center mt-4">
|
||||
<h1 class="h2">Sistema xxxx</h1>
|
||||
<h1 class="h2">Gestión de Transporte</h1>
|
||||
<p class="lead">
|
||||
Acceda a su cuenta para continuar
|
||||
</p>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import '@adminkit/core/dist/css/app.css'
|
||||
import '@adminkit/core/dist/js/app.js'
|
||||
import 'bootstrap-icons/font/bootstrap-icons.css'
|
||||
import '../assets/colors.css'
|
||||
import Navbar from './Navbar.svelte'
|
||||
import Sidebar from './Sidebar.svelte'
|
||||
import Footer from './Footer.svelte'
|
||||
|
@ -11,6 +12,8 @@
|
|||
import { Router, Route, createHistory } from 'svelte-navigator'
|
||||
import hashHistory from './hashHistory'
|
||||
import { onMount } from 'svelte'
|
||||
import { getInfoToken } from '$/services/login'
|
||||
import { storeSession } from '$/stores/session'
|
||||
|
||||
|
||||
let triggerEvent = false;
|
||||
|
@ -19,6 +22,15 @@
|
|||
onMount(() => {
|
||||
triggerEvent && document.dispatchEvent(new Event('DOMContentLoaded'));
|
||||
})
|
||||
|
||||
async function begin() {
|
||||
try {
|
||||
$storeSession = await getInfoToken()
|
||||
} catch (error) {
|
||||
alert(error.message || error)
|
||||
}
|
||||
}
|
||||
begin()
|
||||
</script>
|
||||
|
||||
<div class="wrapper">
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
import { Link } from 'svelte-navigator'
|
||||
|
||||
let avatar = null;
|
||||
$: avatar = $storeSession?.avatar_img || '/img/avatar.jpg';
|
||||
let persona = {}
|
||||
|
||||
$: persona = $storeSession
|
||||
$: avatar = $storeSession?.avatar_img || '/avatars/avatar1.jpg';
|
||||
|
||||
function onLogout() {
|
||||
sessionStorage.clear();
|
||||
|
@ -17,11 +20,11 @@
|
|||
</a>
|
||||
|
||||
<a class="nav-link dropdown-toggle d-none d-sm-inline-block" href={"#"} data-bs-toggle="dropdown">
|
||||
<img src={avatar} class="avatar img-fluid rounded me-1" alt={$storeSession?.nombre_completo} />
|
||||
<span class="text-dark">{$storeSession?.alias}</span>
|
||||
<img src={avatar} class="avatar img-fluid rounded me-1" alt={persona.nombres} />
|
||||
<span class="text-dark">{$storeSession.login}</span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-end">
|
||||
<Link class="dropdown-item" to="/profile">
|
||||
<Link class="dropdown-item" to="/perfil">
|
||||
<i class="align-middle me-1" data-feather="user"></i> Perfil
|
||||
</Link>
|
||||
<div class="dropdown-divider"></div>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
<nav id="sidebar" class="sidebar js-sidebar">
|
||||
<div class="sidebar-content js-simplebar">
|
||||
<Link class="sidebar-brand" to="/">
|
||||
<span class="fs-1">🚌</span>
|
||||
<span class="align-middle">
|
||||
Transporte
|
||||
</span>
|
||||
|
@ -19,7 +20,7 @@
|
|||
<span class="align-middle">Inicio</span>
|
||||
</SideLink>
|
||||
|
||||
<SideLink to="/profile">
|
||||
<SideLink to="/perfil">
|
||||
<i class="align-middle bi bi-person-lines-fill fs-4"></i>
|
||||
<span class="align-middle">Perfil</span>
|
||||
</SideLink>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { Link } from 'svelte-navigator'
|
||||
import { getToken } from '$/services/login'
|
||||
import { createToken } from '$/services/login'
|
||||
|
||||
let form = { username: '', pass: '' }
|
||||
let message_error = '';
|
||||
|
@ -8,11 +8,13 @@
|
|||
// validar usuario contraseña
|
||||
async function onIngresar() {
|
||||
try {
|
||||
const token = await getToken(form)
|
||||
message_error = ''
|
||||
const { token } = await createToken(form)
|
||||
sessionStorage.setItem('token', token)
|
||||
document.location.reload();
|
||||
} catch(error) {
|
||||
message_error = error.message || error
|
||||
setTimeout(() => message_error = '', 3000)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -20,12 +22,10 @@
|
|||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="m-sm-4">
|
||||
<div class="row align-items-center mb-4">
|
||||
<div class="col-auto">
|
||||
<img src="/img/avatar.jpg" alt="Avatar"
|
||||
class="img-fluid rounded-circle" width="132" height="132"
|
||||
/>
|
||||
</div>
|
||||
<div class="text-center mb-4">
|
||||
<img src="/avatars/avatar1.jpg" alt="Avatar"
|
||||
class="img-fluid rounded-circle" width="132" height="132"
|
||||
/>
|
||||
</div>
|
||||
<form on:submit|preventDefault={onIngresar}>
|
||||
<div class="mb-3">
|
||||
|
@ -35,7 +35,7 @@
|
|||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for={null}>Contraseña</label>
|
||||
<input class="form-control form-control-lg" type="password" bind:value={form.pass} required
|
||||
<input class="form-control form-control-lg" type="password" bind:value={form.password} required
|
||||
placeholder="Ingrese su contraseña">
|
||||
</div>
|
||||
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
<script>
|
||||
import { storeSession } from "$/stores/session";
|
||||
let persona = {}
|
||||
$: persona = $storeSession.persona || {};
|
||||
</script>
|
||||
|
||||
<h1 class="h3 mb-3">Perfil de usuario</h1>
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-xl-3">
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Perfil Detallado</h5>
|
||||
</div>
|
||||
<div class="card-body text-center">
|
||||
<img
|
||||
src="/avatars/avatar1.jpg"
|
||||
alt="Christina Mason"
|
||||
class="img-fluid rounded-circle mb-2"
|
||||
width="128"
|
||||
height="128"
|
||||
/>
|
||||
<h5 class="card-title mb-0">{persona.nombres} {persona.apellido_a} {persona.apellido_b}</h5>
|
||||
<div class="text-muted mb-2">{persona.rut}-{persona.dv}</div>
|
||||
|
||||
<div>
|
||||
<a class="btn btn-primary btn-sm" href={"#"}>Follow</a>
|
||||
<a class="btn btn-primary btn-sm" href={"#"}
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="feather feather-message-square"
|
||||
><path
|
||||
d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"
|
||||
/></svg
|
||||
> Message</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="my-0" />
|
||||
<div class="card-body">
|
||||
<h5 class="h6 card-title">Skills</h5>
|
||||
<a href={"#"} class="badge bg-primary me-1 my-1">HTML</a>
|
||||
<a href={"#"} class="badge bg-primary me-1 my-1">JavaScript</a>
|
||||
<a href={"#"} class="badge bg-primary me-1 my-1">Sass</a>
|
||||
<a href={"#"} class="badge bg-primary me-1 my-1">Angular</a>
|
||||
<a href={"#"} class="badge bg-primary me-1 my-1">Vue</a>
|
||||
<a href={"#"} class="badge bg-primary me-1 my-1">React</a>
|
||||
<a href={"#"} class="badge bg-primary me-1 my-1">Redux</a>
|
||||
<a href={"#"} class="badge bg-primary me-1 my-1">UI</a>
|
||||
<a href={"#"} class="badge bg-primary me-1 my-1">UX</a>
|
||||
</div>
|
||||
<hr class="my-0" />
|
||||
<div class="card-body">
|
||||
<h5 class="h6 card-title">About</h5>
|
||||
<ul class="list-unstyled mb-0">
|
||||
<li class="mb-1">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="feather feather-home feather-sm me-1"
|
||||
><path
|
||||
d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"
|
||||
/><polyline points="9 22 9 12 15 12 15 22" /></svg
|
||||
>
|
||||
Lives in <a href={"#"}>San Francisco, SA</a>
|
||||
</li>
|
||||
|
||||
<li class="mb-1">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="feather feather-briefcase feather-sm me-1"
|
||||
><rect
|
||||
x="2"
|
||||
y="7"
|
||||
width="20"
|
||||
height="14"
|
||||
rx="2"
|
||||
ry="2"
|
||||
/><path
|
||||
d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"
|
||||
/></svg
|
||||
>
|
||||
Works at <a href={"#"}>GitHub</a>
|
||||
</li>
|
||||
<li class="mb-1">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="feather feather-map-pin feather-sm me-1"
|
||||
><path
|
||||
d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"
|
||||
/><circle cx="12" cy="10" r="3" /></svg
|
||||
>
|
||||
From <a href={"#"}>Boston</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<hr class="my-0" />
|
||||
<div class="card-body">
|
||||
<h5 class="h6 card-title">Elsewhere</h5>
|
||||
<ul class="list-unstyled mb-0">
|
||||
<li class="mb-1"><a href={"#"}>staciehall.co</a></li>
|
||||
<li class="mb-1"><a href={"#"}>Twitter</a></li>
|
||||
<li class="mb-1"><a href={"#"}>Facebook</a></li>
|
||||
<li class="mb-1"><a href={"#"}>Instagram</a></li>
|
||||
<li class="mb-1"><a href={"#"}>LinkedIn</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,9 +1,11 @@
|
|||
import PageHome from '$/pages/site/Home.svelte'
|
||||
import PagePerfil from '$/pages/usuario/Perfil.svelte'
|
||||
import PageError from '$/pages/site/Error.svelte'
|
||||
import PageAplicaciones from '$/pages/aplicaciones/Admin.svelte'
|
||||
|
||||
export const routes = [
|
||||
{ path: '/', component: PageHome },
|
||||
{ path: '/perfil', component: PagePerfil },
|
||||
{ path: '/aplicaciones', component: PageAplicaciones },
|
||||
{ path: '*', component: PageError },
|
||||
]
|
|
@ -1,2 +1,2 @@
|
|||
export const base = import.meta.env.VITE_BACKEND || origin;
|
||||
export const base = import.meta.env.VITE_BACKEND || '/api';
|
||||
export const getToken = () => sessionStorage.getItem('token') || null;
|
|
@ -1,5 +1,19 @@
|
|||
import { base } from "./_config";
|
||||
import { base, getToken } from "./_config";
|
||||
|
||||
export async function getToken({ username, password }) {
|
||||
return 'token12345'
|
||||
export async function createToken({ username, password }) {
|
||||
const res = await fetch(`${base}/auth/`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ username, password }),
|
||||
headers: { "Content-Type": "application/json" }
|
||||
})
|
||||
if (!res.ok) throw await res.text()
|
||||
return res.json()
|
||||
}
|
||||
|
||||
export async function getInfoToken() {
|
||||
const res = await fetch(`${base}/auth/`, {
|
||||
headers: { "Authorization": `Bearer ${getToken()}`, "Content-Type": "application/json" }
|
||||
})
|
||||
if (!res.ok) throw await res.text()
|
||||
return res.json()
|
||||
}
|