Initial commit
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<router-view/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'app'
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,32 @@
|
||||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
import Router from 'vue-router'
|
||||
import {VuejsDatatableFactory} from 'vuejs-datatable';
|
||||
|
||||
import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome'
|
||||
|
||||
import store from './store'
|
||||
import routes from './routes'
|
||||
import "./icons"
|
||||
|
||||
Vue.component('FontAwesome', FontAwesomeIcon)
|
||||
Vue.config.productionTip = false
|
||||
|
||||
Vue.use(Router)
|
||||
|
||||
VuejsDatatableFactory.useDefaultType(false)
|
||||
.registerTableType('datatable', tableType => tableType.mergeSettings({
|
||||
table: {class: 'datatable table-fixed w-full'},
|
||||
}));
|
||||
Vue.use(VuejsDatatableFactory);
|
||||
|
||||
const router = new Router({
|
||||
mode: 'hash',
|
||||
routes
|
||||
})
|
||||
new Vue({
|
||||
render: h => h(App),
|
||||
router,
|
||||
store
|
||||
}).$mount('#app')
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<div class="leading-normal tracking-normal" id="main-body">
|
||||
<div class="flex flex-wrap">
|
||||
|
||||
<Sidebar/>
|
||||
|
||||
<div class="w-full bg-gray-100 pl-0 lg:pl-64 min-h-screen" :class="sideBarOpen ? 'overlay' : ''"
|
||||
id="main-content">
|
||||
|
||||
<Navbar/>
|
||||
|
||||
<div class="p-6 bg-gray-100 mb-20">
|
||||
<router-view/>
|
||||
</div>
|
||||
|
||||
<Footer/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
import Sidebar from './Sidebar'
|
||||
import Navbar from './Navbar'
|
||||
import Footer from './Footer'
|
||||
|
||||
export default {
|
||||
name: 'Dashboard',
|
||||
computed: {
|
||||
...mapState(['sideBarOpen'])
|
||||
},
|
||||
components: {
|
||||
Sidebar,
|
||||
Navbar,
|
||||
Footer
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,17 @@
|
||||
<template>
|
||||
<div class="w-full border-t-2 px-8 py-6 lg:flex justify-between items-center">
|
||||
<p class="mb-2 lg:mb-0">© Copyright 2020</p>
|
||||
|
||||
<div class="flex">
|
||||
<a href="#" class="mr-6 hover:text-gray-900">Terms of Service</a>
|
||||
<a href="#" class="mr-6 hover:text-gray-900">Privacy Policy</a>
|
||||
<a href="#" class="hover:text-gray-900">About Us</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Footer'
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<div class="sticky top-0 z-40">
|
||||
<div class="w-full h-20 px-6 bg-gray-100 border-b flex items-center justify-between">
|
||||
|
||||
<!-- left navbar -->
|
||||
<div class="flex">
|
||||
|
||||
<!-- mobile hamburger -->
|
||||
<div class="inline-block lg:hidden flex items-center mr-4">
|
||||
<button class="hover:text-blue-500 hover:border-white focus:outline-none navbar-burger"
|
||||
@click="toggleSidebar()">
|
||||
<svg class="h-5 w-5" v-bind:style="{ fill: 'black' }" viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"><title>Menu</title>
|
||||
<path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- search bar -->
|
||||
<div class="relative text-gray-600">
|
||||
<input type="search" name="serch" placeholder="Search products..."
|
||||
class="bg-white h-10 w-full xl:w-64 px-5 rounded-lg border text-sm focus:outline-none">
|
||||
<button type="submit" class="absolute right-0 top-0 mt-3 mr-4">
|
||||
<svg class="h-4 w-4 fill-current" 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"
|
||||
viewBox="0 0 56.966 56.966" style="enable-background:new 0 0 56.966 56.966;"
|
||||
xml:space="preserve" width="512px" height="512px">
|
||||
<path d="M55.146,51.887L41.588,37.786c3.486-4.144,5.396-9.358,5.396-14.786c0-12.682-10.318-23-23-23s-23,10.318-23,23 s10.318,23,23,23c4.761,0,9.298-1.436,13.177-4.162l13.661,14.208c0.571,0.593,1.339,0.92,2.162,0.92 c0.779,0,1.518-0.297,2.079-0.837C56.255,54.982,56.293,53.08,55.146,51.887z M23.984,6c9.374,0,17,7.626,17,17s-7.626,17-17,17 s-17-7.626-17-17S14.61,6,23.984,6z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- right navbar -->
|
||||
<div class="flex items-center relative">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"
|
||||
class="fill-current mr-3 hover:text-blue-500">
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.9 2 2 2zm6-6v-5c0-3.07-1.63-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.64 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2zm-2 1H8v-6c0-2.48 1.51-4.5 4-4.5s4 2.02 4 4.5v6z"/>
|
||||
</svg>
|
||||
<img src="https://a7sas.net/wp-content/uploads/2019/07/4060.jpeg"
|
||||
class="w-12 h-12 rounded-full shadow-lg" @click="dropDownOpen = !dropDownOpen">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- dropdown menu -->
|
||||
<div class="absolute bg-gray-100 border border-t-0 shadow-xl text-gray-700 rounded-b-lg w-48 bottom-10 right-0 mr-6"
|
||||
:class="dropDownOpen ? '' : 'hidden'">
|
||||
<a href="#" class="block px-4 py-2 hover:bg-gray-200">Account</a>
|
||||
<a href="#" class="block px-4 py-2 hover:bg-gray-200">Settings</a>
|
||||
<a href="#" class="block px-4 py-2 hover:bg-gray-200">Logout</a>
|
||||
</div>
|
||||
<!-- dropdown menu end -->
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Navbar',
|
||||
computed: {
|
||||
...mapState(['sideBarOpen'])
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dropDownOpen: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleSidebar() {
|
||||
this.$store.dispatch('toggleSidebar')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,148 @@
|
||||
<template>
|
||||
<!-- give the sidebar z-50 class so its higher than the navbar if you want to see the logo -->
|
||||
<!-- you will need to add a little "X" button next to the logo in order to close it though -->
|
||||
<div
|
||||
class="w-1/2 md:w-1/3 lg:w-64 fixed md:top-0 md:left-0 h-screen lg:block bg-gray-100 border-r z-30"
|
||||
:class="sideBarOpen ? '' : 'hidden'"
|
||||
id="main-nav"
|
||||
>
|
||||
<div class="w-full h-20 border-b flex px-4 items-center mb-8">
|
||||
<router-link to="/dashboard/home">
|
||||
<div class="font-semibold text-3xl text-blue-400 pl-4">LOGO</div>
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
<div class="mb-4 px-4">
|
||||
<p class="pl-4 text-sm font-semibold mb-1">MAIN</p>
|
||||
<router-link to="/dashboard/home">
|
||||
<div
|
||||
class="w-full flex items-center text-blue-400 h-10 pl-4 bg-gray-200 hover:bg-gray-200 rounded-lg cursor-pointer"
|
||||
>
|
||||
<svg class="h-6 w-6 fill-current mr-2" viewBox="0 0 20 20">
|
||||
<path
|
||||
d="M18.121,9.88l-7.832-7.836c-0.155-0.158-0.428-0.155-0.584,0L1.842,9.913c-0.262,0.263-0.073,0.705,0.292,0.705h2.069v7.042c0,0.227,0.187,0.414,0.414,0.414h3.725c0.228,0,0.414-0.188,0.414-0.414v-3.313h2.483v3.313c0,0.227,0.187,0.414,0.413,0.414h3.726c0.229,0,0.414-0.188,0.414-0.414v-7.042h2.068h0.004C18.331,10.617,18.389,10.146,18.121,9.88 M14.963,17.245h-2.896v-3.313c0-0.229-0.186-0.415-0.414-0.415H8.342c-0.228,0-0.414,0.187-0.414,0.415v3.313H5.032v-6.628h9.931V17.245z M3.133,9.79l6.864-6.868l6.867,6.868H3.133z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="text-gray-700">Dashboard</span>
|
||||
</div>
|
||||
</router-link>
|
||||
<div
|
||||
class="w-full flex items-center text-blue-400 h-10 pl-4 hover:bg-gray-200 rounded-lg cursor-pointer"
|
||||
>
|
||||
<svg class="h-6 w-6 fill-current mr-2" viewBox="0 0 20 20">
|
||||
<path
|
||||
d="M17.431,2.156h-3.715c-0.228,0-0.413,0.186-0.413,0.413v6.973h-2.89V6.687c0-0.229-0.186-0.413-0.413-0.413H6.285c-0.228,0-0.413,0.184-0.413,0.413v6.388H2.569c-0.227,0-0.413,0.187-0.413,0.413v3.942c0,0.228,0.186,0.413,0.413,0.413h14.862c0.228,0,0.413-0.186,0.413-0.413V2.569C17.844,2.342,17.658,2.156,17.431,2.156 M5.872,17.019h-2.89v-3.117h2.89V17.019zM9.587,17.019h-2.89V7.1h2.89V17.019z M13.303,17.019h-2.89v-6.651h2.89V17.019z M17.019,17.019h-2.891V2.982h2.891V17.019z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="text-gray-700">Analytics</span>
|
||||
</div>
|
||||
<div
|
||||
class="w-full flex items-center text-blue-400 h-10 pl-4 hover:bg-gray-200 rounded-lg cursor-pointer"
|
||||
>
|
||||
<svg class="h-6 w-6 fill-current mr-2" viewBox="0 0 20 20">
|
||||
<path
|
||||
d="M17.283,5.549h-5.26V4.335c0-0.222-0.183-0.404-0.404-0.404H8.381c-0.222,0-0.404,0.182-0.404,0.404v1.214h-5.26c-0.223,0-0.405,0.182-0.405,0.405v9.71c0,0.223,0.182,0.405,0.405,0.405h14.566c0.223,0,0.404-0.183,0.404-0.405v-9.71C17.688,5.731,17.506,5.549,17.283,5.549 M8.786,4.74h2.428v0.809H8.786V4.74z M16.879,15.26H3.122v-4.046h5.665v1.201c0,0.223,0.182,0.404,0.405,0.404h1.618c0.222,0,0.405-0.182,0.405-0.404v-1.201h5.665V15.26z M9.595,9.583h0.81v2.428h-0.81V9.583zM16.879,10.405h-5.665V9.19c0-0.222-0.183-0.405-0.405-0.405H9.191c-0.223,0-0.405,0.183-0.405,0.405v1.215H3.122V6.358h13.757V10.405z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="text-gray-700">Inventory</span>
|
||||
</div>
|
||||
<div
|
||||
class="w-full flex items-center text-blue-400 h-10 pl-4 hover:bg-gray-200 rounded-lg cursor-pointer"
|
||||
>
|
||||
<svg class="h-6 w-6 fill-current mr-2" viewBox="0 0 20 20">
|
||||
<path
|
||||
d="M18.303,4.742l-1.454-1.455c-0.171-0.171-0.475-0.171-0.646,0l-3.061,3.064H2.019c-0.251,0-0.457,0.205-0.457,0.456v9.578c0,0.251,0.206,0.456,0.457,0.456h13.683c0.252,0,0.457-0.205,0.457-0.456V7.533l2.144-2.146C18.481,5.208,18.483,4.917,18.303,4.742 M15.258,15.929H2.476V7.263h9.754L9.695,9.792c-0.057,0.057-0.101,0.13-0.119,0.212L9.18,11.36h-3.98c-0.251,0-0.457,0.205-0.457,0.456c0,0.253,0.205,0.456,0.457,0.456h4.336c0.023,0,0.899,0.02,1.498-0.127c0.312-0.077,0.55-0.137,0.55-0.137c0.08-0.018,0.155-0.059,0.212-0.118l3.463-3.443V15.929z M11.241,11.156l-1.078,0.267l0.267-1.076l6.097-6.091l0.808,0.808L11.241,11.156z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="text-gray-700">Enquiries</span>
|
||||
</div>
|
||||
<div
|
||||
class="w-full flex items-center text-blue-400 h-10 pl-4 hover:bg-gray-200 rounded-lg cursor-pointer"
|
||||
>
|
||||
<svg class="h-6 w-6 fill-current mr-2" viewBox="0 0 20 20">
|
||||
<path
|
||||
d="M16.557,4.467h-1.64v-0.82c0-0.225-0.183-0.41-0.409-0.41c-0.226,0-0.41,0.185-0.41,0.41v0.82H5.901v-0.82c0-0.225-0.185-0.41-0.41-0.41c-0.226,0-0.41,0.185-0.41,0.41v0.82H3.442c-0.904,0-1.64,0.735-1.64,1.639v9.017c0,0.904,0.736,1.64,1.64,1.64h13.114c0.904,0,1.64-0.735,1.64-1.64V6.106C18.196,5.203,17.461,4.467,16.557,4.467 M17.377,15.123c0,0.453-0.366,0.819-0.82,0.819H3.442c-0.453,0-0.82-0.366-0.82-0.819V8.976h14.754V15.123z M17.377,8.156H2.623V6.106c0-0.453,0.367-0.82,0.82-0.82h1.639v1.23c0,0.225,0.184,0.41,0.41,0.41c0.225,0,0.41-0.185,0.41-0.41v-1.23h8.196v1.23c0,0.225,0.185,0.41,0.41,0.41c0.227,0,0.409-0.185,0.409-0.41v-1.23h1.64c0.454,0,0.82,0.367,0.82,0.82V8.156z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="text-gray-700">Calender</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4 px-4">
|
||||
<p class="pl-4 text-sm font-semibold mb-1">PRODUCTS</p>
|
||||
<div
|
||||
class="w-full flex items-center text-blue-400 h-10 pl-4 hover:bg-gray-200 rounded-lg cursor-pointer"
|
||||
>
|
||||
<svg class="h-6 w-6 fill-current mr-2" viewBox="0 0 20 20">
|
||||
<path
|
||||
d="M14.613,10c0,0.23-0.188,0.419-0.419,0.419H10.42v3.774c0,0.23-0.189,0.42-0.42,0.42s-0.419-0.189-0.419-0.42v-3.774H5.806c-0.23,0-0.419-0.189-0.419-0.419s0.189-0.419,0.419-0.419h3.775V5.806c0-0.23,0.189-0.419,0.419-0.419s0.42,0.189,0.42,0.419v3.775h3.774C14.425,9.581,14.613,9.77,14.613,10 M17.969,10c0,4.401-3.567,7.969-7.969,7.969c-4.402,0-7.969-3.567-7.969-7.969c0-4.402,3.567-7.969,7.969-7.969C14.401,2.031,17.969,5.598,17.969,10 M17.13,10c0-3.932-3.198-7.13-7.13-7.13S2.87,6.068,2.87,10c0,3.933,3.198,7.13,7.13,7.13S17.13,13.933,17.13,10"
|
||||
/>
|
||||
</svg>
|
||||
<span class="text-gray-700">Add Product</span>
|
||||
</div>
|
||||
<div
|
||||
class="w-full flex items-center text-blue-400 h-10 pl-4 hover:bg-gray-200 rounded-lg cursor-pointer"
|
||||
>
|
||||
<svg class="h-6 w-6 fill-current mr-2" viewBox="0 0 20 20">
|
||||
<path
|
||||
d="M15.396,2.292H4.604c-0.212,0-0.385,0.174-0.385,0.386v14.646c0,0.212,0.173,0.385,0.385,0.385h10.792c0.211,0,0.385-0.173,0.385-0.385V2.677C15.781,2.465,15.607,2.292,15.396,2.292 M15.01,16.938H4.99v-2.698h1.609c0.156,0.449,0.586,0.771,1.089,0.771c0.638,0,1.156-0.519,1.156-1.156s-0.519-1.156-1.156-1.156c-0.503,0-0.933,0.321-1.089,0.771H4.99v-3.083h1.609c0.156,0.449,0.586,0.771,1.089,0.771c0.638,0,1.156-0.518,1.156-1.156c0-0.638-0.519-1.156-1.156-1.156c-0.503,0-0.933,0.322-1.089,0.771H4.99V6.531h1.609C6.755,6.98,7.185,7.302,7.688,7.302c0.638,0,1.156-0.519,1.156-1.156c0-0.638-0.519-1.156-1.156-1.156c-0.503,0-0.933,0.322-1.089,0.771H4.99V3.062h10.02V16.938z M7.302,13.854c0-0.212,0.173-0.386,0.385-0.386s0.385,0.174,0.385,0.386s-0.173,0.385-0.385,0.385S7.302,14.066,7.302,13.854 M7.302,10c0-0.212,0.173-0.385,0.385-0.385S8.073,9.788,8.073,10s-0.173,0.385-0.385,0.385S7.302,10.212,7.302,10 M7.302,6.146c0-0.212,0.173-0.386,0.385-0.386s0.385,0.174,0.385,0.386S7.899,6.531,7.688,6.531S7.302,6.358,7.302,6.146"
|
||||
/>
|
||||
</svg>
|
||||
<span class="text-gray-700">View Products</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4 px-4">
|
||||
<p class="pl-4 text-sm font-semibold mb-1">MISC</p>
|
||||
<div
|
||||
class="w-full flex items-center text-blue-400 h-10 pl-4 hover:bg-gray-200 rounded-lg cursor-pointer"
|
||||
>
|
||||
<svg class="h-6 w-6 fill-current mr-2" viewBox="0 0 20 20">
|
||||
<path
|
||||
d="M17.592,8.936l-6.531-6.534c-0.593-0.631-0.751-0.245-0.751,0.056l0.002,2.999L5.427,9.075H2.491c-0.839,0-0.162,0.901-0.311,0.752l3.683,3.678l-3.081,3.108c-0.17,0.171-0.17,0.449,0,0.62c0.169,0.17,0.448,0.17,0.618,0l3.098-3.093l3.675,3.685c-0.099-0.099,0.773,0.474,0.773-0.296v-2.965l3.601-4.872l2.734-0.005C17.73,9.688,18.326,9.669,17.592,8.936 M3.534,9.904h1.906l4.659,4.66v1.906L3.534,9.904z M10.522,13.717L6.287,9.48l4.325-3.124l3.088,3.124L10.522,13.717z M14.335,8.845l-3.177-3.177V3.762l5.083,5.083H14.335z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="text-gray-700">Notices</span>
|
||||
</div>
|
||||
<div
|
||||
class="w-full flex items-center text-blue-400 h-10 pl-4 hover:bg-gray-200 rounded-lg cursor-pointer"
|
||||
>
|
||||
<svg class="h-6 w-6 fill-current mr-2" viewBox="0 0 20 20">
|
||||
<path
|
||||
d="M6.176,7.241V6.78c0-0.221-0.181-0.402-0.402-0.402c-0.221,0-0.403,0.181-0.403,0.402v0.461C4.79,7.416,4.365,7.955,4.365,8.591c0,0.636,0.424,1.175,1.006,1.35v3.278c0,0.222,0.182,0.402,0.403,0.402c0.222,0,0.402-0.181,0.402-0.402V9.941c0.582-0.175,1.006-0.714,1.006-1.35C7.183,7.955,6.758,7.416,6.176,7.241 M5.774,9.195c-0.332,0-0.604-0.272-0.604-0.604c0-0.332,0.272-0.604,0.604-0.604c0.332,0,0.604,0.272,0.604,0.604C6.377,8.923,6.105,9.195,5.774,9.195 M10.402,10.058V6.78c0-0.221-0.181-0.402-0.402-0.402c-0.222,0-0.402,0.181-0.402,0.402v3.278c-0.582,0.175-1.006,0.714-1.006,1.35c0,0.637,0.424,1.175,1.006,1.351v0.461c0,0.222,0.181,0.402,0.402,0.402c0.221,0,0.402-0.181,0.402-0.402v-0.461c0.582-0.176,1.006-0.714,1.006-1.351C11.408,10.772,10.984,10.233,10.402,10.058M10,12.013c-0.333,0-0.604-0.272-0.604-0.604S9.667,10.805,10,10.805c0.332,0,0.604,0.271,0.604,0.604S10.332,12.013,10,12.013M14.629,8.448V6.78c0-0.221-0.182-0.402-0.403-0.402c-0.221,0-0.402,0.181-0.402,0.402v1.668c-0.581,0.175-1.006,0.714-1.006,1.35c0,0.636,0.425,1.176,1.006,1.351v2.07c0,0.222,0.182,0.402,0.402,0.402c0.222,0,0.403-0.181,0.403-0.402v-2.07c0.581-0.175,1.006-0.715,1.006-1.351C15.635,9.163,15.21,8.624,14.629,8.448 M14.226,10.402c-0.331,0-0.604-0.272-0.604-0.604c0-0.332,0.272-0.604,0.604-0.604c0.332,0,0.604,0.272,0.604,0.604C14.83,10.13,14.558,10.402,14.226,10.402 M17.647,3.962H2.353c-0.221,0-0.402,0.181-0.402,0.402v11.27c0,0.222,0.181,0.402,0.402,0.402h15.295c0.222,0,0.402-0.181,0.402-0.402V4.365C18.05,4.144,17.869,3.962,17.647,3.962 M17.245,15.232H2.755V4.768h14.49V15.232z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="text-gray-700">Controls</span>
|
||||
</div>
|
||||
<div
|
||||
class="w-full flex items-center text-blue-400 h-10 pl-4 hover:bg-gray-200 rounded-lg cursor-pointer"
|
||||
>
|
||||
<svg class="h-6 w-6 fill-current mr-2" viewBox="0 0 20 20">
|
||||
<path
|
||||
d="M17.498,11.697c-0.453-0.453-0.704-1.055-0.704-1.697c0-0.642,0.251-1.244,0.704-1.697c0.069-0.071,0.15-0.141,0.257-0.22c0.127-0.097,0.181-0.262,0.137-0.417c-0.164-0.558-0.388-1.093-0.662-1.597c-0.075-0.141-0.231-0.22-0.391-0.199c-0.13,0.02-0.238,0.027-0.336,0.027c-1.325,0-2.401-1.076-2.401-2.4c0-0.099,0.008-0.207,0.027-0.336c0.021-0.158-0.059-0.316-0.199-0.391c-0.503-0.274-1.039-0.498-1.597-0.662c-0.154-0.044-0.32,0.01-0.416,0.137c-0.079,0.106-0.148,0.188-0.22,0.257C11.244,2.956,10.643,3.207,10,3.207c-0.642,0-1.244-0.25-1.697-0.704c-0.071-0.069-0.141-0.15-0.22-0.257C7.987,2.119,7.821,2.065,7.667,2.109C7.109,2.275,6.571,2.497,6.07,2.771C5.929,2.846,5.85,3.004,5.871,3.162c0.02,0.129,0.027,0.237,0.027,0.336c0,1.325-1.076,2.4-2.401,2.4c-0.098,0-0.206-0.007-0.335-0.027C3.001,5.851,2.845,5.929,2.77,6.07C2.496,6.572,2.274,7.109,2.108,7.667c-0.044,0.154,0.01,0.32,0.137,0.417c0.106,0.079,0.187,0.148,0.256,0.22c0.938,0.936,0.938,2.458,0,3.394c-0.069,0.072-0.15,0.141-0.256,0.221c-0.127,0.096-0.181,0.262-0.137,0.416c0.166,0.557,0.388,1.096,0.662,1.596c0.075,0.143,0.231,0.221,0.392,0.199c0.129-0.02,0.237-0.027,0.335-0.027c1.325,0,2.401,1.076,2.401,2.402c0,0.098-0.007,0.205-0.027,0.334C5.85,16.996,5.929,17.154,6.07,17.23c0.501,0.273,1.04,0.496,1.597,0.66c0.154,0.047,0.32-0.008,0.417-0.137c0.079-0.105,0.148-0.186,0.22-0.256c0.454-0.453,1.055-0.703,1.697-0.703c0.643,0,1.244,0.25,1.697,0.703c0.071,0.07,0.141,0.15,0.22,0.256c0.073,0.098,0.188,0.152,0.307,0.152c0.036,0,0.073-0.004,0.109-0.016c0.558-0.164,1.096-0.387,1.597-0.66c0.141-0.076,0.22-0.234,0.199-0.393c-0.02-0.129-0.027-0.236-0.027-0.334c0-1.326,1.076-2.402,2.401-2.402c0.098,0,0.206,0.008,0.336,0.027c0.159,0.021,0.315-0.057,0.391-0.199c0.274-0.5,0.496-1.039,0.662-1.596c0.044-0.154-0.01-0.32-0.137-0.416C17.648,11.838,17.567,11.77,17.498,11.697 M16.671,13.334c-0.059-0.002-0.114-0.002-0.168-0.002c-1.749,0-3.173,1.422-3.173,3.172c0,0.053,0.002,0.109,0.004,0.166c-0.312,0.158-0.64,0.295-0.976,0.406c-0.039-0.045-0.077-0.086-0.115-0.123c-0.601-0.6-1.396-0.93-2.243-0.93s-1.643,0.33-2.243,0.93c-0.039,0.037-0.077,0.078-0.116,0.123c-0.336-0.111-0.664-0.248-0.976-0.406c0.002-0.057,0.004-0.113,0.004-0.166c0-1.75-1.423-3.172-3.172-3.172c-0.054,0-0.11,0-0.168,0.002c-0.158-0.312-0.293-0.639-0.405-0.975c0.044-0.039,0.085-0.078,0.124-0.115c1.236-1.236,1.236-3.25,0-4.486C3.009,7.719,2.969,7.68,2.924,7.642c0.112-0.336,0.247-0.664,0.405-0.976C3.387,6.668,3.443,6.67,3.497,6.67c1.75,0,3.172-1.423,3.172-3.172c0-0.054-0.002-0.11-0.004-0.168c0.312-0.158,0.64-0.293,0.976-0.405C7.68,2.969,7.719,3.01,7.757,3.048c0.6,0.6,1.396,0.93,2.243,0.93s1.643-0.33,2.243-0.93c0.038-0.039,0.076-0.079,0.115-0.123c0.336,0.112,0.663,0.247,0.976,0.405c-0.002,0.058-0.004,0.114-0.004,0.168c0,1.749,1.424,3.172,3.173,3.172c0.054,0,0.109-0.002,0.168-0.004c0.158,0.312,0.293,0.64,0.405,0.976c-0.045,0.038-0.086,0.077-0.124,0.116c-0.6,0.6-0.93,1.396-0.93,2.242c0,0.847,0.33,1.645,0.93,2.244c0.038,0.037,0.079,0.076,0.124,0.115C16.964,12.695,16.829,13.021,16.671,13.334 M10,5.417c-2.528,0-4.584,2.056-4.584,4.583c0,2.529,2.056,4.584,4.584,4.584s4.584-2.055,4.584-4.584C14.584,7.472,12.528,5.417,10,5.417 M10,13.812c-2.102,0-3.812-1.709-3.812-3.812c0-2.102,1.71-3.812,3.812-3.812c2.102,0,3.812,1.71,3.812,3.812C13.812,12.104,12.102,13.812,10,13.812"
|
||||
/>
|
||||
</svg>
|
||||
<span class="text-gray-700">Settings</span>
|
||||
</div>
|
||||
<router-link to="/dashboard/user">
|
||||
<div
|
||||
class="w-full flex items-center text-blue-400 h-10 pl-4 hover:bg-gray-200 rounded-lg cursor-pointer"
|
||||
>
|
||||
<FontAwesome class="h-6 w-6 fill-current mr-3" icon="users"/>
|
||||
<span class="text-gray-700">Users</span>
|
||||
</div>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
|
||||
export default {
|
||||
name: "Sidebar",
|
||||
computed: {
|
||||
...mapState(["sideBarOpen"])
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,28 @@
|
||||
import {library} from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faUsers,
|
||||
faHome,
|
||||
faChartBar,
|
||||
faBriefcase,
|
||||
faPencilAlt,
|
||||
faCalendarAlt,
|
||||
faPlusCircle,
|
||||
faClipboardList,
|
||||
faThumbtack,
|
||||
faSlidersH,
|
||||
faCogs,
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
faUsers,
|
||||
faHome,
|
||||
faChartBar,
|
||||
faBriefcase,
|
||||
faPencilAlt,
|
||||
faCalendarAlt,
|
||||
faPlusCircle,
|
||||
faClipboardList,
|
||||
faThumbtack,
|
||||
faSlidersH,
|
||||
faCogs,
|
||||
)
|
||||
@@ -0,0 +1,294 @@
|
||||
<template>
|
||||
<div id="home">
|
||||
|
||||
<!-- breadcrumb -->
|
||||
<nav class="text-sm font-semibold mb-6" aria-label="Breadcrumb">
|
||||
<ol class="list-none p-0 inline-flex">
|
||||
<li class="flex items-center text-blue-500">
|
||||
<a href="#" class="text-gray-700">Home</a>
|
||||
<svg class="fill-current w-3 h-3 mx-3" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
|
||||
<path d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z"/>
|
||||
</svg>
|
||||
</li>
|
||||
<li class="flex items-center">
|
||||
<a href="#" class="text-gray-600">Dashboard</a>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
<!-- breadcrumb end -->
|
||||
|
||||
<div class="lg:flex justify-between items-center mb-6">
|
||||
<p class="text-2xl font-semibold mb-2 lg:mb-0">Good afternoon, Joe!</p>
|
||||
<button class="bg-blue-500 hover:bg-blue-600 focus:outline-none rounded-lg px-6 py-2 text-white font-semibold shadow">
|
||||
View Logs
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap -mx-3 mb-20">
|
||||
|
||||
<div class="w-1/2 xl:w-1/4 px-3">
|
||||
<div class="w-full bg-white border text-blue-400 rounded-lg flex items-center p-6 mb-6 xl:mb-0">
|
||||
<svg class="w-16 h-16 fill-current mr-4 hidden lg:block" viewBox="0 0 20 20">
|
||||
<path d="M17.35,2.219h-5.934c-0.115,0-0.225,0.045-0.307,0.128l-8.762,8.762c-0.171,0.168-0.171,0.443,0,0.611l5.933,5.934c0.167,0.171,0.443,0.169,0.612,0l8.762-8.763c0.083-0.083,0.128-0.192,0.128-0.307V2.651C17.781,2.414,17.587,2.219,17.35,2.219M16.916,8.405l-8.332,8.332l-5.321-5.321l8.333-8.332h5.32V8.405z M13.891,4.367c-0.957,0-1.729,0.772-1.729,1.729c0,0.957,0.771,1.729,1.729,1.729s1.729-0.772,1.729-1.729C15.619,5.14,14.848,4.367,13.891,4.367 M14.502,6.708c-0.326,0.326-0.896,0.326-1.223,0c-0.338-0.342-0.338-0.882,0-1.224c0.342-0.337,0.881-0.337,1.223,0C14.84,5.826,14.84,6.366,14.502,6.708"></path>
|
||||
</svg>
|
||||
|
||||
<div class="text-gray-700">
|
||||
<p class="font-semibold text-3xl">237</p>
|
||||
<p>Products Sold</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="w-1/2 xl:w-1/4 px-3">
|
||||
<div class="w-full bg-white border text-blue-400 rounded-lg flex items-center p-6 mb-6 xl:mb-0">
|
||||
<svg class="w-16 h-16 fill-current mr-4 hidden lg:block" viewBox="0 0 20 20">
|
||||
<path d="M17.684,7.925l-5.131-0.67L10.329,2.57c-0.131-0.275-0.527-0.275-0.658,0L7.447,7.255l-5.131,0.67C2.014,7.964,1.892,8.333,2.113,8.54l3.76,3.568L4.924,17.21c-0.056,0.297,0.261,0.525,0.533,0.379L10,15.109l4.543,2.479c0.273,0.153,0.587-0.089,0.533-0.379l-0.949-5.103l3.76-3.568C18.108,8.333,17.986,7.964,17.684,7.925 M13.481,11.723c-0.089,0.083-0.129,0.205-0.105,0.324l0.848,4.547l-4.047-2.208c-0.055-0.03-0.116-0.045-0.176-0.045s-0.122,0.015-0.176,0.045l-4.047,2.208l0.847-4.547c0.023-0.119-0.016-0.241-0.105-0.324L3.162,8.54L7.74,7.941c0.124-0.016,0.229-0.093,0.282-0.203L10,3.568l1.978,4.17c0.053,0.11,0.158,0.187,0.282,0.203l4.578,0.598L13.481,11.723z"></path>
|
||||
</svg>
|
||||
|
||||
<div class="text-gray-700">
|
||||
<p class="font-semibold text-3xl">177</p>
|
||||
<p>Product Reviews</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="w-1/2 xl:w-1/4 px-3">
|
||||
<div class="w-full bg-white border text-blue-400 rounded-lg flex items-center p-6">
|
||||
<svg class="w-16 h-16 fill-current mr-4 hidden lg:block" viewBox="0 0 20 20">
|
||||
<path d="M14.999,8.543c0,0.229-0.188,0.417-0.416,0.417H5.417C5.187,8.959,5,8.772,5,8.543s0.188-0.417,0.417-0.417h9.167C14.812,8.126,14.999,8.314,14.999,8.543 M12.037,10.213H5.417C5.187,10.213,5,10.4,5,10.63c0,0.229,0.188,0.416,0.417,0.416h6.621c0.229,0,0.416-0.188,0.416-0.416C12.453,10.4,12.266,10.213,12.037,10.213 M14.583,6.046H5.417C5.187,6.046,5,6.233,5,6.463c0,0.229,0.188,0.417,0.417,0.417h9.167c0.229,0,0.416-0.188,0.416-0.417C14.999,6.233,14.812,6.046,14.583,6.046 M17.916,3.542v10c0,0.229-0.188,0.417-0.417,0.417H9.373l-2.829,2.796c-0.117,0.116-0.71,0.297-0.71-0.296v-2.5H2.5c-0.229,0-0.417-0.188-0.417-0.417v-10c0-0.229,0.188-0.417,0.417-0.417h15C17.729,3.126,17.916,3.313,17.916,3.542 M17.083,3.959H2.917v9.167H6.25c0.229,0,0.417,0.187,0.417,0.416v1.919l2.242-2.215c0.079-0.077,0.184-0.12,0.294-0.12h7.881V3.959z"></path>
|
||||
</svg>
|
||||
|
||||
<div class="text-gray-700">
|
||||
<p class="font-semibold text-3xl">31</p>
|
||||
<p>New Enquiries</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="w-1/2 xl:w-1/4 px-3">
|
||||
<div class="w-full bg-white border text-blue-400 rounded-lg flex items-center p-6">
|
||||
<svg class="w-16 h-16 fill-current mr-4 hidden lg:block" viewBox="0 0 20 20">
|
||||
<path d="M17.431,2.156h-3.715c-0.228,0-0.413,0.186-0.413,0.413v6.973h-2.89V6.687c0-0.229-0.186-0.413-0.413-0.413H6.285c-0.228,0-0.413,0.184-0.413,0.413v6.388H2.569c-0.227,0-0.413,0.187-0.413,0.413v3.942c0,0.228,0.186,0.413,0.413,0.413h14.862c0.228,0,0.413-0.186,0.413-0.413V2.569C17.844,2.342,17.658,2.156,17.431,2.156 M5.872,17.019h-2.89v-3.117h2.89V17.019zM9.587,17.019h-2.89V7.1h2.89V17.019z M13.303,17.019h-2.89v-6.651h2.89V17.019z M17.019,17.019h-2.891V2.982h2.891V17.019z"></path>
|
||||
</svg>
|
||||
|
||||
<div class="text-gray-700">
|
||||
<p class="font-semibold text-3xl">1,653</p>
|
||||
<p>Product Views</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<section class="text-gray-700 body-font">
|
||||
<div class="container px-5 py-24 mx-auto">
|
||||
<div class="flex flex-col text-center w-full mb-20">
|
||||
<h1 class="sm:text-3xl text-2xl font-medium title-font mb-4 text-gray-900">Master Cleanse Reliac
|
||||
Heirloom</h1>
|
||||
<p class="lg:w-2/3 mx-auto leading-relaxed ">Whatever cardigan tote bag tumblr hexagon
|
||||
brooklyn asymmetrical gentrify, subway tile poke farm-to-table. Franzen you probably haven't
|
||||
heard of them man bun deep jianbing selfies heirloom prism food truck ugh squid celiac
|
||||
humblebrag.</p>
|
||||
</div>
|
||||
<div class="flex flex-wrap -m-4 text-center">
|
||||
<div class="p-4 md:w-1/4 sm:w-1/2 w-full">
|
||||
<div class="border-2 border-gray-200 px-4 py-6 rounded-lg">
|
||||
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||
stroke-width="2" class="text-indigo-500 w-12 h-12 mb-3 inline-block"
|
||||
viewBox="0 0 24 24">
|
||||
<path d="M8 17l4 4 4-4m-4-5v9"></path>
|
||||
<path d="M20.88 18.09A5 5 0 0018 9h-1.26A8 8 0 103 16.29"></path>
|
||||
</svg>
|
||||
<h2 class="title-font font-medium text-3xl text-gray-900">2.7K</h2>
|
||||
<p class="leading-relaxed">Downloads</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4 md:w-1/4 sm:w-1/2 w-full">
|
||||
<div class="border-2 border-gray-200 px-4 py-6 rounded-lg">
|
||||
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||
stroke-width="2" class="text-indigo-500 w-12 h-12 mb-3 inline-block"
|
||||
viewBox="0 0 24 24">
|
||||
<path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2"></path>
|
||||
<circle cx="9" cy="7" r="4"></circle>
|
||||
<path d="M23 21v-2a4 4 0 00-3-3.87m-4-12a4 4 0 010 7.75"></path>
|
||||
</svg>
|
||||
<h2 class="title-font font-medium text-3xl text-gray-900">1.3K</h2>
|
||||
<p class="leading-relaxed">Users</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4 md:w-1/4 sm:w-1/2 w-full">
|
||||
<div class="border-2 border-gray-200 px-4 py-6 rounded-lg">
|
||||
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||
stroke-width="2" class="text-indigo-500 w-12 h-12 mb-3 inline-block"
|
||||
viewBox="0 0 24 24">
|
||||
<path d="M3 18v-6a9 9 0 0118 0v6"></path>
|
||||
<path d="M21 19a2 2 0 01-2 2h-1a2 2 0 01-2-2v-3a2 2 0 012-2h3zM3 19a2 2 0 002 2h1a2 2 0 002-2v-3a2 2 0 00-2-2H3z"></path>
|
||||
</svg>
|
||||
<h2 class="title-font font-medium text-3xl text-gray-900">74</h2>
|
||||
<p class="leading-relaxed">Files</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4 md:w-1/4 sm:w-1/2 w-full">
|
||||
<div class="border-2 border-gray-200 px-4 py-6 rounded-lg">
|
||||
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||
stroke-width="2" class="text-indigo-500 w-12 h-12 mb-3 inline-block"
|
||||
viewBox="0 0 24 24">
|
||||
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path>
|
||||
</svg>
|
||||
<h2 class="title-font font-medium text-3xl text-gray-900">46</h2>
|
||||
<p class="leading-relaxed">Places</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap -mx-3">
|
||||
|
||||
<div class="w-full xl:w-1/3 px-3">
|
||||
<p class="text-xl font-semibold mb-4">Recent Sales</p>
|
||||
|
||||
<div class="w-full bg-white border rounded-lg p-4 mb-8 xl:mb-0">
|
||||
<canvas id="buyers-chart" width="600" height="400"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="w-full xl:w-1/3 px-3">
|
||||
<p class="text-xl font-semibold mb-4">Recent Reviews</p>
|
||||
|
||||
<div class="w-full bg-white border rounded-lg p-4 mb-8 xl:mb-0">
|
||||
<canvas id="reviews-chart" width="600" height="400"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="w-full xl:w-1/3 px-3">
|
||||
<p class="text-xl font-semibold mb-4">Recent Transactions</p>
|
||||
<div class="w-full bg-white border rounded-lg p-4">
|
||||
<div class="w-full bg-gray-100 border rounded-lg flex justify-between items-center px-4 py-2 mb-4">
|
||||
<div>
|
||||
<p class="font-semibold text-xl">Trent Murphy</p>
|
||||
<p>Product 1</p>
|
||||
</div>
|
||||
<span class="text-green-500 font-semibold text-lg">$25.00</span>
|
||||
</div>
|
||||
|
||||
<div class="w-full bg-gray-100 border rounded-lg flex justify-between items-center px-4 py-2 mb-4">
|
||||
<div>
|
||||
<p class="font-semibold text-xl">Joseph Brent</p>
|
||||
<p>Product 34</p>
|
||||
</div>
|
||||
<span class="text-red-500 font-semibold text-lg">$74.99</span>
|
||||
</div>
|
||||
|
||||
<div class="w-full bg-gray-100 border rounded-lg flex justify-between items-center px-4 py-2 mb-4">
|
||||
<div>
|
||||
<p class="font-semibold text-xl">Jacob Bator</p>
|
||||
<p>Product 23</p>
|
||||
</div>
|
||||
<span class="text-green-500 font-semibold text-lg">$14.95</span>
|
||||
</div>
|
||||
|
||||
<div class="w-full bg-gray-100 border rounded-lg flex justify-between items-center px-4 py-2">
|
||||
<div>
|
||||
<p class="font-semibold text-xl">Alex Mason</p>
|
||||
<p>Product 66</p>
|
||||
</div>
|
||||
<span class="text-green-500 font-semibold text-lg">$44.99</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Chart from 'chart.js'
|
||||
|
||||
export default {
|
||||
name: 'DashboardHome',
|
||||
data() {
|
||||
return {
|
||||
buyersData: {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
|
||||
datasets: [{
|
||||
backgroundColor: "rgba(99,179,237,0.4)",
|
||||
strokeColor: "#63b3ed",
|
||||
pointColor: "#fff",
|
||||
pointStrokeColor: "#63b3ed",
|
||||
data: [203, 156, 99, 251, 305, 247, 256]
|
||||
},
|
||||
{
|
||||
backgroundColor: "rgba(198,198,198,0.4)",
|
||||
strokeColor: "#f7fafc",
|
||||
pointColor: "#fff",
|
||||
pointStrokeColor: "#f7fafc",
|
||||
data: [86, 97, 144, 114, 94, 108, 156]
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
scales: {
|
||||
yAxes: [{
|
||||
gridLines: {
|
||||
display: false
|
||||
},
|
||||
ticks: {
|
||||
display: false
|
||||
}
|
||||
}],
|
||||
xAxes: [{
|
||||
gridLines: {
|
||||
display: false
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
reviewsData: {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
|
||||
datasets: [{
|
||||
backgroundColor: "rgba(99,179,237,0.4)",
|
||||
strokeColor: "#63b3ed",
|
||||
pointColor: "#fff",
|
||||
pointStrokeColor: "#63b3ed",
|
||||
data: [203, 156, 99, 251, 305, 247, 256]
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
scales: {
|
||||
yAxes: [{
|
||||
gridLines: {
|
||||
display: false
|
||||
},
|
||||
ticks: {
|
||||
display: false
|
||||
}
|
||||
}],
|
||||
xAxes: [{
|
||||
gridLines: {
|
||||
display: false
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
new Chart(document.getElementById('buyers-chart'), this.buyersData)
|
||||
new Chart(document.getElementById('reviews-chart'), this.reviewsData)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<div id="user">
|
||||
<nav class="text-sm font-semibold mb-6" aria-label="Breadcrumb">
|
||||
<ol class="list-none p-0 inline-flex">
|
||||
<li class="flex items-center text-blue-500">
|
||||
<a href="#" class="text-gray-700">Home</a>
|
||||
<svg
|
||||
class="fill-current w-3 h-3 mx-3"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 320 512"
|
||||
>
|
||||
<path
|
||||
d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z"
|
||||
/>
|
||||
</svg>
|
||||
</li>
|
||||
<li class="flex items-center">
|
||||
<a href="#" class="text-gray-600">Users</a>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
<div class="lg:flex justify-between items-center mb-6">
|
||||
<p class="text-2xl font-semibold mb-2 lg:mb-0">Users</p>
|
||||
</div>
|
||||
<div class="flex flex-wrap -mx-3 mb-20">
|
||||
<div class="w-full xl:w-full px-3">
|
||||
<div class="w-full bg-white border rounded-lg flex items-center p-6 mb-6 xl:mb-0">
|
||||
<div v-if="loading" class="loading">Loading...</div>
|
||||
<datatable v-else :columns="columns" :data="rows"></datatable>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {GetUserList} from "../store/api/users";
|
||||
|
||||
export default {
|
||||
data: () => ({
|
||||
loading: false,
|
||||
columns: [
|
||||
{label: "#", field: "num", headerClass: "w-1/6"},
|
||||
{
|
||||
label: "Name",
|
||||
field: "name"
|
||||
},
|
||||
{
|
||||
label: "Age",
|
||||
field: "age"
|
||||
}
|
||||
],
|
||||
rows: []
|
||||
}),
|
||||
created() {
|
||||
this.fetchData();
|
||||
},
|
||||
watch: {
|
||||
// call again the method if the route changes
|
||||
$route: "fetchData"
|
||||
},
|
||||
methods: {
|
||||
fetchData() {
|
||||
this.loading = true;
|
||||
GetUserList()
|
||||
.then(({data}) => {
|
||||
this.loading = false;
|
||||
for (let i in data) {
|
||||
data[i].num = parseInt(i) + 1;
|
||||
}
|
||||
this.rows = data;
|
||||
})
|
||||
.error(err => {
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,116 @@
|
||||
paypal.Buttons({
|
||||
|
||||
// Set your environment
|
||||
env: paypal_env,
|
||||
|
||||
// Set style of buttons
|
||||
style: {
|
||||
layout: 'horizontal', // horizontal | vertical
|
||||
size: 'large', // medium | large | responsive
|
||||
shape: 'rect', // pill | rect
|
||||
color: 'gold', // gold | blue | silver | black,
|
||||
fundingicons: false, // true | false,
|
||||
tagline: false // true | false,
|
||||
},
|
||||
// onInit is called when the button first renders
|
||||
onInit: function (data, actions) {
|
||||
|
||||
// Disable the buttons
|
||||
actions.disable();
|
||||
|
||||
// Listen for changes to the checkbox
|
||||
document.querySelector('#amount')
|
||||
.addEventListener('keyup', function (event) {
|
||||
let amount = event.target.value;
|
||||
amount = +amount;
|
||||
if (isNaN(amount)) {
|
||||
document.getElementById("amount-err").innerHTML = "Invalid amount format";
|
||||
setTimeout(function () {
|
||||
document.getElementById("amount-err").innerHTML = "";
|
||||
}, 2000);
|
||||
actions.disable();
|
||||
} else if (amount < 5) {
|
||||
document.getElementById("amount-err").innerHTML = "Amount must be greater than 5";
|
||||
setTimeout(function () {
|
||||
document.getElementById("amount-err").innerHTML = "";
|
||||
}, 2000);
|
||||
actions.disable();
|
||||
}
|
||||
if (event.target.value === "") {
|
||||
document.getElementById("amount-err").innerHTML = "Invalid amount format";
|
||||
setTimeout(function () {
|
||||
document.getElementById("amount-err").innerHTML = "";
|
||||
}, 2000);
|
||||
actions.disable();
|
||||
} else {
|
||||
actions.enable();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// onClick is called when the button is clicked
|
||||
onClick: function () {
|
||||
var regex = /^\d+(?:\.\d{0,2})$/;
|
||||
let amount = document.getElementById("amount").value;
|
||||
amount = +amount;
|
||||
if (isNaN(amount)) {
|
||||
alert(2);
|
||||
document.getElementById("amount-err").innerHTML = "Invalid amount format";
|
||||
setTimeout(function () {
|
||||
document.getElementById("amount-err").innerHTML = "";
|
||||
}, 2000);
|
||||
}
|
||||
},
|
||||
// Wait for the PayPal button to be clicked
|
||||
createOrder: function () {
|
||||
let formData = new FormData();
|
||||
let amount = document.getElementById("amount").value;
|
||||
|
||||
formData.append('amount', amount);
|
||||
|
||||
return fetch(
|
||||
'/app/paypal/do/order',
|
||||
{
|
||||
method: 'POST',
|
||||
body: formData
|
||||
}
|
||||
).then(function (response) {
|
||||
return response.json();
|
||||
}).then(function (resJson) {
|
||||
return resJson.data.id;
|
||||
});
|
||||
},
|
||||
|
||||
// Wait for the payment to be authorized by the customer
|
||||
onApprove: function (data, actions) {
|
||||
return fetch(
|
||||
'/app/paypal/order/success/' + data.orderID,
|
||||
{
|
||||
method: 'POST'
|
||||
}
|
||||
).then(function (res) {
|
||||
return res.json();
|
||||
}).then(function (res) {
|
||||
|
||||
// window.location.href = '/account/paypal/order/success';
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
// Wait for the payment to be authorized by the customer
|
||||
onCancel: function (data, actions) {
|
||||
return fetch(
|
||||
'/app/paypal/order/cancel/' + data.orderID,
|
||||
{
|
||||
method: 'POST'
|
||||
}
|
||||
).then(function (res) {
|
||||
return res.json();
|
||||
}).then(function (res) {
|
||||
|
||||
// window.location.href = '/account/paypal/order/success';
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
}).render('#paypalCheckoutContainer');
|
||||
@@ -0,0 +1,16 @@
|
||||
import Dashboard from './components/Dashboard'
|
||||
import DashboardHome from './pages/Home'
|
||||
import UserPage from './pages/User'
|
||||
|
||||
const routes = [
|
||||
{path: '/', redirect: {name: 'DashboardHome'}},
|
||||
{
|
||||
path: '/dashboard', component: Dashboard, children: [
|
||||
{path: '/', redirect: {name: 'DashboardHome'}},
|
||||
{path: 'home', name: 'DashboardHome', component: DashboardHome},
|
||||
{path: 'user', name: 'UserPage', component: UserPage}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
export default routes
|
||||
@@ -0,0 +1,3 @@
|
||||
import Axios from "axios";
|
||||
|
||||
export const GetUserList = () => Axios.get("/users").then(r => r.data)
|
||||
@@ -0,0 +1,26 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
export default new Vuex.Store({
|
||||
state: {
|
||||
sideBarOpen: false,
|
||||
users: [],
|
||||
},
|
||||
getters: {
|
||||
sideBarOpen: state => {
|
||||
return state.sideBarOpen
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
toggleSidebar(state) {
|
||||
state.sideBarOpen = !state.sideBarOpen
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
toggleSidebar(context) {
|
||||
context.commit('toggleSidebar')
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,3 @@
|
||||
User-agent: *
|
||||
Disallow:
|
||||
Disallow: /cgi-bin/
|
||||
@@ -0,0 +1,26 @@
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition-duration: 0.2s;
|
||||
transition-property: opacity;
|
||||
transition-timing-function: ease;
|
||||
}
|
||||
|
||||
.fade-enter,
|
||||
.fade-leave-active {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
overflow-y: scroll; /* Add the ability to scroll */
|
||||
}
|
||||
|
||||
/* Hide scrollbar for Chrome, Safari and Opera */
|
||||
.sidebar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Hide scrollbar for IE, Edge and Firefox */
|
||||
.sidebar {
|
||||
-ms-overflow-style: none; /* IE and Edge */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
body {
|
||||
background-image: url("../img/pattern.svg");
|
||||
}
|
||||
|
||||
.string {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.number {
|
||||
color: darkorange;
|
||||
}
|
||||
|
||||
.boolean {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.null {
|
||||
color: magenta;
|
||||
}
|
||||
|
||||
.key {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.hero_button {
|
||||
background-color: #0a165c !important;
|
||||
color: #fff !important;
|
||||
transition: all .5s ease
|
||||
}
|
||||
|
||||
.hero_button:hover {
|
||||
background-color: #6074edff !important
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 70%;
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
@import "~flag-icons/sass/flag-icons";
|
||||
|
||||
.gridjs-head button,
|
||||
.gridjs-footer button {
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
background-image: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.gridjs-head {
|
||||
margin-bottom: 5px;
|
||||
padding: 5px 1px;
|
||||
}
|
||||
|
||||
.gridjs-head::after {
|
||||
content: "";
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.gridjs-head:empty {
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.gridjs-container {
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
padding: 2px;
|
||||
color: #000;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.gridjs-footer {
|
||||
display: block;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
padding: 12px 24px;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
background-color: transparent;
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
border-bottom-width: ipx;
|
||||
border-color: #e5e7eb;
|
||||
border-bottom: none;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.gridjs-footer:empty {
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
input.gridjs-input {
|
||||
outline: none;
|
||||
background-color: #fff;
|
||||
border: 1px solid #d2d6dc;
|
||||
border-radius: 5px;
|
||||
padding: 10px 13px;
|
||||
font-size: 14px;
|
||||
line-height: 1.45;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
input.gridjs-input:focus {
|
||||
box-shadow: 0 0 0 3px rgba(149, 189, 243, 0.5);
|
||||
border-color: #9bc2f7;
|
||||
}
|
||||
|
||||
.gridjs-pagination {
|
||||
color: #3d4044;
|
||||
}
|
||||
|
||||
.gridjs-pagination::after {
|
||||
content: "";
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.gridjs-pagination .gridjs-summary {
|
||||
float: left;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.gridjs-pagination .gridjs-pages {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.gridjs-pagination .gridjs-pages button {
|
||||
padding: 0.25rem 0.75rem;
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
border-right: none;
|
||||
outline: none;
|
||||
margin-right: 1px;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.gridjs-pagination .gridjs-pages button:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.gridjs-pagination .gridjs-pages button:hover {
|
||||
background-color: #f7f7f7;
|
||||
color: #3c4257;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.gridjs-pagination .gridjs-pages button:disabled,
|
||||
.gridjs-pagination .gridjs-pages button[disabled],
|
||||
.gridjs-pagination .gridjs-pages button:hover:disabled {
|
||||
cursor: default;
|
||||
background-color: transparent;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.gridjs-pagination .gridjs-pages button.gridjs-spread {
|
||||
cursor: default;
|
||||
box-shadow: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.gridjs-pagination .gridjs-pages button.gridjs-currentPage {
|
||||
background-color: #48bb78;
|
||||
color: white;
|
||||
border-radius: 0.25rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.gridjs-pagination .gridjs-pages button.gridjs-currentPage:hover {
|
||||
background-color: rgba(56, 161, 105, 1);
|
||||
border-radius: 0.25rem;
|
||||
font-weight: normal;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.gridjs-pagination .gridjs-pages button:hover {
|
||||
background-color: #48bb78;
|
||||
border-radius: 0.25rem;
|
||||
font-weight: normal;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.gridjs-pagination .gridjs-pages button:last-child {
|
||||
border-bottom-right-radius: 6px;
|
||||
border-top-right-radius: 6px;
|
||||
border-right: 1px solid #d2d6dc;
|
||||
font-size: 13px;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.gridjs-pagination .gridjs-pages button:first-child {
|
||||
border-bottom-left-radius: 6px;
|
||||
border-top-left-radius: 6px;
|
||||
font-size: 13px;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
button.gridjs-sort {
|
||||
float: right;
|
||||
height: 24px;
|
||||
width: 16px;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
button.gridjs-sort-neutral {
|
||||
opacity: 0.3;
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAr0lEQVQ4T6WTUQ5BQQxFz1uG4IdnH2xHgo3w/xKLYSOEiMQqkCatSE2nwfy297Rz70zDn6dJ9APgAVyjvhpgAuyAOzADDiVIBDBxX0WXCFICeLENLkI8oAX2gE32WwtkChyt4AFzYJkYuwG2EeDrULMYU6AHLIBVoloDXXSFkZo4DCBnNfFU82CsD8hDPsQCiTzwkKK4BpCaQeQpS/avtd+vl6XQ0890++UzpRFKwxNZzCARuMPL3wAAAABJRU5ErkJggg==");
|
||||
background-position-y: center;
|
||||
}
|
||||
|
||||
button.gridjs-sort-asc {
|
||||
padding-bottom: 6px;
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAaUlEQVQ4T+3SsQ1AUBQF0GMfQ5hEoddILKHR6VT2MIZtJBoSkf/9iE68+t1T3NzMy8te5v2AZAc1Vgyxsu9KbNHtwQZ9CIkB5/CRCyIhIBSOIlegwpgYV4np+LkCOYoEMGOJAY+X/YEpbzl7DBHJyXtQAAAAAElFTkSuQmCC");
|
||||
background-position-y: top;
|
||||
}
|
||||
|
||||
button.gridjs-sort-desc {
|
||||
padding-top: 6px;
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAc0lEQVQ4T2NkoBAwUqifYRgaIMPAwGBAIFzOMzAwPIWpQQ+DYgYGhh4CBuQzMDBMwmUAEwMDw1QGBoYMHIaA5HIZGBj+4zIAJI7LEAzNIMW4ohHdEKya8RkAc0kvAwPDHwYGhjJkZyN7bxgmJJLzFsVhAAAclRAR/sEwnwAAAABJRU5ErkJggg==");
|
||||
background-position-y: bottom;
|
||||
}
|
||||
|
||||
button.gridjs-sort:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
table.gridjs-table {
|
||||
max-width: 100%;
|
||||
border-collapse: collapse;
|
||||
text-align: left;
|
||||
display: table;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: auto;
|
||||
table-layout: unset;
|
||||
}
|
||||
|
||||
.gridjs-tbody {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
td.gridjs-td {
|
||||
border: none;
|
||||
padding: 0.5rem 1rem;
|
||||
background-color: #fff;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
td.gridjs-td:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
td.gridjs-td:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
td.gridjs-message {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
th.gridjs-th {
|
||||
color: hsl(220, 95%, 8%);
|
||||
background-color: #f9fafb;
|
||||
border: none;
|
||||
padding: 0.5rem 1rem;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
box-sizing: content-box;
|
||||
white-space: nowrap;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
th.gridjs-th-sort {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
th.gridjs-th-sort:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
th.gridjs-th-sort:focus {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
th.gridjs-th-fixed {
|
||||
top: 0;
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
box-shadow: 0 1px 0 0 #e5e7eb;
|
||||
}
|
||||
|
||||
@supports (-moz-appearance: none) {
|
||||
th.gridjs-th-fixed {
|
||||
box-shadow: 0 0 0 1px #e5e7eb;
|
||||
}
|
||||
}
|
||||
|
||||
th.gridjs-th:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
th.gridjs-th:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.gridjs-tr {
|
||||
border: none;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.gridjs-tr:last-child td {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.gridjs *,
|
||||
.gridjs :after,
|
||||
.gridjs :before {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.gridjs-wrapper {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
overflow: auto;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
/* box-shadow: none; */
|
||||
box-shadow: 0 1px 3px 0 rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 2px 1px -1px rgba(0,0,0,.12);
|
||||
border-radius: 0.125rem;
|
||||
display: block;
|
||||
border-top-width: 1px;
|
||||
border-color: #e5e7eb;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.gridjs-wrapper:last-of-type {
|
||||
border-radius: 0;
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
.gridjs-search {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.gridjs-search-input {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.gridjs-loading-bar {
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
background-color: #fff;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.gridjs-loading-bar::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
transform: translateX(-100%);
|
||||
background-image: linear-gradient(
|
||||
90deg,
|
||||
rgba(204, 204, 204, 0) 0,
|
||||
rgba(204, 204, 204, 0.2) 20%,
|
||||
rgba(204, 204, 204, 0.5) 60%,
|
||||
rgba(204, 204, 204, 0)
|
||||
);
|
||||
animation: shimmer 2s infinite;
|
||||
content: "";
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
100% {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
@import url("https://fonts.googleapis.com/css2?family=Raleway:wght@100;300;400;500;600;700;800;900&display=swap");
|
||||
|
||||
@tailwind base;
|
||||
|
||||
@tailwind components;
|
||||
|
||||
.bg-accent {
|
||||
background-color: #f3f5f9;
|
||||
}
|
||||
|
||||
.bg-primary {
|
||||
background-color: #006aff;
|
||||
}
|
||||
|
||||
.transition-basic {
|
||||
@apply transition-colors duration-200 ease-in;
|
||||
}
|
||||
|
||||
.shadow-primary {
|
||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14),
|
||||
0 2px 1px -1px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.shadow-dropdown {
|
||||
box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.3), 0 2px 4px 1px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
@tailwind utilities;
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition-duration: 0.2s;
|
||||
transition-property: opacity;
|
||||
transition-timing-function: ease;
|
||||
}
|
||||
|
||||
.fade-enter,
|
||||
.fade-leave-active {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* used for dropdown */
|
||||
.slide-in-up-enter-active,
|
||||
.slide-in-up-leave-active {
|
||||
transition-duration: 250ms;
|
||||
transition-property: transform, visibility, opacity;
|
||||
transition-timing-function: ease-in;
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
.slide-in-up-enter,
|
||||
.slide-in-up-leave-active {
|
||||
transform: translate3d(0, 50%, 0);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* bounce in up */
|
||||
.bounce-in-up-enter-active {
|
||||
animation: bounceInUp 1s;
|
||||
}
|
||||
|
||||
/* .bounce-in-up-leave-active { */
|
||||
/* animation: bounceInUp 0.5s reverse; */
|
||||
/* } */
|
||||
|
||||
@keyframes bounceInUp {
|
||||
from,
|
||||
60%,
|
||||
75%,
|
||||
90%,
|
||||
to {
|
||||
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
}
|
||||
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translate3d(0, 3000px, 0) scaleY(5);
|
||||
}
|
||||
|
||||
60% {
|
||||
opacity: 1;
|
||||
transform: translate3d(0, -20px, 0) scaleY(0.9);
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: translate3d(0, 10px, 0) scaleY(0.95);
|
||||
}
|
||||
|
||||
90% {
|
||||
transform: translate3d(0, -5px, 0) scaleY(0.985);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,477 @@
|
||||
<div x-data="app" class="bg-white rounded-lg shadow">
|
||||
|
||||
<div x-show="loading" class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-50 justify-center items-center">
|
||||
<img src="../img/loading.gif" alt="Cargando..." class="w-16 h-16" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="container mx-auto p-6 w-full">
|
||||
<div class="justify-between items-center w-full md:flex">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold mb-2">Lista de actualizaciones de datos de usuario</h1>
|
||||
<p class="mb-4 text-sm">Gestión de actualizaciones de datos de usuario.</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-4 md:mb-0 relative">
|
||||
<input type="text" placeholder="Buscar..." class="border border-gray-300 rounded p-2 w-full"
|
||||
x-model="search" @input.debounce.500ms="loadData()" />
|
||||
</div>
|
||||
|
||||
<div class="flex itmems-center justify-end mb-4 md:mb-0">
|
||||
<button @click="exportToExcel()" class="bg-[#8eb02f] text-white px-4 py-2 rounded text-sm">Exportar a
|
||||
Excel</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table-auto w-full">
|
||||
<thead class="text-sm text-left py-4 border-b border-gray-300">
|
||||
<tr class="text-left font-semibold border-collapse">
|
||||
<th class="py-2 px-4 border-b">Código</th>
|
||||
<th class="py-2 px-4 border-b">Nombre</th>
|
||||
<th class="py-2 px-4 border-b">Tipo persona</th>
|
||||
<th class="py-2 px-4 border-b">Celular</th>
|
||||
<th class="py-2 px-4 border-b">Celular alternativo</th>
|
||||
<th class="py-2 px-4 border-b">Correo</th>
|
||||
<th class="py-2 px-4 border-b">Dirección</th>
|
||||
<th class="py-2 px-4 border-b">Tipo documento</th>
|
||||
<th class="py-2 px-4 border-b">N° documento</th>
|
||||
<th class="py-2 px-4 border-b">OTP</th>
|
||||
<th class="py-2 px-4 border-b">Revisado</th>
|
||||
<th class="py-2 px-4 border-b">Fecha registro</th>
|
||||
<th class="py-2 px-4 border-b"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-gray-500 select-none text-sm">
|
||||
<template x-for="data in datos" :key="data.id">
|
||||
<tr class="hover:bg-gray-100">
|
||||
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="data.codigo"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="data.name"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="data.tipo_persona"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="data.movil1"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="data.movil2"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="data.email"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="data.direccion"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="data.tipo_documento"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="data.documento"></td>
|
||||
<td class="py-3 text-xs px-4 border-b">
|
||||
<div class="flex items-center">
|
||||
<div :class="data.validacion_otp ? 'bg-green-500' : 'bg-gray-400'"
|
||||
class="w-3 h-3 rounded-full mr-2"></div>
|
||||
<span x-text="data.validacion_otp ? 'Validado' : 'No Validado'"></span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-3 text-xs px-4 border-b">
|
||||
<div class="flex items-center">
|
||||
<div :class="data.revisado ? 'bg-green-500' : 'bg-gray-400'"
|
||||
class="w-3 h-3 rounded-full mr-2"></div>
|
||||
<span x-text="data.revisado ? 'Revisado' : 'No Revisado'"></span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-3 text-xs px-4 border-b"
|
||||
x-text="data.created_at ? new Date(data.created_at).toLocaleDateString('es-ES', { year: 'numeric', month: 'long', day: 'numeric' }) : 'Fecha no disponible'">
|
||||
</td>
|
||||
<td class="py-3 text-xs px-4 border-b">
|
||||
<div class="flex items-center gap-2">
|
||||
<button @click="openAddModal(data)" title="Añadir nota">
|
||||
<svg class="w-5 text-gray-500" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 12H14M12 10V14M19.9592 15H16.6C16.0399 15 15.7599 15 15.546 15.109C15.3578 15.2049 15.2049 15.3578 15.109 15.546C15 15.7599 15 16.0399 15 16.6V19.9592M20 14.1031V7.2C20 6.07989 20 5.51984 19.782 5.09202C19.5903 4.71569 19.2843 4.40973 18.908 4.21799C18.4802 4 17.9201 4 16.8 4H7.2C6.0799 4 5.51984 4 5.09202 4.21799C4.71569 4.40973 4.40973 4.71569 4.21799 5.09202C4 5.51984 4 6.0799 4 7.2V16.8C4 17.9201 4 18.4802 4.21799 18.908C4.40973 19.2843 4.71569 19.5903 5.09202 19.782C5.51984 20 6.0799 20 7.2 20H14.1031C14.5923 20 14.8369 20 15.067 19.9447C15.2711 19.8957 15.4662 19.8149 15.6451 19.7053C15.847 19.5816 16.0199 19.4086 16.3658 19.0627L19.0627 16.3658C19.4086 16.0199 19.5816 15.847 19.7053 15.6451C19.8149 15.4662 19.8957 15.2711 19.9447 15.067C20 14.8369 20 14.5923 20 14.1031Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<button @click="openViewModal(data)" title="Ver">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 text-[#8eb02f]">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
</svg>
|
||||
</button>
|
||||
<!--button @click="openEditModal(data)" title="Editar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10" />
|
||||
</svg>
|
||||
</button>
|
||||
<button @click="openDeleteModal(data)" title="Eliminar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 text-red-500">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
|
||||
</svg>
|
||||
</button-->
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-start items-center gap-2 p-4 text-sm">
|
||||
<button @click="page = Math.max(1, page - 1); loadData()" :disabled="page === 1"
|
||||
class="px-4 py-2 text-black bg-gray-200 rounded-l-md opacity-50 disabled:cursor-not-allowed">
|
||||
Anterior
|
||||
</button>
|
||||
<template x-for="pageNum in paginatedPages" :key="pageNum">
|
||||
<button @click="goToPage(pageNum)" class="px-4 py-2 text-black bg-gray-200 bg-black text-gray-50 rounded-md hover:bg-gray-300"
|
||||
:class="{ 'bg-black text-white': pageNum === page }" x-text="pageNum"></button>
|
||||
</template>
|
||||
<button @click="page += 1; loadData()" :disabled="datos.length < limit" :disabled="page === totalPages"
|
||||
class="px-4 py-2 text-black bg-gray-200 rounded-r-md opacity-50 disabled:cursor-not-allowed">
|
||||
Siguiente
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modales -->
|
||||
<div x-show="viewModal" x-transition:enter="transition ease-out duration-300 transform" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" x-transition:leave="transition ease-in duration-200 transform" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0"
|
||||
class="fixed inset-0 overflow-auto bg-gray-800 bg-opacity-75 flex justify-center items-center text-sm z-50">
|
||||
<div class="bg-white rounded-lg shadow-lg p-6 w-11/12 max-w-lg">
|
||||
<h2 class="text-xl font-bold mb-4">Ver actualizacion de datos de usuario</h2>
|
||||
|
||||
<div class="w-full mb-4">
|
||||
<label class="block mb-2">Tipo de usuario:</label>
|
||||
<input type="text" x-model="selectedItem.tipo_usuario" disabled
|
||||
class="border border-gray-300 rounded p-2 w-full" placeholder="Ingresa el tipo de usuario" />
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row justify-between gap-4 mb-4">
|
||||
<div class="w-full">
|
||||
<label class="block mb-2">Tipo de persona:</label>
|
||||
<input type="text" x-model="selectedItem.tipo_persona" disabled
|
||||
class="border border-gray-300 rounded p-2 w-full" placeholder="Ingresa el tipo de persona" />
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<label class="block mb-2">Nombre:</label>
|
||||
<input type="text" x-model="selectedItem.name" disabled
|
||||
class="border border-gray-300 rounded p-2 w-full" placeholder="Ingresa el nombre" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row justify-between gap-4 mb-4">
|
||||
<div class="w-full">
|
||||
<label class="block mb-2">Tipo de documento:</label>
|
||||
<input type="email" x-model="selectedItem.tipo_documento" disabled
|
||||
class="border border-gray-300 rounded p-2 w-full" placeholder="Ingresa el email" />
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<label class="block mb-2">Documento:</label>
|
||||
<input type="email" x-model="selectedItem.documento" disabled
|
||||
class="border border-gray-300 rounded p-2 w-full" placeholder="Ingresa el email" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row justify-between gap-4 mb-4">
|
||||
<div class="w-full">
|
||||
<label class="block mb-2">Celular:</label>
|
||||
<input type="email" x-model="selectedItem.movil1" disabled
|
||||
class="border border-gray-300 rounded p-2 w-full" placeholder="Ingresa el celular" />
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<label class="block mb-2">Celular alternativo:</label>
|
||||
<input type="email" x-model="selectedItem.movil2" disabled
|
||||
class="border border-gray-300 rounded p-2 w-full" placeholder="Ingresa el celular alternativo" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row justify-between gap-4 mb-4">
|
||||
<div class="w-full">
|
||||
<label class="block mb-2">Email:</label>
|
||||
<input type="email" x-model="selectedItem.email" disabled
|
||||
class="border border-gray-300 rounded p-2 w-full" placeholder="Ingresa el email" />
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<label class="block mb-2">Dirección:</label>
|
||||
<input type="email" x-model="selectedItem.direccion" disabled
|
||||
class="border border-gray-300 rounded p-2 w-full" placeholder="Ingresa el direccion" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between gap-2 text-sm">
|
||||
<button @click="addModal = true" class="px-4 py-2 bg-[#8eb02f] text-white rounded">Añadir nota</button>
|
||||
<button @click="viewModal = false" class="px-4 py-2 bg-gray-600 text-white rounded">Cerrar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div x-show="editModal" x-transition:enter="transition ease-out duration-300 transform" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" x-transition:leave="transition ease-in duration-200 transform" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0"
|
||||
class="fixed inset-0 overflow-auto bg-gray-800 bg-opacity-75 flex justify-center items-center text-sm z-50">
|
||||
<div class="bg-white rounded-lg shadow-lg p-6 w-11/12 max-w-lg">
|
||||
<h2 class="text-xl font-bold mb-4">Editar actualizacion de datos de usuario</h2>
|
||||
|
||||
<div class="w-full mb-4">
|
||||
<label class="block mb-2">Tipo de usuario:</label>
|
||||
<input type="text" x-model="selectedItem.tipo_usuario"
|
||||
class="border border-gray-300 rounded p-2 w-full" placeholder="Ingresa el tipo de usuario" />
|
||||
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row justify-between gap-4 mb-4">
|
||||
<div class="w-full">
|
||||
<label class="block mb-2">Tipo de persona:</label>
|
||||
<input type="text" x-model="selectedItem.tipo_persona"
|
||||
class="border border-gray-300 rounded p-2 w-full" placeholder="Ingresa el tipo de persona" />
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<label class="block mb-2">Nombre:</label>
|
||||
<input type="text" x-model="selectedItem.name"
|
||||
class="border border-gray-300 rounded p-2 w-full" placeholder="Ingresa el nombre" />
|
||||
<p x-show="errors.name" x-text="errors.name" class="text-red-500 text-sm"></p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row justify-between gap-4 mb-4">
|
||||
<div class="w-full">
|
||||
<label class="block mb-2">Tipo de documento:</label>
|
||||
<input type="email" x-model="selectedItem.tipo_documento"
|
||||
class="border border-gray-300 rounded p-2 w-full" placeholder="Ingresa el email" />
|
||||
<p x-show="errors.tipo_documento" x-text="errors.tipo_documento" class="text-red-500 text-sm"></p>
|
||||
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<label class="block mb-2">Documento:</label>
|
||||
<input type="email" x-model="selectedItem.documento"
|
||||
class="border border-gray-300 rounded p-2 w-full" placeholder="Ingresa el email" />
|
||||
<p x-show="errors.documento" x-text="errors.documento" class="text-red-500 text-sm"></p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row justify-between gap-4 mb-4">
|
||||
<div class="w-full">
|
||||
<label class="block mb-2">Celular:</label>
|
||||
<input type="email" x-model="selectedItem.movil1"
|
||||
class="border border-gray-300 rounded p-2 w-full" placeholder="Ingresa el celular" />
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<label class="block mb-2">Celular alternativo:</label>
|
||||
<input type="email" x-model="selectedItem.movil2"
|
||||
class="border border-gray-300 rounded p-2 w-full" placeholder="Ingresa el celular alternativo" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row justify-between gap-4 mb-4">
|
||||
<div class="w-full">
|
||||
<label class="block mb-2">Email:</label>
|
||||
<input type="email" x-model="selectedItem.email"
|
||||
class="border border-gray-300 rounded p-2 w-full" placeholder="Ingresa el email" />
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<label class="block mb-2">Dirección:</label>
|
||||
<input type="email" x-model="selectedItem.direccion"
|
||||
class="border border-gray-300 rounded p-2 w-full" placeholder="Ingresa el direccion" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between gap-2 text-sm">
|
||||
<button @click="updateItem()" class="px-4 py-2 bg-[#8eb02f] text-white rounded">Actualizar</button>
|
||||
<button @click="closeModals()" class="px-4 py-2 bg-gray-600 text-white rounded">Cerrar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div x-show="addModal" class="fixed inset-0 bg-gray-800 bg-opacity-75 flex justify-center items-center text-sm z-50">
|
||||
<div class="bg-white rounded-lg shadow-lg p-6 w-11/12 max-w-lg">
|
||||
<h2 class="text-xl font-bold mb-4">Añadir nota al cliente</h2>
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="block mb-2">Notas:</label>
|
||||
<textarea x-model="item.notas" class="border border-gray-300 rounded p-2 w-full"
|
||||
placeholder="Ingresa la nota"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between gap-2 text-sm">
|
||||
<button @click="addNote()" class="px-4 py-2 bg-[#8eb02f] text-white rounded">Añadir nota</button>
|
||||
<button @click="addModal = false" class="px-4 py-2 bg-gray-600 text-white rounded">Cancelar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div x-show="deleteModal" class="fixed inset-0 overflow-auto bg-gray-800 bg-opacity-75 flex justify-center items-center z-50">
|
||||
<div class="bg-white rounded-lg shadow-lg p-6 w-11/12 max-w-lg">
|
||||
<h2 class="text-xl font-bold mb-4">Confirmar Eliminación</h2>
|
||||
|
||||
<p>¿Estás seguro de que deseas eliminar este registro?</p>
|
||||
|
||||
|
||||
<div class="flex mt-4 justify-end gap-2 text-sm">
|
||||
<button @click="deleteItem()" class="px-4 py-2 bg-red-500 text-white rounded">Eliminar</button>
|
||||
<button @click="closeModals()" class="bg-gray-600 text-white px-4 py-2 rounded">Cancelar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function app() {
|
||||
return {
|
||||
datos: [],
|
||||
loading: false,
|
||||
limit: 10,
|
||||
page: 1,
|
||||
search: '',
|
||||
totalPages: 0,
|
||||
paginatedPages: [],
|
||||
// modales
|
||||
viewModal: false,
|
||||
addModal: false,
|
||||
editModal: false,
|
||||
deleteModal: false,
|
||||
// inputs
|
||||
item: {
|
||||
id: '', notas: ''
|
||||
},
|
||||
selectedItem: {},
|
||||
errors: {},
|
||||
loadData() {
|
||||
if (this.search !== '') {
|
||||
this.page = 1;
|
||||
this.limit = 100;
|
||||
} else {
|
||||
this.limit = 10;
|
||||
}
|
||||
this.loading = true;
|
||||
axios.get('/app/loadactualizaciondatosusuarios', {
|
||||
params: {
|
||||
page: this.page,
|
||||
limit: this.limit,
|
||||
search: this.search
|
||||
}
|
||||
}).then(response => {
|
||||
this.datos = response.data.registros.map(data => ({
|
||||
id: data.ID,
|
||||
tipo_persona: data.tipo_persona,
|
||||
name: data.name,
|
||||
movil1: data.movil1,
|
||||
movil2: data.movil2,
|
||||
email: data.email,
|
||||
codigo: data.codigo,
|
||||
tipo_usuario: data.tipo_usuario,
|
||||
direccion: data.direccion,
|
||||
tipo_documento: data.tipo_documento,
|
||||
documento: data.documento,
|
||||
notas: data.notas,
|
||||
revisado: data.revisado,
|
||||
created_at: data.CreatedAt,
|
||||
validacion_otp: data.validacion_otp
|
||||
}));
|
||||
this.totalPages = response.data.totalPages;
|
||||
this.calculatePaginatedPages();
|
||||
}).catch(error => {
|
||||
console.error('Error al obtener datos:', error);
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
setSelectedItem(data) {
|
||||
this.selectedItem = { ...data };
|
||||
this.errors = {};
|
||||
},
|
||||
resetSelectedItem() {
|
||||
this.selectedItem = {};
|
||||
this.errors = {};
|
||||
},
|
||||
calculatePaginatedPages() {
|
||||
const maxVisiblePages = 5;
|
||||
const startPage = Math.max(1, this.page - Math.floor(maxVisiblePages / 2));
|
||||
const endPage = Math.min(this.totalPages, startPage + maxVisiblePages - 1);
|
||||
this.paginatedPages = Array.from({ length: endPage - startPage + 1 }, (_, i) => i + startPage);
|
||||
},
|
||||
goToPage(page) {
|
||||
this.page = page;
|
||||
this.loadData();
|
||||
},
|
||||
setLoading(value) {
|
||||
this.loading = value;
|
||||
},
|
||||
validateFields(fields) {
|
||||
this.errors = {};
|
||||
fields.forEach(field => {
|
||||
if (!this.selectedItem[field]) {
|
||||
this.errors[field] = 'Este campo es obligatorio';
|
||||
}
|
||||
});
|
||||
return Object.keys(this.errors).length === 0;
|
||||
},
|
||||
init() {
|
||||
this.loadData();
|
||||
},
|
||||
openViewModal(data) {
|
||||
this.setSelectedItem(data);
|
||||
this.viewModal = true;
|
||||
},
|
||||
openEditModal(data) {
|
||||
this.setSelectedItem(data);
|
||||
this.editModal = true;
|
||||
},
|
||||
updateItem() {
|
||||
if (this.validateFields(['tipo_documento', 'documento', 'name'])) {
|
||||
this.setLoading(true);
|
||||
axios.put(`/app/actualizacion-datos-usuario/${this.selectedItem.id}`, this.selectedItem)
|
||||
.then(() => {
|
||||
alert("Registro actualizado exitosamente.");
|
||||
this.resetSelectedItem();
|
||||
this.loadData();
|
||||
})
|
||||
.catch(error => console.error("Error al actualizar el registro:", error))
|
||||
.finally(() => {
|
||||
this.closeModals()
|
||||
this.setLoading(false);
|
||||
});
|
||||
}
|
||||
},
|
||||
deleteItem() {
|
||||
this.setLoading(true);
|
||||
axios.delete(`/app/actualizacion-datos-usuario/${this.selectedItem.id}`)
|
||||
.then(() => {
|
||||
alert("Registro eliminado exitosamente.");
|
||||
this.resetSelectedItem();
|
||||
this.loadData();
|
||||
})
|
||||
.catch(error => console.error("Error al eliminar el registro:", error))
|
||||
.finally(() => this.setLoading(false));
|
||||
},
|
||||
openAddModal(data) {
|
||||
this.selectedItem.id = data.id;
|
||||
this.addModal = true;
|
||||
},
|
||||
openDeleteModal(data) {
|
||||
this.selectedItem.id = data.id;
|
||||
|
||||
this.deleteModal = true;
|
||||
},
|
||||
closeModals(){
|
||||
this.viewModal = false;
|
||||
this.addModal = false;
|
||||
this.editModal = false;
|
||||
this.deleteModal = false;
|
||||
},
|
||||
addNote() {
|
||||
if (this.selectedItem.id && this.item.notas) {
|
||||
axios.put(`/app/actualizacion-datos-usuario/${this.selectedItem.id}`, {
|
||||
notas: this.item.notas,
|
||||
revisado: true
|
||||
}).then(() => {
|
||||
alert("Nota añadida exitosamente.");
|
||||
this.item.notas = '';
|
||||
this.addModal = false;
|
||||
this.loadData();
|
||||
}).catch(error => console.error("Error al añadir la nota:", error));
|
||||
} else {
|
||||
alert('Debe seleccionar un usuario y añadir una nota');
|
||||
}
|
||||
},
|
||||
exportToExcel() {
|
||||
axios.get('/app/export/actualizacion-datos-usuarios', { responseType: 'blob' })
|
||||
.then(response => {
|
||||
const url = window.URL.createObjectURL(new Blob([response.data]));
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.setAttribute('download', 'actualizacion_datos_usuarios.xlsx');
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
})
|
||||
.catch(error => console.error('Error al exportar datos:', error));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,88 @@
|
||||
<div class="max-w-5xl mx-auto p-8">
|
||||
<div class="section-title flex items-center mb-6">
|
||||
<span class="w-1 h-10 bg-blue-800 mr-4"></span>
|
||||
<h2 class="text-3xl font-bold text-gray-800">
|
||||
Oficina Virtual Gases del Oriente
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<p class="mb-12">
|
||||
Bienvenid@ a la Oficina Virtual de Gases del Oriente SA ESP. Si ya está registrado(a), puede
|
||||
iniciar sesión con el Usuario y Contraseña asignados durante el registro. Si aún no tiene Usuario y Contraseña,
|
||||
es necesario registrarse según las acciones que desee realizar.
|
||||
</p>
|
||||
<div class="relative w-full max-w-5xl bg-white shadow-lg rounded-[35px] overflow-hidden">
|
||||
<div class="relative w-full h-0 pb-[120%] md:pb-[60%] lg:pb-[50%]"> <!-- Aspect ratio box -->
|
||||
<img src="/img/img20.webp" alt="Background Image"
|
||||
class="absolute inset-0 w-full h-full object-cover rounded-[35px]">
|
||||
<div class="absolute inset-0 z-10 flex flex-col justify-center p-8 lg:max-w-md lg:ml-8">
|
||||
<h1 class="text-2xl lg:text-4xl font-bold mb-6 text-[#404e7b] text-center">Iniciar sesión</h1>
|
||||
<form action="/do/login" method="POST">
|
||||
<div class="mb-4">
|
||||
<label for="email" class="block text-md font-medium text-gray-700">Correo electrónico</label>
|
||||
<input type="email" id="email" required name="email"
|
||||
class="mt-1 block w-full px-3 py-3 lg:py-4 rounded-xl shadow-[0_5px_25px_rgba(0,0,0,0.1)]"
|
||||
placeholder="Ingrese su correo electrónico" />
|
||||
</div>
|
||||
<div class="mb-8">
|
||||
<label for="password" class="block text-md font-medium text-gray-700">Contraseña</label>
|
||||
<input type="password" id="password" name="password" required
|
||||
class="mt-1 block w-full px-3 py-3 lg:py-4 rounded-xl shadow-[0_5px_25px_rgba(0,0,0,0.1)]"
|
||||
placeholder="Ingrese su contraseña" />
|
||||
</div>
|
||||
<a href="/request-password-reset" class="text-black">¿Olvidaste tu contraseña?</a>
|
||||
<div class="flex justify-center">
|
||||
<button type="{{.Type}}" class="primary-button py-2 px-5 bg-[#284c91] text-white font-medium rounded shadow-sm">
|
||||
Iniciar sesión
|
||||
</button>
|
||||
|
||||
|
||||
{{if .error}}
|
||||
<p class="text-red-300">{{.message}}</p>
|
||||
{{end}}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="max-w-5xl mx-auto p-8 mb-8">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||
<div class="flex flex-col">
|
||||
<div class="flex items-center mb-4">
|
||||
<div class="w-1 h-16 bg-[#274e93] mr-2"></div>
|
||||
<h2 class="text-3xl font-bold text-gray-800">Registrarse Como Usuario del Gas Natural</h2>
|
||||
</div>
|
||||
<div class="flex-grow bg-white p-10 rounded-lg shadow-[0_5px_25px_rgba(0,0,0,0.1)]">
|
||||
<p class="mb-4 text-gray-600">
|
||||
Podrá Ver o Imprimir facturas, Consultar o Registrar PQRs, Consultar Estado de créditos, Realizar
|
||||
pagos.
|
||||
</p>
|
||||
<a href="/register-gas">
|
||||
<button type="{{.Type}}" class="secondary-button w-full py-2 px-5 bg-[#beda75] text-[#284c91] font-medium rounded shadow-sm hover:bg-[#aecc5b] my-auto">
|
||||
Registrarse como usuario del Gas
|
||||
</button>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<div class="flex items-center mb-4">
|
||||
<div class="w-1 h-16 bg-[#274e93] mr-2"></div>
|
||||
<h2 class="text-3xl font-bold text-gray-800">Registrarse Como Organismo de Inspección (OIA)</h2>
|
||||
</div>
|
||||
<div class="flex-grow bg-white p-10 rounded-lg shadow-[0_5px_25px_rgba(0,0,0,0.1)]">
|
||||
<p class="mb-4 text-gray-600">
|
||||
Para cargar los certificados de resultados de inspección de conformidad.
|
||||
</p>
|
||||
<a href="/register-oia">
|
||||
<button type="{{.Type}}" class="secondary-button w-full py-2 px-5 bg-[#beda75] text-[#284c91] font-medium rounded shadow-sm hover:bg-[#aecc5b] my-auto">
|
||||
Registrarse como OIA
|
||||
</button>
|
||||
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,50 @@
|
||||
<div class="min-h-screen flex items-center justify-center bg-gray-100">
|
||||
<div class="w-full max-w-md bg-white rounded-lg shadow-lg p-6">
|
||||
<h1 class="text-2xl font-bold text-center text-gray-700 mb-6">¡Restablece tu contraseña!</h1>
|
||||
<form action="/do/password-reset/{{.Token}}" method="POST" class="space-y-4">
|
||||
<div>
|
||||
<label for="email" class="block text-sm font-medium text-gray-700">Codigo de Usuario</label>
|
||||
<input
|
||||
id="email"
|
||||
type="text"
|
||||
placeholder="Ingresa tu codigo de usuario"
|
||||
name="nombre_usuario"
|
||||
required
|
||||
class="w-full mt-1 px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring focus:ring-blue-500 focus:border-blue-500"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password" class="block text-sm font-medium text-gray-700">Nueva contraseña</label>
|
||||
<input
|
||||
id="password"
|
||||
type="password"
|
||||
placeholder="Ingresa tu nueva contraseña"
|
||||
name="password"
|
||||
required
|
||||
class="w-full mt-1 px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring focus:ring-blue-500 focus:border-blue-500"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="c_password" class="block text-sm font-medium text-gray-700">Confirma tu contraseña</label>
|
||||
<input
|
||||
id="c_password"
|
||||
type="password"
|
||||
placeholder="Confirma tu nueva contraseña"
|
||||
name="c_password"
|
||||
required
|
||||
class="w-full mt-1 px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring focus:ring-blue-500 focus:border-blue-500"
|
||||
>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="w-full bg-blue-500 text-white font-bold py-2 px-4 rounded-md hover:bg-blue-600 focus:outline-none focus:ring focus:ring-blue-300"
|
||||
>
|
||||
Restablecer contraseña
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<div class="p-10">
|
||||
<div class="bg-cover h-full">
|
||||
<div class="content px-8 py-2">
|
||||
<div class="body mt-10 mx-8">
|
||||
<div class="md:flex items-center justify-between">
|
||||
<div class="w-full md:w-1/2 mr-auto">
|
||||
|
||||
</div>
|
||||
<div class="w-full md:max-w-md mt-6">
|
||||
<div class="card bg-white shadow-md rounded-lg px-4 py-4 mb-6 ">
|
||||
<form action="/do/register" method="POST">
|
||||
<div class="flex items-center justify-center">
|
||||
<h2 class="text-2xl font-bold tracking-wide">
|
||||
Let me in!!!
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<h2 class="text-xl text-center font-semibold text-gray-800 mb-2">
|
||||
Sign Up
|
||||
</h2>
|
||||
<div class="flex items-center justify-center">
|
||||
{{if .error}}
|
||||
<p class="text-red-300">{{.message}}</p>
|
||||
{{end}}
|
||||
</div>
|
||||
<input name="name" required type="text"
|
||||
class="rounded px-4 w-full py-1 bg-gray-200 border border-gray-400 mb-6 text-gray-700 placeholder-gray-700 focus:bg-white focus:outline-none"
|
||||
placeholder="Full Name">
|
||||
<input name="email" required type="email"
|
||||
class="rounded px-4 w-full py-1 bg-gray-200 border border-gray-400 mb-6 text-gray-700 placeholder-gray-700 focus:bg-white focus:outline-none"
|
||||
placeholder="Email Address">
|
||||
<input name="password" required type="password"
|
||||
class="rounded px-4 w-full py-1 bg-gray-200 border border-gray-400 mb-4 text-gray-700 placeholder-gray-700 focus:bg-white focus:outline-none"
|
||||
placeholder="Password">
|
||||
<input name="c_password" required type="password"
|
||||
class="rounded px-4 w-full py-1 bg-gray-200 border border-gray-400 mb-4 text-gray-700 placeholder-gray-700 focus:bg-white focus:outline-none"
|
||||
placeholder="Confirm Password">
|
||||
<div class="flex items-center justify-between">
|
||||
<button class="bg-black text-gray-200 px-2 py-1 rounded" type="submit">Let me in!
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,11 @@
|
||||
<h1 class="h1">Reset my password!</h1>
|
||||
<form action="/do/reset-password" method="POST">
|
||||
<div class="container">
|
||||
<label for="Usuario"><b>Codigo de usuario</b></label>
|
||||
<input id="Usuario" type="text" placeholder="Ingrese su usuario" name="email" required>
|
||||
|
||||
<button type="submit">Let me reset password!!</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{{.Login.Email}}
|
||||
@@ -0,0 +1,22 @@
|
||||
<!-- Container Principal -->
|
||||
<div x-data="modals" @keydown.escape="closeModal" class="bg-white rounded-lg shadow">
|
||||
<div class="container mx-auto p-6 w-full ">
|
||||
<h1 class="text-2xl font-bold mb-4">Oficina Virtual</h1>
|
||||
<div class="justify-between w-full md:flex">
|
||||
<p class="mb-4 text-sm">Bienvenido a la oficina virtual de GASES DEL ORIENTE S.A E.S.P</p>
|
||||
<a href="/"><button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded flex space-x-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
||||
stroke="currentColor" class="w-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5 3 12m0 0 7.5-7.5M3 12h18" />
|
||||
</svg>
|
||||
<p> Volver a la pagina principal </p>
|
||||
</button>
|
||||
</a>
|
||||
|
||||
<!-- Agregar el GIF de carga -->
|
||||
<div x-show="loading" class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-50 justify-center items-center">
|
||||
<img src="../img/loading.gif" alt="Cargando..." class="w-16 h-16" />
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,450 @@
|
||||
<!-- Container Principal -->
|
||||
<div x-data="modals" @keydown.escape="closeModal" class="bg-white rounded-lg shadow">
|
||||
<div class="container mx-auto p-6 w-full">
|
||||
<h1 class="text-2xl font-bold mb-4">Lista de deberes y derechos de usuario</h1>
|
||||
<div class="justify-between w-full md:flex">
|
||||
<p class="mb-4 text-sm">Gestión de deberes y derechos de usuario</p>
|
||||
<!-- Campo de Búsqueda -->
|
||||
<div class="mb-4 relative">
|
||||
<input type="text" x-model="searchQuery" placeholder="Buscar..."
|
||||
class="border border-gray-300 rounded w-full md:w-60 p-2 text-sm" @input="loadRegister()">
|
||||
|
||||
<div x-show="isLoading" class="absolute right-2 top-2 flex items-center">
|
||||
<svg class="animate-spin h-5 w-5 text-gray-500" xmlns="http://www.w3.org/2000/svg" fill="none"
|
||||
viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4">
|
||||
</circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end mb-4">
|
||||
<button class="bg-[#8eb02f] text-white px-4 py-2 rounded text-sm"
|
||||
x-on:click="addModal=true">Nuevo</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div x-show="loading" class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-50 justify-center items-center">
|
||||
<img src="../img/loading.gif" alt="Cargando..." class="w-16 h-16" />
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto max-w-full">
|
||||
<!-- Tabla de Registros -->
|
||||
<table class="table-auto w-full">
|
||||
<thead class="text-sm text-left py-4 border-b border-gray-300">
|
||||
<tr class="text-left font-semibold border-collapse">
|
||||
<th class="py-2 px-4 border-b">Item</th>
|
||||
<th class="py-2 px-4 border-b">Título</th>
|
||||
<th class="py-2 px-4 border-b">Descripción</th>
|
||||
<th class="py-2 px-4 border-b">Imagen</th>
|
||||
<th class="py-2 px-4 border-b">Archivo</th>
|
||||
<th class="py-2 px-4 border-b">Botón de Texto</th>
|
||||
<th class="py-2 px-4 border-b w-32"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-gray-500 select-none text-sm">
|
||||
<!-- Mensaje de Carga Inicial -->
|
||||
<tr class="hover:bg-gray-100" x-show="isLoading">
|
||||
<td colspan="" class="py-2 px-4 border-b text-center w-full">
|
||||
<div class="text-center mx-auto justify-center flex space-x-2">
|
||||
<!-- SVG de cargando (puedes reemplazarlo con un botón si lo prefieres) -->
|
||||
<svg class="animate-spin h-5 w-5 mx-1 text-gray-500" xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor"
|
||||
stroke-width="4">
|
||||
</circle>
|
||||
<path class="opacity-75" fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z">
|
||||
</path>
|
||||
</svg>
|
||||
Cargando registros...
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<template x-for="registro in registros" :key="registro.ID">
|
||||
<tr class="hover:bg-gray-100" :data-role-id="registro.ID">
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="registro.ID"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="registro.title"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="registro.description"></td>
|
||||
<td class="py-3 text-xs px-4 border-b">
|
||||
<button class="bg-[#8eb02f] text-white px-4 py-2 rounded"
|
||||
x-on:click="window.open(`${window.location.origin}/${registro.imagen}`, '_blank')">
|
||||
Ver imagen
|
||||
</button>
|
||||
</td>
|
||||
<td class="py-3 text-xs px-4 border-b">
|
||||
<button class="bg-[#8eb02f] text-white px-4 py-2 rounded"
|
||||
x-on:click="window.open(`${window.location.origin}/${registro.archivo}`, '_blank')">
|
||||
Ver archivo
|
||||
</button>
|
||||
</td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="registro.text_button"></td>
|
||||
<td class="py-3 text-xs px-4 border-b">
|
||||
<div class="flex justify-between gap-2">
|
||||
<button
|
||||
@click="viewModal = true; Title = registro.title; Description = registro.description; Imagen = registro.imagen; Archivo = registro.archivo; Text_button = registro.text_button;"
|
||||
title="Ver">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" class="w-5 text-[#8eb02f]">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
@click="editModal = true; Id = registro.ID; Title = registro.title; Description = registro.description; Imagen = registro.imagen; Archivo = registro.archivo; Text_button = registro.text_button;"
|
||||
title="Editar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" class="w-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10" />
|
||||
</svg>
|
||||
</button>
|
||||
<button @click="showConfirmModal = true; deleteId = registro.ID;" title="Eliminar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" class="w-5 text-red-500">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<tr x-show="sinregistro">
|
||||
<td colspan="7" class="py-2 px-4 border-b text-center">No hay registros disponibles.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<div id="pagination" class="flex justify-left my-4 text-sm"></div>
|
||||
<div id="recordCountDiv" class="text-sm text-gray-700 ml-4"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Ver -->
|
||||
<div x-cloak x-show="viewModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Ver deberes y derechos de usuario</h2>
|
||||
<p class="font-semibold" x-text="Title"></p>
|
||||
<p class="mt-2" x-text="Description"></p>
|
||||
<p class="mt-2" x-text="Text_button"></p>
|
||||
<button class="bg-[#8eb02f] text-white px-4 py-2 rounded"
|
||||
x-on:click="window.open(`${window.location.origin}/${Imagen}`, '_blank')">
|
||||
Ver imagen
|
||||
</button>
|
||||
<button class="bg-[#8eb02f] text-white px-4 py-2 rounded"
|
||||
x-on:click="window.open(`${window.location.origin}/${Archivo}`, '_blank')">
|
||||
Ver archivo
|
||||
</button>
|
||||
<button class="mt-4 bg-[#8eb02f] text-white px-4 py-2 rounded"
|
||||
x-on:click="viewModal = false">Cerrar</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Editar -->
|
||||
<div x-cloak x-show="editModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Editar deberes y derechos de usuario</h2>
|
||||
<form @submit.prevent="submitEdit">
|
||||
<label class="block mt-4 mb-2" for="editTitle">Título</label>
|
||||
<input id="editTitle" x-model="Title" class="border border-gray-300 rounded w-full p-2" required>
|
||||
|
||||
<label class="block mt-4 mb-2" for="editDescription">Descripción</label>
|
||||
<textarea id="editDescription" x-model="Description" class="border border-gray-300 rounded w-full p-2"
|
||||
required></textarea>
|
||||
|
||||
<label class="block mt-4 mb-2" for="editImagen">Imagen</label>
|
||||
<input type="file" id="editImagen" @change="handleUpdateFileChange($event, 'imagen')"
|
||||
class="border border-gray-300 rounded w-full p-2" accept="image/*">
|
||||
|
||||
<label class="block mb-2" for="editArchivo">Archivo</label>
|
||||
<input type="file" id="editArchivo" @change="handleUpdateFileChange($event, 'archivo')"
|
||||
class="border border-gray-300 rounded w-full p-2" accept=".jpg,.png,.pdf,.doc,.docx">
|
||||
|
||||
<label class="block mt-4 mb-2">Botón de Texto</label>
|
||||
<input type="text" x-model="Text_button" class="border border-gray-300 rounded w-full p-2" required>
|
||||
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar Cambios</button>
|
||||
<button type="button" class="bg-gray-600 text-white px-4 py-2 rounded"
|
||||
x-on:click="editModal = false">Cancelar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Añadir -->
|
||||
<div x-cloak x-show="addModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Agregar deberes y derechos de usuario</h2>
|
||||
<form @submit.prevent="submitAdd">
|
||||
<label class="block mt-4 mb-2" for="newTitle">Título</label>
|
||||
<input id="title" x-model="newTitle" class="border border-gray-300 rounded w-full p-2" required>
|
||||
|
||||
<label class="block mt-4 mb-2" for="newDescription">Descripción</label>
|
||||
<textarea id="description" x-model="newDescription" class="border border-gray-300 rounded w-full p-2"
|
||||
required></textarea>
|
||||
|
||||
<label class="block mt-4 mb-2" for="newImagen">Imagen</label>
|
||||
<input type="file" id="imagen" @change="handleFileChange($event, 'imagen')"
|
||||
class="border border-gray-300 rounded w-full p-2" accept="image/*" required>
|
||||
|
||||
<label class="block mb-2" for="newArchivo">Archivo</label>
|
||||
<input type="file" id="archivo" @change="handleFileChange($event, 'archivo')"
|
||||
class="border border-gray-300 rounded w-full p-2" accept=".jpg,.png,.pdf,.doc,.docx" required>
|
||||
|
||||
<label class="block mt-4 mb-2">Botón de Texto</label>
|
||||
<input type="text" id="text_button" x-model="newText_button"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar Publicación</button>
|
||||
<button type="button" class="bg-gray-600 text-white px-4 py-2 rounded"
|
||||
x-on:click="closeModal">Cancelar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Confirmar Eliminación -->
|
||||
<div x-cloak x-show="showConfirmModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-4">Confirmar Eliminación</h2>
|
||||
<p>¿Estás seguro de que deseas eliminar esta registro?</p>
|
||||
<div class="mt-4 flex justify-end">
|
||||
<button class="bg-red-500 text-white px-4 py-2 rounded mr-2" @click="deleteItem()">Eliminar</button>
|
||||
<button @click="closeModal" class="bg-gray-600 text-white px-4 py-2 rounded">Cancelar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Alpine.js Script -->
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('modals', () => ({
|
||||
addModal: false,
|
||||
editModal: false,
|
||||
viewModal: false,
|
||||
showConfirmModal: false,
|
||||
|
||||
newTitle: '',
|
||||
newDescription: '',
|
||||
newImagen: null, // Imagen para la carga
|
||||
newArchivo: null, // Archivo para la carga
|
||||
newText_button: '', // Botón de texto (como texto)
|
||||
|
||||
Title: '',
|
||||
Description: '',
|
||||
Imagen: '',
|
||||
Archivo: '',
|
||||
Text_button: '', // Botón de texto (como texto)
|
||||
updateImagen: null, // Imagen para la actualización
|
||||
updateArchivo: null, // Archivo para la actualización
|
||||
|
||||
sinregistro: '',
|
||||
Id: null,
|
||||
deleteId: null,
|
||||
loading: false,
|
||||
totalRecords: 0,
|
||||
isLoading: false,
|
||||
registros: '',
|
||||
|
||||
init() {
|
||||
this.loadRegister();
|
||||
},
|
||||
|
||||
searchQuery: '',
|
||||
|
||||
loadRegister(page = 1) {
|
||||
this.isLoading = true;
|
||||
const search = this.searchQuery ? `&search=${this.searchQuery}` : '';
|
||||
fetch(`/loaddeberesusuario?page=${page}${search}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log(data);
|
||||
this.totalRecords = data.total;
|
||||
this.registros = data.records;
|
||||
this.totalPages = data.totalPages;
|
||||
this.createPagination(this.totalPages, page);
|
||||
this.sinregistro = data.records.length === 0;
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.isLoading = false;
|
||||
});
|
||||
},
|
||||
|
||||
createPagination(totalPages, currentPage) {
|
||||
const paginationContainer = document.getElementById('pagination');
|
||||
paginationContainer.innerHTML = '';
|
||||
|
||||
const paginationButtonsContainer = document.createElement('div');
|
||||
paginationButtonsContainer.className = "md:flex mx-auto mb-2 md:justify-between items-center w-full";
|
||||
|
||||
const createButton = (text, isDisabled, onClick, additionalClasses = '') => {
|
||||
const button = document.createElement('button');
|
||||
button.textContent = text;
|
||||
button.disabled = isDisabled;
|
||||
button.className = `px-4 py-2 text-black bg-gray-200 ${additionalClasses} ${isDisabled ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-300'}`;
|
||||
if (!isDisabled) {
|
||||
button.onclick = onClick;
|
||||
}
|
||||
return button;
|
||||
};
|
||||
|
||||
const leftContainer = document.createElement('div');
|
||||
leftContainer.className = "md:flex text-center mb-2";
|
||||
leftContainer.appendChild(createButton('Anterior', currentPage === 1, () => this.loadRegister(currentPage - 1), 'rounded-l-md'));
|
||||
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
const pageButton = createButton(i, false, () => this.loadRegister(i), `mx-1 ${i === currentPage ? 'bg-black text-gray-50' : 'bg-white text-black'} rounded-md`);
|
||||
leftContainer.appendChild(pageButton);
|
||||
}
|
||||
|
||||
leftContainer.appendChild(createButton('Siguiente', currentPage === totalPages, () => this.loadRegister(currentPage + 1), 'rounded-r-md'));
|
||||
paginationButtonsContainer.appendChild(leftContainer);
|
||||
|
||||
const recordCountDiv = document.createElement('div');
|
||||
const startRecord = (currentPage - 1) * 10 + 1;
|
||||
const endRecord = Math.min(currentPage * 10, this.totalRecords);
|
||||
recordCountDiv.className = "text-sm text-gray-700 text-center md:ml-auto";
|
||||
recordCountDiv.innerHTML = `Mostrando ${startRecord} a ${endRecord} de ${this.totalRecords} registros`;
|
||||
|
||||
paginationButtonsContainer.appendChild(recordCountDiv);
|
||||
paginationContainer.appendChild(paginationButtonsContainer);
|
||||
},
|
||||
|
||||
closeModal() {
|
||||
this.addModal = false;
|
||||
this.editModal = false;
|
||||
this.viewModal = false;
|
||||
this.showConfirmModal = false;
|
||||
this.newImagen = null; // Reiniciar imagen
|
||||
this.newArchivo = null; // Reiniciar archivo
|
||||
this.updateImagen = null; // Reiniciar imagen de actualización
|
||||
this.updateArchivo = null; // Reiniciar archivo de actualización
|
||||
},
|
||||
|
||||
handleFileChange(event, field) {
|
||||
if (field === 'imagen') {
|
||||
this.newImagen = event.target.files[0];
|
||||
} else if (field === 'archivo') {
|
||||
this.newArchivo = event.target.files[0];
|
||||
}
|
||||
},
|
||||
|
||||
handleUpdateFileChange(event, field) {
|
||||
if (field === 'imagen') {
|
||||
this.updateImagen = event.target.files[0];
|
||||
} else if (field === 'archivo') {
|
||||
this.updateArchivo = event.target.files[0];
|
||||
}
|
||||
},
|
||||
|
||||
submitAdd() {
|
||||
this.loading = true;
|
||||
const formData = new FormData();
|
||||
formData.append('title', this.newTitle);
|
||||
formData.append('description', this.newDescription);
|
||||
formData.append('text_button', this.newText_button); // Guardar el texto
|
||||
if (this.newImagen) formData.append('imagen', this.newImagen); // Adjuntar la imagen si existe
|
||||
if (this.newArchivo) formData.append('archivo', this.newArchivo); // Adjuntar el archivo si existe
|
||||
|
||||
fetch('/app/deberesusuario', { // Cambié la ruta a 'politicashseq'
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.newTitle = '';
|
||||
this.newDescription = '';
|
||||
this.newText_button = '';
|
||||
this.newImagen = null;
|
||||
this.newArchivo = null;
|
||||
// Limpia los campos de archivo en el DOM
|
||||
document.getElementById('imagen').value = ''; // Restablece el input de imagen
|
||||
document.getElementById('archivo').value = ''; // Restablece el input de archivo
|
||||
this.closeModal();
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
submitEdit() {
|
||||
this.loading = true;
|
||||
const formData = new FormData();
|
||||
formData.append('title', this.Title);
|
||||
formData.append('description', this.Description);
|
||||
formData.append('text_button', this.Text_button); // Guardar el texto
|
||||
|
||||
// Adjuntar la imagen si existe, o usar la ruta de imagen
|
||||
if (this.updateImagen) {
|
||||
formData.append('imagen', this.updateImagen);
|
||||
} else if (this.Imagen) {
|
||||
formData.append('imagen', this.Imagen);
|
||||
}
|
||||
|
||||
// Adjuntar el archivo si existe, o usar la ruta del archivo
|
||||
if (this.updateArchivo) {
|
||||
formData.append('archivo', this.updateArchivo);
|
||||
} else if (this.Archivo) {
|
||||
formData.append('archivo', this.Archivo);
|
||||
}
|
||||
|
||||
fetch(`/app/deberesusuario/${this.Id}`, { // Cambié la ruta a 'politicashseq'
|
||||
method: 'PUT',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.Title = '';
|
||||
this.Description = '';
|
||||
this.Text_button = '';
|
||||
this.updateImagen = null;
|
||||
this.updateArchivo = null;
|
||||
|
||||
// Limpia los campos de archivo en el DOM
|
||||
document.getElementById('editImagen').value = ''; // Restablece el input de imagen
|
||||
document.getElementById('editArchivo').value = ''; // Restablece el input de archivo
|
||||
this.closeModal();
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
deleteItem() {
|
||||
this.loading = true;
|
||||
fetch(`/app/deberesusuario/${this.deleteId}`, { // Cambié la ruta a 'politicashseq'
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
})
|
||||
.then(() => {
|
||||
this.closeModal();
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
|
||||
<div class="email-container">
|
||||
<div class="email-header">Hola! 👋 ¡Gracias por registrarte en nuestra oficina virtual! 🖥️</div>
|
||||
<div class="email-content">
|
||||
Estamos emocionados de que te unas a nosotros. Antes de empezar, necesitamos confirmar tu dirección de correo electrónico para asegurarnos de que todo esté en orden.<br><br>
|
||||
🔒 Haz clic en el siguiente botón para confirmar tu registro:
|
||||
</div>
|
||||
<a href="{{.confirm_link}}" class="email-button">Confirmar Registro</a>
|
||||
<div class="email-content">
|
||||
<p>Si no puedes hacer clic en el botón, copia y pega este enlace en tu navegador:</p>
|
||||
<a href="{{.confirm_link}}">{{.confirm_link}}</a>
|
||||
</div>
|
||||
<div class="footer-note">
|
||||
📌 ¿No realizaste este registro? Ignora este correo, y tu cuenta no será activada.<br><br>
|
||||
Bienvenido a nuestra oficina virtual,<br>
|
||||
El equipo de Gases del Oriente 🚀
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,15 @@
|
||||
<div class="email-container">
|
||||
<div class="email-header">Hola! 👋 ¡Restablece tu contraseña! 🖥️</div>
|
||||
<div class="email-content">
|
||||
Por favor haz click en el siguiente boton para restablecer tu contraseña en la oficina virtual:
|
||||
</div>
|
||||
<a href="{{.reset_link}}" class="email-button">Restablecer contraseña</a>
|
||||
<div class="email-content">
|
||||
<p>Si no puedes hacer clic en el botón, copia y pega este enlace en tu navegador:</p>
|
||||
<a href="{{.reset_link}}">{{.reset_link}}</a>
|
||||
</div>
|
||||
<div class="footer-note">
|
||||
📌 ¿No realizaste esta solicitud? Ignora este correo..<br>
|
||||
El equipo de Gases del Oriente 🚀
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Simple HttpErrorPages | MIT License | https://github.com/AndiDittrich/HttpErrorPages -->
|
||||
<meta charset="utf-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>We've got some trouble | 400 - Bad Request</title>
|
||||
<style type="text/css">/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}template{display:none}[hidden]{display:none}/*! Simple HttpErrorPages | MIT X11 License | https://github.com/AndiDittrich/HttpErrorPages */body,html{width:100%;height:100%;background-color:#21232a}body{color:#fff;text-align:center;text-shadow:0 2px 4px rgba(0,0,0,.5);padding:0;min-height:100%;-webkit-box-shadow:inset 0 0 100px rgba(0,0,0,.8);box-shadow:inset 0 0 100px rgba(0,0,0,.8);display:table;font-family:"Open Sans",Arial,sans-serif}h1{font-family:inherit;font-weight:500;line-height:1.1;color:inherit;font-size:36px}h1 small{font-size:68%;font-weight:400;line-height:1;color:#777}a{text-decoration:none;color:#fff;font-size:inherit;border-bottom:dotted 1px #707070}.lead{color:silver;font-size:21px;line-height:1.4}.cover{display:table-cell;vertical-align:middle;padding:0 20px}footer{position:fixed;width:100%;height:40px;left:0;bottom:0;color:#a0a0a0;font-size:14px}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="cover"><h1>Bad Request <small>Error 400</small></h1><p class="lead">The server cannot process the request due to something that is perceived to be a client error.</p></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,285 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Simple HttpErrorPages | MIT License | https://github.com/AndiDittrich/HttpErrorPages -->
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>We've got some trouble | 401 - Unauthorized</title>
|
||||
<style type="text/css">/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
line-height: 1.15;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
article, aside, footer, header, nav, section {
|
||||
display: block
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: .67em 0
|
||||
}
|
||||
|
||||
figcaption, figure, main {
|
||||
display: block
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 1em 40px
|
||||
}
|
||||
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
-webkit-text-decoration-skip: objects
|
||||
}
|
||||
|
||||
a:active, a:hover {
|
||||
outline-width: 0
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: none;
|
||||
text-decoration: underline;
|
||||
text-decoration: underline dotted
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: inherit
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: bolder
|
||||
}
|
||||
|
||||
code, kbd, samp {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
dfn {
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
mark {
|
||||
background-color: #ff0;
|
||||
color: #000
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 80%
|
||||
}
|
||||
|
||||
sub, sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -.25em
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -.5em
|
||||
}
|
||||
|
||||
audio, video {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0
|
||||
}
|
||||
|
||||
img {
|
||||
border-style: none
|
||||
}
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
button, input, optgroup, select, textarea {
|
||||
font-family: sans-serif;
|
||||
font-size: 100%;
|
||||
line-height: 1.15;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
button, input {
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
button, select {
|
||||
text-transform: none
|
||||
}
|
||||
|
||||
[type=reset], [type=submit], button, html [type=button] {
|
||||
-webkit-appearance: button
|
||||
}
|
||||
|
||||
[type=button]::-moz-focus-inner, [type=reset]::-moz-focus-inner, [type=submit]::-moz-focus-inner, button::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
[type=button]:-moz-focusring, [type=reset]:-moz-focusring, [type=submit]:-moz-focusring, button:-moz-focusring {
|
||||
outline: 1px dotted ButtonText
|
||||
}
|
||||
|
||||
fieldset {
|
||||
border: 1px solid silver;
|
||||
margin: 0 2px;
|
||||
padding: .35em .625em .75em
|
||||
}
|
||||
|
||||
legend {
|
||||
box-sizing: border-box;
|
||||
color: inherit;
|
||||
display: table;
|
||||
max-width: 100%;
|
||||
padding: 0;
|
||||
white-space: normal
|
||||
}
|
||||
|
||||
progress {
|
||||
display: inline-block;
|
||||
vertical-align: baseline
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: auto
|
||||
}
|
||||
|
||||
[type=checkbox], [type=radio] {
|
||||
box-sizing: border-box;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
[type=number]::-webkit-inner-spin-button, [type=number]::-webkit-outer-spin-button {
|
||||
height: auto
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
-webkit-appearance: textfield;
|
||||
outline-offset: -2px
|
||||
}
|
||||
|
||||
[type=search]::-webkit-search-cancel-button, [type=search]::-webkit-search-decoration {
|
||||
-webkit-appearance: none
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button;
|
||||
font: inherit
|
||||
}
|
||||
|
||||
details, menu {
|
||||
display: block
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
template {
|
||||
display: none
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none
|
||||
}
|
||||
|
||||
/*! Simple HttpErrorPages | MIT X11 License | https://github.com/AndiDittrich/HttpErrorPages */
|
||||
body, html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #21232a
|
||||
}
|
||||
|
||||
body {
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, .5);
|
||||
padding: 0;
|
||||
min-height: 100%;
|
||||
-webkit-box-shadow: inset 0 0 100px rgba(0, 0, 0, .8);
|
||||
box-shadow: inset 0 0 100px rgba(0, 0, 0, .8);
|
||||
display: table;
|
||||
font-family: "Open Sans", Arial, sans-serif
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: inherit;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: inherit;
|
||||
font-size: 36px
|
||||
}
|
||||
|
||||
h1 small {
|
||||
font-size: 68%;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: #777
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
font-size: inherit;
|
||||
border-bottom: dotted 1px #707070
|
||||
}
|
||||
|
||||
.lead {
|
||||
color: silver;
|
||||
font-size: 21px;
|
||||
line-height: 1.4
|
||||
}
|
||||
|
||||
.cover {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
padding: 0 20px
|
||||
}
|
||||
|
||||
footer {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
color: #a0a0a0;
|
||||
font-size: 14px
|
||||
}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="cover"><h1>Unauthorized <small>Error 401</small></h1>
|
||||
<p class="lead">The requested resource requires an authentication.</p></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,285 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Simple HttpErrorPages | MIT License | https://github.com/AndiDittrich/HttpErrorPages -->
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>We've got some trouble | 403 - Access Denied</title>
|
||||
<style type="text/css">/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
line-height: 1.15;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
article, aside, footer, header, nav, section {
|
||||
display: block
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: .67em 0
|
||||
}
|
||||
|
||||
figcaption, figure, main {
|
||||
display: block
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 1em 40px
|
||||
}
|
||||
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
-webkit-text-decoration-skip: objects
|
||||
}
|
||||
|
||||
a:active, a:hover {
|
||||
outline-width: 0
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: none;
|
||||
text-decoration: underline;
|
||||
text-decoration: underline dotted
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: inherit
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: bolder
|
||||
}
|
||||
|
||||
code, kbd, samp {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
dfn {
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
mark {
|
||||
background-color: #ff0;
|
||||
color: #000
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 80%
|
||||
}
|
||||
|
||||
sub, sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -.25em
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -.5em
|
||||
}
|
||||
|
||||
audio, video {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0
|
||||
}
|
||||
|
||||
img {
|
||||
border-style: none
|
||||
}
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
button, input, optgroup, select, textarea {
|
||||
font-family: sans-serif;
|
||||
font-size: 100%;
|
||||
line-height: 1.15;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
button, input {
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
button, select {
|
||||
text-transform: none
|
||||
}
|
||||
|
||||
[type=reset], [type=submit], button, html [type=button] {
|
||||
-webkit-appearance: button
|
||||
}
|
||||
|
||||
[type=button]::-moz-focus-inner, [type=reset]::-moz-focus-inner, [type=submit]::-moz-focus-inner, button::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
[type=button]:-moz-focusring, [type=reset]:-moz-focusring, [type=submit]:-moz-focusring, button:-moz-focusring {
|
||||
outline: 1px dotted ButtonText
|
||||
}
|
||||
|
||||
fieldset {
|
||||
border: 1px solid silver;
|
||||
margin: 0 2px;
|
||||
padding: .35em .625em .75em
|
||||
}
|
||||
|
||||
legend {
|
||||
box-sizing: border-box;
|
||||
color: inherit;
|
||||
display: table;
|
||||
max-width: 100%;
|
||||
padding: 0;
|
||||
white-space: normal
|
||||
}
|
||||
|
||||
progress {
|
||||
display: inline-block;
|
||||
vertical-align: baseline
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: auto
|
||||
}
|
||||
|
||||
[type=checkbox], [type=radio] {
|
||||
box-sizing: border-box;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
[type=number]::-webkit-inner-spin-button, [type=number]::-webkit-outer-spin-button {
|
||||
height: auto
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
-webkit-appearance: textfield;
|
||||
outline-offset: -2px
|
||||
}
|
||||
|
||||
[type=search]::-webkit-search-cancel-button, [type=search]::-webkit-search-decoration {
|
||||
-webkit-appearance: none
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button;
|
||||
font: inherit
|
||||
}
|
||||
|
||||
details, menu {
|
||||
display: block
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
template {
|
||||
display: none
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none
|
||||
}
|
||||
|
||||
/*! Simple HttpErrorPages | MIT X11 License | https://github.com/AndiDittrich/HttpErrorPages */
|
||||
body, html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #21232a
|
||||
}
|
||||
|
||||
body {
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, .5);
|
||||
padding: 0;
|
||||
min-height: 100%;
|
||||
-webkit-box-shadow: inset 0 0 100px rgba(0, 0, 0, .8);
|
||||
box-shadow: inset 0 0 100px rgba(0, 0, 0, .8);
|
||||
display: table;
|
||||
font-family: "Open Sans", Arial, sans-serif
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: inherit;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: inherit;
|
||||
font-size: 36px
|
||||
}
|
||||
|
||||
h1 small {
|
||||
font-size: 68%;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: #777
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
font-size: inherit;
|
||||
border-bottom: dotted 1px #707070
|
||||
}
|
||||
|
||||
.lead {
|
||||
color: silver;
|
||||
font-size: 21px;
|
||||
line-height: 1.4
|
||||
}
|
||||
|
||||
.cover {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
padding: 0 20px
|
||||
}
|
||||
|
||||
footer {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
color: #a0a0a0;
|
||||
font-size: 14px
|
||||
}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="cover"><h1>Access Denied <small>Error 403</small></h1>
|
||||
<p class="lead">The requested resource requires an authentication.</p></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,285 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Simple HttpErrorPages | MIT License | https://github.com/AndiDittrich/HttpErrorPages -->
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>We've got some trouble | 404 - Resource not found</title>
|
||||
<style type="text/css">/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
line-height: 1.15;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
article, aside, footer, header, nav, section {
|
||||
display: block
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: .67em 0
|
||||
}
|
||||
|
||||
figcaption, figure, main {
|
||||
display: block
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 1em 40px
|
||||
}
|
||||
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
-webkit-text-decoration-skip: objects
|
||||
}
|
||||
|
||||
a:active, a:hover {
|
||||
outline-width: 0
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: none;
|
||||
text-decoration: underline;
|
||||
text-decoration: underline dotted
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: inherit
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: bolder
|
||||
}
|
||||
|
||||
code, kbd, samp {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
dfn {
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
mark {
|
||||
background-color: #ff0;
|
||||
color: #000
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 80%
|
||||
}
|
||||
|
||||
sub, sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -.25em
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -.5em
|
||||
}
|
||||
|
||||
audio, video {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0
|
||||
}
|
||||
|
||||
img {
|
||||
border-style: none
|
||||
}
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
button, input, optgroup, select, textarea {
|
||||
font-family: sans-serif;
|
||||
font-size: 100%;
|
||||
line-height: 1.15;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
button, input {
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
button, select {
|
||||
text-transform: none
|
||||
}
|
||||
|
||||
[type=reset], [type=submit], button, html [type=button] {
|
||||
-webkit-appearance: button
|
||||
}
|
||||
|
||||
[type=button]::-moz-focus-inner, [type=reset]::-moz-focus-inner, [type=submit]::-moz-focus-inner, button::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
[type=button]:-moz-focusring, [type=reset]:-moz-focusring, [type=submit]:-moz-focusring, button:-moz-focusring {
|
||||
outline: 1px dotted ButtonText
|
||||
}
|
||||
|
||||
fieldset {
|
||||
border: 1px solid silver;
|
||||
margin: 0 2px;
|
||||
padding: .35em .625em .75em
|
||||
}
|
||||
|
||||
legend {
|
||||
box-sizing: border-box;
|
||||
color: inherit;
|
||||
display: table;
|
||||
max-width: 100%;
|
||||
padding: 0;
|
||||
white-space: normal
|
||||
}
|
||||
|
||||
progress {
|
||||
display: inline-block;
|
||||
vertical-align: baseline
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: auto
|
||||
}
|
||||
|
||||
[type=checkbox], [type=radio] {
|
||||
box-sizing: border-box;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
[type=number]::-webkit-inner-spin-button, [type=number]::-webkit-outer-spin-button {
|
||||
height: auto
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
-webkit-appearance: textfield;
|
||||
outline-offset: -2px
|
||||
}
|
||||
|
||||
[type=search]::-webkit-search-cancel-button, [type=search]::-webkit-search-decoration {
|
||||
-webkit-appearance: none
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button;
|
||||
font: inherit
|
||||
}
|
||||
|
||||
details, menu {
|
||||
display: block
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
template {
|
||||
display: none
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none
|
||||
}
|
||||
|
||||
/*! Simple HttpErrorPages | MIT X11 License | https://github.com/AndiDittrich/HttpErrorPages */
|
||||
body, html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #21232a
|
||||
}
|
||||
|
||||
body {
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, .5);
|
||||
padding: 0;
|
||||
min-height: 100%;
|
||||
-webkit-box-shadow: inset 0 0 100px rgba(0, 0, 0, .8);
|
||||
box-shadow: inset 0 0 100px rgba(0, 0, 0, .8);
|
||||
display: table;
|
||||
font-family: "Open Sans", Arial, sans-serif
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: inherit;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: inherit;
|
||||
font-size: 36px
|
||||
}
|
||||
|
||||
h1 small {
|
||||
font-size: 68%;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: #777
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
font-size: inherit;
|
||||
border-bottom: dotted 1px #707070
|
||||
}
|
||||
|
||||
.lead {
|
||||
color: silver;
|
||||
font-size: 21px;
|
||||
line-height: 1.4
|
||||
}
|
||||
|
||||
.cover {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
padding: 0 20px
|
||||
}
|
||||
|
||||
footer {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
color: #a0a0a0;
|
||||
font-size: 14px
|
||||
}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="cover"><h1>Resource not found <small>Error 404</small></h1>
|
||||
<p class="lead">The requested resource could not be found but may be available again in the future.</p></div>
|
||||
<footer><p>Technical Contact: <a href="mailto:x@example.com">x@example.com</a></p></footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,293 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Simple HttpErrorPages | MIT License | https://github.com/AndiDittrich/HttpErrorPages -->
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>We've got some trouble | 500 - Webservice currently unavailable</title>
|
||||
<style type="text/css">/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
line-height: 1.15;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
article, aside, footer, header, nav, section {
|
||||
display: block
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: .67em 0
|
||||
}
|
||||
|
||||
figcaption, figure, main {
|
||||
display: block
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 1em 40px
|
||||
}
|
||||
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
-webkit-text-decoration-skip: objects
|
||||
}
|
||||
|
||||
a:active, a:hover {
|
||||
outline-width: 0
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: none;
|
||||
text-decoration: underline;
|
||||
text-decoration: underline dotted
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: inherit
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: bolder
|
||||
}
|
||||
|
||||
code, kbd, samp {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
dfn {
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
mark {
|
||||
background-color: #ff0;
|
||||
color: #000
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 80%
|
||||
}
|
||||
|
||||
sub, sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -.25em
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -.5em
|
||||
}
|
||||
|
||||
audio, video {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0
|
||||
}
|
||||
|
||||
img {
|
||||
border-style: none
|
||||
}
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
button, input, optgroup, select, textarea {
|
||||
font-family: sans-serif;
|
||||
font-size: 100%;
|
||||
line-height: 1.15;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
button, input {
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
button, select {
|
||||
text-transform: none
|
||||
}
|
||||
|
||||
[type=reset], [type=submit], button, html [type=button] {
|
||||
-webkit-appearance: button
|
||||
}
|
||||
|
||||
[type=button]::-moz-focus-inner, [type=reset]::-moz-focus-inner, [type=submit]::-moz-focus-inner, button::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
[type=button]:-moz-focusring, [type=reset]:-moz-focusring, [type=submit]:-moz-focusring, button:-moz-focusring {
|
||||
outline: 1px dotted ButtonText
|
||||
}
|
||||
|
||||
fieldset {
|
||||
border: 1px solid silver;
|
||||
margin: 0 2px;
|
||||
padding: .35em .625em .75em
|
||||
}
|
||||
|
||||
legend {
|
||||
box-sizing: border-box;
|
||||
color: inherit;
|
||||
display: table;
|
||||
max-width: 100%;
|
||||
padding: 0;
|
||||
white-space: normal
|
||||
}
|
||||
|
||||
progress {
|
||||
display: inline-block;
|
||||
vertical-align: baseline
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: auto
|
||||
}
|
||||
|
||||
[type=checkbox], [type=radio] {
|
||||
box-sizing: border-box;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
[type=number]::-webkit-inner-spin-button, [type=number]::-webkit-outer-spin-button {
|
||||
height: auto
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
-webkit-appearance: textfield;
|
||||
outline-offset: -2px
|
||||
}
|
||||
|
||||
[type=search]::-webkit-search-cancel-button, [type=search]::-webkit-search-decoration {
|
||||
-webkit-appearance: none
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button;
|
||||
font: inherit
|
||||
}
|
||||
|
||||
details, menu {
|
||||
display: block
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
template {
|
||||
display: none
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none
|
||||
}
|
||||
|
||||
/*! Simple HttpErrorPages | MIT X11 License | https://github.com/AndiDittrich/HttpErrorPages */
|
||||
body, html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #21232a
|
||||
}
|
||||
|
||||
body {
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, .5);
|
||||
padding: 0;
|
||||
min-height: 100%;
|
||||
-webkit-box-shadow: inset 0 0 100px rgba(0, 0, 0, .8);
|
||||
box-shadow: inset 0 0 100px rgba(0, 0, 0, .8);
|
||||
display: table;
|
||||
font-family: "Open Sans", Arial, sans-serif
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: inherit;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: inherit;
|
||||
font-size: 36px
|
||||
}
|
||||
|
||||
h1 small {
|
||||
font-size: 68%;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: #777
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
font-size: inherit;
|
||||
border-bottom: dotted 1px #707070
|
||||
}
|
||||
|
||||
.lead {
|
||||
color: silver;
|
||||
font-size: 21px;
|
||||
line-height: 1.4
|
||||
}
|
||||
|
||||
.cover {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
padding: 0 20px
|
||||
}
|
||||
|
||||
footer {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
color: #a0a0a0;
|
||||
font-size: 14px
|
||||
}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="cover"><h1>Webservice currently unavailable <small>Error 500</small></h1>
|
||||
<p class="lead">An unexpected condition was encountered.<br/>Our service team has been dispatched to bring it back
|
||||
online.
|
||||
</p>
|
||||
<p class="lead">
|
||||
<code>
|
||||
{{ .error }}
|
||||
</code>
|
||||
</p>
|
||||
</div>
|
||||
<footer><p>Technical Contact: <a href="mailto:x@example.com">x@example.com</a></p></footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,285 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Simple HttpErrorPages | MIT License | https://github.com/AndiDittrich/HttpErrorPages -->
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>We've got some trouble | 501 - Not Implemented</title>
|
||||
<style type="text/css">/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
line-height: 1.15;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
article, aside, footer, header, nav, section {
|
||||
display: block
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: .67em 0
|
||||
}
|
||||
|
||||
figcaption, figure, main {
|
||||
display: block
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 1em 40px
|
||||
}
|
||||
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
-webkit-text-decoration-skip: objects
|
||||
}
|
||||
|
||||
a:active, a:hover {
|
||||
outline-width: 0
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: none;
|
||||
text-decoration: underline;
|
||||
text-decoration: underline dotted
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: inherit
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: bolder
|
||||
}
|
||||
|
||||
code, kbd, samp {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
dfn {
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
mark {
|
||||
background-color: #ff0;
|
||||
color: #000
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 80%
|
||||
}
|
||||
|
||||
sub, sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -.25em
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -.5em
|
||||
}
|
||||
|
||||
audio, video {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0
|
||||
}
|
||||
|
||||
img {
|
||||
border-style: none
|
||||
}
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
button, input, optgroup, select, textarea {
|
||||
font-family: sans-serif;
|
||||
font-size: 100%;
|
||||
line-height: 1.15;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
button, input {
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
button, select {
|
||||
text-transform: none
|
||||
}
|
||||
|
||||
[type=reset], [type=submit], button, html [type=button] {
|
||||
-webkit-appearance: button
|
||||
}
|
||||
|
||||
[type=button]::-moz-focus-inner, [type=reset]::-moz-focus-inner, [type=submit]::-moz-focus-inner, button::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
[type=button]:-moz-focusring, [type=reset]:-moz-focusring, [type=submit]:-moz-focusring, button:-moz-focusring {
|
||||
outline: 1px dotted ButtonText
|
||||
}
|
||||
|
||||
fieldset {
|
||||
border: 1px solid silver;
|
||||
margin: 0 2px;
|
||||
padding: .35em .625em .75em
|
||||
}
|
||||
|
||||
legend {
|
||||
box-sizing: border-box;
|
||||
color: inherit;
|
||||
display: table;
|
||||
max-width: 100%;
|
||||
padding: 0;
|
||||
white-space: normal
|
||||
}
|
||||
|
||||
progress {
|
||||
display: inline-block;
|
||||
vertical-align: baseline
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: auto
|
||||
}
|
||||
|
||||
[type=checkbox], [type=radio] {
|
||||
box-sizing: border-box;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
[type=number]::-webkit-inner-spin-button, [type=number]::-webkit-outer-spin-button {
|
||||
height: auto
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
-webkit-appearance: textfield;
|
||||
outline-offset: -2px
|
||||
}
|
||||
|
||||
[type=search]::-webkit-search-cancel-button, [type=search]::-webkit-search-decoration {
|
||||
-webkit-appearance: none
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button;
|
||||
font: inherit
|
||||
}
|
||||
|
||||
details, menu {
|
||||
display: block
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
template {
|
||||
display: none
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none
|
||||
}
|
||||
|
||||
/*! Simple HttpErrorPages | MIT X11 License | https://github.com/AndiDittrich/HttpErrorPages */
|
||||
body, html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #21232a
|
||||
}
|
||||
|
||||
body {
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, .5);
|
||||
padding: 0;
|
||||
min-height: 100%;
|
||||
-webkit-box-shadow: inset 0 0 100px rgba(0, 0, 0, .8);
|
||||
box-shadow: inset 0 0 100px rgba(0, 0, 0, .8);
|
||||
display: table;
|
||||
font-family: "Open Sans", Arial, sans-serif
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: inherit;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: inherit;
|
||||
font-size: 36px
|
||||
}
|
||||
|
||||
h1 small {
|
||||
font-size: 68%;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: #777
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
font-size: inherit;
|
||||
border-bottom: dotted 1px #707070
|
||||
}
|
||||
|
||||
.lead {
|
||||
color: silver;
|
||||
font-size: 21px;
|
||||
line-height: 1.4
|
||||
}
|
||||
|
||||
.cover {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
padding: 0 20px
|
||||
}
|
||||
|
||||
footer {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
color: #a0a0a0;
|
||||
font-size: 14px
|
||||
}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="cover"><h1>Not Implemented <small>Error 501</small></h1>
|
||||
<p class="lead">The Webserver cannot recognize the request method.</p></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,286 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Simple HttpErrorPages | MIT License | https://github.com/AndiDittrich/HttpErrorPages -->
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>We've got some trouble | 502 - Webservice currently unavailable</title>
|
||||
<style type="text/css">/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
line-height: 1.15;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
article, aside, footer, header, nav, section {
|
||||
display: block
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: .67em 0
|
||||
}
|
||||
|
||||
figcaption, figure, main {
|
||||
display: block
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 1em 40px
|
||||
}
|
||||
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
-webkit-text-decoration-skip: objects
|
||||
}
|
||||
|
||||
a:active, a:hover {
|
||||
outline-width: 0
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: none;
|
||||
text-decoration: underline;
|
||||
text-decoration: underline dotted
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: inherit
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: bolder
|
||||
}
|
||||
|
||||
code, kbd, samp {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
dfn {
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
mark {
|
||||
background-color: #ff0;
|
||||
color: #000
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 80%
|
||||
}
|
||||
|
||||
sub, sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -.25em
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -.5em
|
||||
}
|
||||
|
||||
audio, video {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0
|
||||
}
|
||||
|
||||
img {
|
||||
border-style: none
|
||||
}
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
button, input, optgroup, select, textarea {
|
||||
font-family: sans-serif;
|
||||
font-size: 100%;
|
||||
line-height: 1.15;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
button, input {
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
button, select {
|
||||
text-transform: none
|
||||
}
|
||||
|
||||
[type=reset], [type=submit], button, html [type=button] {
|
||||
-webkit-appearance: button
|
||||
}
|
||||
|
||||
[type=button]::-moz-focus-inner, [type=reset]::-moz-focus-inner, [type=submit]::-moz-focus-inner, button::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
[type=button]:-moz-focusring, [type=reset]:-moz-focusring, [type=submit]:-moz-focusring, button:-moz-focusring {
|
||||
outline: 1px dotted ButtonText
|
||||
}
|
||||
|
||||
fieldset {
|
||||
border: 1px solid silver;
|
||||
margin: 0 2px;
|
||||
padding: .35em .625em .75em
|
||||
}
|
||||
|
||||
legend {
|
||||
box-sizing: border-box;
|
||||
color: inherit;
|
||||
display: table;
|
||||
max-width: 100%;
|
||||
padding: 0;
|
||||
white-space: normal
|
||||
}
|
||||
|
||||
progress {
|
||||
display: inline-block;
|
||||
vertical-align: baseline
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: auto
|
||||
}
|
||||
|
||||
[type=checkbox], [type=radio] {
|
||||
box-sizing: border-box;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
[type=number]::-webkit-inner-spin-button, [type=number]::-webkit-outer-spin-button {
|
||||
height: auto
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
-webkit-appearance: textfield;
|
||||
outline-offset: -2px
|
||||
}
|
||||
|
||||
[type=search]::-webkit-search-cancel-button, [type=search]::-webkit-search-decoration {
|
||||
-webkit-appearance: none
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button;
|
||||
font: inherit
|
||||
}
|
||||
|
||||
details, menu {
|
||||
display: block
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
template {
|
||||
display: none
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none
|
||||
}
|
||||
|
||||
/*! Simple HttpErrorPages | MIT X11 License | https://github.com/AndiDittrich/HttpErrorPages */
|
||||
body, html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #21232a
|
||||
}
|
||||
|
||||
body {
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, .5);
|
||||
padding: 0;
|
||||
min-height: 100%;
|
||||
-webkit-box-shadow: inset 0 0 100px rgba(0, 0, 0, .8);
|
||||
box-shadow: inset 0 0 100px rgba(0, 0, 0, .8);
|
||||
display: table;
|
||||
font-family: "Open Sans", Arial, sans-serif
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: inherit;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: inherit;
|
||||
font-size: 36px
|
||||
}
|
||||
|
||||
h1 small {
|
||||
font-size: 68%;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: #777
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
font-size: inherit;
|
||||
border-bottom: dotted 1px #707070
|
||||
}
|
||||
|
||||
.lead {
|
||||
color: silver;
|
||||
font-size: 21px;
|
||||
line-height: 1.4
|
||||
}
|
||||
|
||||
.cover {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
padding: 0 20px
|
||||
}
|
||||
|
||||
footer {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
color: #a0a0a0;
|
||||
font-size: 14px
|
||||
}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="cover"><h1>Webservice currently unavailable <small>Error 502</small></h1>
|
||||
<p class="lead">We've got some trouble with our backend upstream cluster.<br/>Our service team has been
|
||||
dispatched to bring it back online.</p></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,286 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Simple HttpErrorPages | MIT License | https://github.com/AndiDittrich/HttpErrorPages -->
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>We've got some trouble | 503 - Webservice currently unavailable</title>
|
||||
<style type="text/css">/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
line-height: 1.15;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
article, aside, footer, header, nav, section {
|
||||
display: block
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: .67em 0
|
||||
}
|
||||
|
||||
figcaption, figure, main {
|
||||
display: block
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 1em 40px
|
||||
}
|
||||
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
-webkit-text-decoration-skip: objects
|
||||
}
|
||||
|
||||
a:active, a:hover {
|
||||
outline-width: 0
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: none;
|
||||
text-decoration: underline;
|
||||
text-decoration: underline dotted
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: inherit
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: bolder
|
||||
}
|
||||
|
||||
code, kbd, samp {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
dfn {
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
mark {
|
||||
background-color: #ff0;
|
||||
color: #000
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 80%
|
||||
}
|
||||
|
||||
sub, sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -.25em
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -.5em
|
||||
}
|
||||
|
||||
audio, video {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0
|
||||
}
|
||||
|
||||
img {
|
||||
border-style: none
|
||||
}
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
button, input, optgroup, select, textarea {
|
||||
font-family: sans-serif;
|
||||
font-size: 100%;
|
||||
line-height: 1.15;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
button, input {
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
button, select {
|
||||
text-transform: none
|
||||
}
|
||||
|
||||
[type=reset], [type=submit], button, html [type=button] {
|
||||
-webkit-appearance: button
|
||||
}
|
||||
|
||||
[type=button]::-moz-focus-inner, [type=reset]::-moz-focus-inner, [type=submit]::-moz-focus-inner, button::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
[type=button]:-moz-focusring, [type=reset]:-moz-focusring, [type=submit]:-moz-focusring, button:-moz-focusring {
|
||||
outline: 1px dotted ButtonText
|
||||
}
|
||||
|
||||
fieldset {
|
||||
border: 1px solid silver;
|
||||
margin: 0 2px;
|
||||
padding: .35em .625em .75em
|
||||
}
|
||||
|
||||
legend {
|
||||
box-sizing: border-box;
|
||||
color: inherit;
|
||||
display: table;
|
||||
max-width: 100%;
|
||||
padding: 0;
|
||||
white-space: normal
|
||||
}
|
||||
|
||||
progress {
|
||||
display: inline-block;
|
||||
vertical-align: baseline
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: auto
|
||||
}
|
||||
|
||||
[type=checkbox], [type=radio] {
|
||||
box-sizing: border-box;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
[type=number]::-webkit-inner-spin-button, [type=number]::-webkit-outer-spin-button {
|
||||
height: auto
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
-webkit-appearance: textfield;
|
||||
outline-offset: -2px
|
||||
}
|
||||
|
||||
[type=search]::-webkit-search-cancel-button, [type=search]::-webkit-search-decoration {
|
||||
-webkit-appearance: none
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button;
|
||||
font: inherit
|
||||
}
|
||||
|
||||
details, menu {
|
||||
display: block
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
template {
|
||||
display: none
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none
|
||||
}
|
||||
|
||||
/*! Simple HttpErrorPages | MIT X11 License | https://github.com/AndiDittrich/HttpErrorPages */
|
||||
body, html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #21232a
|
||||
}
|
||||
|
||||
body {
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, .5);
|
||||
padding: 0;
|
||||
min-height: 100%;
|
||||
-webkit-box-shadow: inset 0 0 100px rgba(0, 0, 0, .8);
|
||||
box-shadow: inset 0 0 100px rgba(0, 0, 0, .8);
|
||||
display: table;
|
||||
font-family: "Open Sans", Arial, sans-serif
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: inherit;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: inherit;
|
||||
font-size: 36px
|
||||
}
|
||||
|
||||
h1 small {
|
||||
font-size: 68%;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: #777
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
font-size: inherit;
|
||||
border-bottom: dotted 1px #707070
|
||||
}
|
||||
|
||||
.lead {
|
||||
color: silver;
|
||||
font-size: 21px;
|
||||
line-height: 1.4
|
||||
}
|
||||
|
||||
.cover {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
padding: 0 20px
|
||||
}
|
||||
|
||||
footer {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
color: #a0a0a0;
|
||||
font-size: 14px
|
||||
}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="cover"><h1>Webservice currently unavailable <small>Error 503</small></h1>
|
||||
<p class="lead">We've got some trouble with our backend upstream cluster.<br/>Our service team has been
|
||||
dispatched to bring it back online.</p></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,285 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Simple HttpErrorPages | MIT License | https://github.com/AndiDittrich/HttpErrorPages -->
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>We've got some trouble | 520 - Origin Error - Unknown Host</title>
|
||||
<style type="text/css">/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
line-height: 1.15;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
article, aside, footer, header, nav, section {
|
||||
display: block
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: .67em 0
|
||||
}
|
||||
|
||||
figcaption, figure, main {
|
||||
display: block
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 1em 40px
|
||||
}
|
||||
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
-webkit-text-decoration-skip: objects
|
||||
}
|
||||
|
||||
a:active, a:hover {
|
||||
outline-width: 0
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: none;
|
||||
text-decoration: underline;
|
||||
text-decoration: underline dotted
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: inherit
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: bolder
|
||||
}
|
||||
|
||||
code, kbd, samp {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
dfn {
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
mark {
|
||||
background-color: #ff0;
|
||||
color: #000
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 80%
|
||||
}
|
||||
|
||||
sub, sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -.25em
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -.5em
|
||||
}
|
||||
|
||||
audio, video {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0
|
||||
}
|
||||
|
||||
img {
|
||||
border-style: none
|
||||
}
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
button, input, optgroup, select, textarea {
|
||||
font-family: sans-serif;
|
||||
font-size: 100%;
|
||||
line-height: 1.15;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
button, input {
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
button, select {
|
||||
text-transform: none
|
||||
}
|
||||
|
||||
[type=reset], [type=submit], button, html [type=button] {
|
||||
-webkit-appearance: button
|
||||
}
|
||||
|
||||
[type=button]::-moz-focus-inner, [type=reset]::-moz-focus-inner, [type=submit]::-moz-focus-inner, button::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
[type=button]:-moz-focusring, [type=reset]:-moz-focusring, [type=submit]:-moz-focusring, button:-moz-focusring {
|
||||
outline: 1px dotted ButtonText
|
||||
}
|
||||
|
||||
fieldset {
|
||||
border: 1px solid silver;
|
||||
margin: 0 2px;
|
||||
padding: .35em .625em .75em
|
||||
}
|
||||
|
||||
legend {
|
||||
box-sizing: border-box;
|
||||
color: inherit;
|
||||
display: table;
|
||||
max-width: 100%;
|
||||
padding: 0;
|
||||
white-space: normal
|
||||
}
|
||||
|
||||
progress {
|
||||
display: inline-block;
|
||||
vertical-align: baseline
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: auto
|
||||
}
|
||||
|
||||
[type=checkbox], [type=radio] {
|
||||
box-sizing: border-box;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
[type=number]::-webkit-inner-spin-button, [type=number]::-webkit-outer-spin-button {
|
||||
height: auto
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
-webkit-appearance: textfield;
|
||||
outline-offset: -2px
|
||||
}
|
||||
|
||||
[type=search]::-webkit-search-cancel-button, [type=search]::-webkit-search-decoration {
|
||||
-webkit-appearance: none
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button;
|
||||
font: inherit
|
||||
}
|
||||
|
||||
details, menu {
|
||||
display: block
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
template {
|
||||
display: none
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none
|
||||
}
|
||||
|
||||
/*! Simple HttpErrorPages | MIT X11 License | https://github.com/AndiDittrich/HttpErrorPages */
|
||||
body, html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #21232a
|
||||
}
|
||||
|
||||
body {
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, .5);
|
||||
padding: 0;
|
||||
min-height: 100%;
|
||||
-webkit-box-shadow: inset 0 0 100px rgba(0, 0, 0, .8);
|
||||
box-shadow: inset 0 0 100px rgba(0, 0, 0, .8);
|
||||
display: table;
|
||||
font-family: "Open Sans", Arial, sans-serif
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: inherit;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: inherit;
|
||||
font-size: 36px
|
||||
}
|
||||
|
||||
h1 small {
|
||||
font-size: 68%;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: #777
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
font-size: inherit;
|
||||
border-bottom: dotted 1px #707070
|
||||
}
|
||||
|
||||
.lead {
|
||||
color: silver;
|
||||
font-size: 21px;
|
||||
line-height: 1.4
|
||||
}
|
||||
|
||||
.cover {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
padding: 0 20px
|
||||
}
|
||||
|
||||
footer {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
color: #a0a0a0;
|
||||
font-size: 14px
|
||||
}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="cover"><h1>Origin Error - Unknown Host <small>Error 520</small></h1>
|
||||
<p class="lead">The requested hostname is not routed. Use only hostnames to access resources.</p></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,286 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Simple HttpErrorPages | MIT License | https://github.com/AndiDittrich/HttpErrorPages -->
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>We've got some trouble | 521 - Webservice currently unavailable</title>
|
||||
<style type="text/css">/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
line-height: 1.15;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
article, aside, footer, header, nav, section {
|
||||
display: block
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: .67em 0
|
||||
}
|
||||
|
||||
figcaption, figure, main {
|
||||
display: block
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 1em 40px
|
||||
}
|
||||
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
-webkit-text-decoration-skip: objects
|
||||
}
|
||||
|
||||
a:active, a:hover {
|
||||
outline-width: 0
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: none;
|
||||
text-decoration: underline;
|
||||
text-decoration: underline dotted
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: inherit
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: bolder
|
||||
}
|
||||
|
||||
code, kbd, samp {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
dfn {
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
mark {
|
||||
background-color: #ff0;
|
||||
color: #000
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 80%
|
||||
}
|
||||
|
||||
sub, sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -.25em
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -.5em
|
||||
}
|
||||
|
||||
audio, video {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0
|
||||
}
|
||||
|
||||
img {
|
||||
border-style: none
|
||||
}
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
button, input, optgroup, select, textarea {
|
||||
font-family: sans-serif;
|
||||
font-size: 100%;
|
||||
line-height: 1.15;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
button, input {
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
button, select {
|
||||
text-transform: none
|
||||
}
|
||||
|
||||
[type=reset], [type=submit], button, html [type=button] {
|
||||
-webkit-appearance: button
|
||||
}
|
||||
|
||||
[type=button]::-moz-focus-inner, [type=reset]::-moz-focus-inner, [type=submit]::-moz-focus-inner, button::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
[type=button]:-moz-focusring, [type=reset]:-moz-focusring, [type=submit]:-moz-focusring, button:-moz-focusring {
|
||||
outline: 1px dotted ButtonText
|
||||
}
|
||||
|
||||
fieldset {
|
||||
border: 1px solid silver;
|
||||
margin: 0 2px;
|
||||
padding: .35em .625em .75em
|
||||
}
|
||||
|
||||
legend {
|
||||
box-sizing: border-box;
|
||||
color: inherit;
|
||||
display: table;
|
||||
max-width: 100%;
|
||||
padding: 0;
|
||||
white-space: normal
|
||||
}
|
||||
|
||||
progress {
|
||||
display: inline-block;
|
||||
vertical-align: baseline
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: auto
|
||||
}
|
||||
|
||||
[type=checkbox], [type=radio] {
|
||||
box-sizing: border-box;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
[type=number]::-webkit-inner-spin-button, [type=number]::-webkit-outer-spin-button {
|
||||
height: auto
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
-webkit-appearance: textfield;
|
||||
outline-offset: -2px
|
||||
}
|
||||
|
||||
[type=search]::-webkit-search-cancel-button, [type=search]::-webkit-search-decoration {
|
||||
-webkit-appearance: none
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button;
|
||||
font: inherit
|
||||
}
|
||||
|
||||
details, menu {
|
||||
display: block
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
template {
|
||||
display: none
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none
|
||||
}
|
||||
|
||||
/*! Simple HttpErrorPages | MIT X11 License | https://github.com/AndiDittrich/HttpErrorPages */
|
||||
body, html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #21232a
|
||||
}
|
||||
|
||||
body {
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, .5);
|
||||
padding: 0;
|
||||
min-height: 100%;
|
||||
-webkit-box-shadow: inset 0 0 100px rgba(0, 0, 0, .8);
|
||||
box-shadow: inset 0 0 100px rgba(0, 0, 0, .8);
|
||||
display: table;
|
||||
font-family: "Open Sans", Arial, sans-serif
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: inherit;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: inherit;
|
||||
font-size: 36px
|
||||
}
|
||||
|
||||
h1 small {
|
||||
font-size: 68%;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: #777
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
font-size: inherit;
|
||||
border-bottom: dotted 1px #707070
|
||||
}
|
||||
|
||||
.lead {
|
||||
color: silver;
|
||||
font-size: 21px;
|
||||
line-height: 1.4
|
||||
}
|
||||
|
||||
.cover {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
padding: 0 20px
|
||||
}
|
||||
|
||||
footer {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
color: #a0a0a0;
|
||||
font-size: 14px
|
||||
}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="cover"><h1>Webservice currently unavailable <small>Error 521</small></h1>
|
||||
<p class="lead">We've got some trouble with our backend upstream cluster.<br/>Our service team has been
|
||||
dispatched to bring it back online.</p></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,286 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Simple HttpErrorPages | MIT License | https://github.com/AndiDittrich/HttpErrorPages -->
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>We've got some trouble | 533 - Scheduled Maintenance</title>
|
||||
<style type="text/css">/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
line-height: 1.15;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
article, aside, footer, header, nav, section {
|
||||
display: block
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: .67em 0
|
||||
}
|
||||
|
||||
figcaption, figure, main {
|
||||
display: block
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 1em 40px
|
||||
}
|
||||
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
-webkit-text-decoration-skip: objects
|
||||
}
|
||||
|
||||
a:active, a:hover {
|
||||
outline-width: 0
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: none;
|
||||
text-decoration: underline;
|
||||
text-decoration: underline dotted
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: inherit
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: bolder
|
||||
}
|
||||
|
||||
code, kbd, samp {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
dfn {
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
mark {
|
||||
background-color: #ff0;
|
||||
color: #000
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 80%
|
||||
}
|
||||
|
||||
sub, sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -.25em
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -.5em
|
||||
}
|
||||
|
||||
audio, video {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0
|
||||
}
|
||||
|
||||
img {
|
||||
border-style: none
|
||||
}
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
button, input, optgroup, select, textarea {
|
||||
font-family: sans-serif;
|
||||
font-size: 100%;
|
||||
line-height: 1.15;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
button, input {
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
button, select {
|
||||
text-transform: none
|
||||
}
|
||||
|
||||
[type=reset], [type=submit], button, html [type=button] {
|
||||
-webkit-appearance: button
|
||||
}
|
||||
|
||||
[type=button]::-moz-focus-inner, [type=reset]::-moz-focus-inner, [type=submit]::-moz-focus-inner, button::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
[type=button]:-moz-focusring, [type=reset]:-moz-focusring, [type=submit]:-moz-focusring, button:-moz-focusring {
|
||||
outline: 1px dotted ButtonText
|
||||
}
|
||||
|
||||
fieldset {
|
||||
border: 1px solid silver;
|
||||
margin: 0 2px;
|
||||
padding: .35em .625em .75em
|
||||
}
|
||||
|
||||
legend {
|
||||
box-sizing: border-box;
|
||||
color: inherit;
|
||||
display: table;
|
||||
max-width: 100%;
|
||||
padding: 0;
|
||||
white-space: normal
|
||||
}
|
||||
|
||||
progress {
|
||||
display: inline-block;
|
||||
vertical-align: baseline
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: auto
|
||||
}
|
||||
|
||||
[type=checkbox], [type=radio] {
|
||||
box-sizing: border-box;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
[type=number]::-webkit-inner-spin-button, [type=number]::-webkit-outer-spin-button {
|
||||
height: auto
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
-webkit-appearance: textfield;
|
||||
outline-offset: -2px
|
||||
}
|
||||
|
||||
[type=search]::-webkit-search-cancel-button, [type=search]::-webkit-search-decoration {
|
||||
-webkit-appearance: none
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button;
|
||||
font: inherit
|
||||
}
|
||||
|
||||
details, menu {
|
||||
display: block
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
template {
|
||||
display: none
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none
|
||||
}
|
||||
|
||||
/*! Simple HttpErrorPages | MIT X11 License | https://github.com/AndiDittrich/HttpErrorPages */
|
||||
body, html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #21232a
|
||||
}
|
||||
|
||||
body {
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, .5);
|
||||
padding: 0;
|
||||
min-height: 100%;
|
||||
-webkit-box-shadow: inset 0 0 100px rgba(0, 0, 0, .8);
|
||||
box-shadow: inset 0 0 100px rgba(0, 0, 0, .8);
|
||||
display: table;
|
||||
font-family: "Open Sans", Arial, sans-serif
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: inherit;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: inherit;
|
||||
font-size: 36px
|
||||
}
|
||||
|
||||
h1 small {
|
||||
font-size: 68%;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: #777
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
font-size: inherit;
|
||||
border-bottom: dotted 1px #707070
|
||||
}
|
||||
|
||||
.lead {
|
||||
color: silver;
|
||||
font-size: 21px;
|
||||
line-height: 1.4
|
||||
}
|
||||
|
||||
.cover {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
padding: 0 20px
|
||||
}
|
||||
|
||||
footer {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
color: #a0a0a0;
|
||||
font-size: 14px
|
||||
}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="cover"><h1>Scheduled Maintenance <small>Error 533</small></h1>
|
||||
<p class="lead">This site is currently down for maintenance.<br/>Our service team is working hard to bring it back
|
||||
online soon.</p></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
{{template "partials/file-upload" .}}
|
||||
|
||||
{{template "partials/footer" .}}
|
||||
@@ -0,0 +1,223 @@
|
||||
<div class="float-left flex-row w-3/4 scrolling-auto">
|
||||
<div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-semibold leading-tight">Users</h2>
|
||||
</div>
|
||||
<div class="my-2 flex sm:flex-row flex-col">
|
||||
<div class="flex flex-row mb-1 sm:mb-0">
|
||||
<div class="relative">
|
||||
<select
|
||||
class="appearance-none h-full rounded-l border block appearance-none w-full bg-white border-gray-400 text-gray-700 py-2 px-4 pr-8 leading-tight focus:outline-none focus:bg-white focus:border-gray-500">
|
||||
<option>5</option>
|
||||
<option>10</option>
|
||||
<option>20</option>
|
||||
</select>
|
||||
<div
|
||||
class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700">
|
||||
<svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
|
||||
<path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative">
|
||||
<select
|
||||
class="appearance-none h-full rounded-r border-t sm:rounded-r-none sm:border-r-0 border-r border-b block appearance-none w-full bg-white border-gray-400 text-gray-700 py-2 px-4 pr-8 leading-tight focus:outline-none focus:border-l focus:border-r focus:bg-white focus:border-gray-500">
|
||||
<option>All</option>
|
||||
<option>Active</option>
|
||||
<option>Inactive</option>
|
||||
</select>
|
||||
<div
|
||||
class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700">
|
||||
<svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
|
||||
<path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="block relative">
|
||||
<span class="h-full absolute inset-y-0 left-0 flex items-center pl-2">
|
||||
<svg viewBox="0 0 24 24" class="h-4 w-4 fill-current text-gray-500">
|
||||
<path
|
||||
d="M10 4a6 6 0 100 12 6 6 0 000-12zm-8 6a8 8 0 1114.32 4.906l5.387 5.387a1 1 0 01-1.414 1.414l-5.387-5.387A8 8 0 012 10z">
|
||||
</path>
|
||||
</svg>
|
||||
</span>
|
||||
<input placeholder="Search"
|
||||
class="appearance-none rounded-r rounded-l sm:rounded-l-none border border-gray-400 border-b block pl-8 pr-6 py-2 w-full bg-white text-sm placeholder-gray-400 text-gray-700 focus:bg-white focus:placeholder-gray-600 focus:text-gray-700 focus:outline-none"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="-mx-4 sm:-mx-8 px-4 sm:px-8 py-4 overflow-x-auto">
|
||||
<div class="inline-block min-w-full shadow rounded-lg overflow-hidden">
|
||||
<table class="min-w-full leading-normal">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
class="px-5 py-3 border-b-2 border-gray-200 bg-gray-100 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">
|
||||
User
|
||||
</th>
|
||||
<th
|
||||
class="px-5 py-3 border-b-2 border-gray-200 bg-gray-100 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">
|
||||
Rol
|
||||
</th>
|
||||
<th
|
||||
class="px-5 py-3 border-b-2 border-gray-200 bg-gray-100 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">
|
||||
Created at
|
||||
</th>
|
||||
<th
|
||||
class="px-5 py-3 border-b-2 border-gray-200 bg-gray-100 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">
|
||||
Status
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0 w-10 h-10">
|
||||
<img class="w-full h-full rounded-full"
|
||||
src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2.2&w=160&h=160&q=80"
|
||||
alt=""/>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-gray-900 whitespace-no-wrap">
|
||||
Vera Carpenter
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
|
||||
<p class="text-gray-900 whitespace-no-wrap">Admin</p>
|
||||
</td>
|
||||
<td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
|
||||
<p class="text-gray-900 whitespace-no-wrap">
|
||||
Jan 21, 2020
|
||||
</p>
|
||||
</td>
|
||||
<td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
|
||||
<span
|
||||
class="relative inline-block px-3 py-1 font-semibold text-green-900 leading-tight">
|
||||
<span aria-hidden
|
||||
class="absolute inset-0 bg-green-200 opacity-50 rounded-full"></span>
|
||||
<span class="relative">Activo</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0 w-10 h-10">
|
||||
<img class="w-full h-full rounded-full"
|
||||
src="https://images.unsplash.com/photo-1500648767791-00dcc994a43e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2.2&w=160&h=160&q=80"
|
||||
alt=""/>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-gray-900 whitespace-no-wrap">
|
||||
Blake Bowman
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
|
||||
<p class="text-gray-900 whitespace-no-wrap">Editor</p>
|
||||
</td>
|
||||
<td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
|
||||
<p class="text-gray-900 whitespace-no-wrap">
|
||||
Jan 01, 2020
|
||||
</p>
|
||||
</td>
|
||||
<td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
|
||||
<span
|
||||
class="relative inline-block px-3 py-1 font-semibold text-green-900 leading-tight">
|
||||
<span aria-hidden
|
||||
class="absolute inset-0 bg-green-200 opacity-50 rounded-full"></span>
|
||||
<span class="relative">Activo</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0 w-10 h-10">
|
||||
<img class="w-full h-full rounded-full"
|
||||
src="https://images.unsplash.com/photo-1540845511934-7721dd7adec3?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2.2&w=160&h=160&q=80"
|
||||
alt=""/>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-gray-900 whitespace-no-wrap">
|
||||
Dana Moore
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
|
||||
<p class="text-gray-900 whitespace-no-wrap">Editor</p>
|
||||
</td>
|
||||
<td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
|
||||
<p class="text-gray-900 whitespace-no-wrap">
|
||||
Jan 10, 2020
|
||||
</p>
|
||||
</td>
|
||||
<td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
|
||||
<span
|
||||
class="relative inline-block px-3 py-1 font-semibold text-orange-900 leading-tight">
|
||||
<span aria-hidden
|
||||
class="absolute inset-0 bg-orange-200 opacity-50 rounded-full"></span>
|
||||
<span class="relative">Suspended</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-5 py-5 bg-white text-sm">
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0 w-10 h-10">
|
||||
<img class="w-full h-full rounded-full"
|
||||
src="https://images.unsplash.com/photo-1522609925277-66fea332c575?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2.2&h=160&w=160&q=80"
|
||||
alt=""/>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-gray-900 whitespace-no-wrap">
|
||||
Alonzo Cox
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-5 py-5 bg-white text-sm">
|
||||
<p class="text-gray-900 whitespace-no-wrap">Admin</p>
|
||||
</td>
|
||||
<td class="px-5 py-5 bg-white text-sm">
|
||||
<p class="text-gray-900 whitespace-no-wrap">Jan 18, 2020</p>
|
||||
</td>
|
||||
<td class="px-5 py-5 bg-white text-sm">
|
||||
<span
|
||||
class="relative inline-block px-3 py-1 font-semibold text-red-900 leading-tight">
|
||||
<span aria-hidden
|
||||
class="absolute inset-0 bg-red-200 opacity-50 rounded-full"></span>
|
||||
<span class="relative">Inactive</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div
|
||||
class="px-5 py-5 bg-white border-t flex flex-col xs:flex-row items-center xs:justify-between ">
|
||||
<span class="text-xs xs:text-sm text-gray-900">
|
||||
Showing 1 to 4 of 50 Entries
|
||||
</span>
|
||||
<div class="inline-flex mt-2 xs:mt-0">
|
||||
<button
|
||||
class="text-sm bg-gray-300 hover:bg-gray-400 text-gray-800 font-semibold py-2 px-4 rounded-l">
|
||||
Prev
|
||||
</button>
|
||||
<button
|
||||
class="text-sm bg-gray-300 hover:bg-gray-400 text-gray-800 font-semibold py-2 px-4 rounded-r">
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{template "partials/file-upload" .}}
|
||||
{{template "partials/footer" .}}
|
||||
@@ -0,0 +1,76 @@
|
||||
<h1>{{.Title}}</h1>
|
||||
{{if .user}}
|
||||
Hello, {{.user.FirstName}} - ID: {{.user.ID}}!
|
||||
{{end}}
|
||||
<div class="bg-white rounded-lg w-1/4 lg:w-1/4 xl:w-1/4 p-4 shadow float-right flex-col">
|
||||
<div>
|
||||
<span class="text-gray-900 relative inline-block date uppercase font-medium tracking-widest">Wednesday 8</span>
|
||||
<div class="flex mb-2">
|
||||
<div class="w-2/12">
|
||||
<span class="text-sm text-gray-600 block">8:00a</span>
|
||||
<span class="text-sm text-gray-600 block">8:15a</span>
|
||||
</div>
|
||||
<div class="w-1/12">
|
||||
<span class="bg-blue-400 h-2 w-2 rounded-full block mt-2"></span>
|
||||
</div>
|
||||
<div class="w-9/12">
|
||||
<span class="text-sm font-semibold block">Morning Standup</span>
|
||||
<span class="text-sm">Zoom ID: 1134 11 1134</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex mb-4">
|
||||
<div class="w-2/12">
|
||||
<span class="text-sm text-gray-600 block">10:00a</span>
|
||||
<span class="text-sm text-gray-600 block">2:00p</span>
|
||||
</div>
|
||||
<div class="w-1/12">
|
||||
<span class="bg-red-400 h-2 w-2 rounded-full block mt-2"></span>
|
||||
</div>
|
||||
<div class="w-9/12">
|
||||
<span class="text-sm font-semibold block">Core Development</span>
|
||||
<span class="text-sm">Joey, Matt, CJ and Vlad</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex mb-4">
|
||||
<div class="w-2/12">
|
||||
<span class="text-sm text-gray-600 block">3:00p</span>
|
||||
<span class="text-sm text-gray-600 block">3:30p</span>
|
||||
</div>
|
||||
<div class="w-1/12">
|
||||
<span class="bg-indigo-600 h-2 w-2 rounded-full block mt-2"></span>
|
||||
</div>
|
||||
<div class="w-9/12">
|
||||
<span class="text-sm font-semibold block">Interview with Ed Harris</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-gray-900 relative inline-block date uppercase font-medium tracking-widest">Thursday 9</span>
|
||||
<div class="flex mb-2">
|
||||
<div class="w-2/12">
|
||||
<span class="text-sm text-gray-600 block">8:00a</span>
|
||||
<span class="text-sm text-gray-600 block">8:15a</span>
|
||||
</div>
|
||||
<div class="w-1/12">
|
||||
<span class="bg-blue-400 h-2 w-2 rounded-full block mt-2"></span>
|
||||
</div>
|
||||
<div class="w-9/12">
|
||||
<span class="text-sm font-semibold block">Morning Standup</span>
|
||||
<span class="text-sm">Zoom ID: 1134 11 1134</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex mb-4">
|
||||
<div class="w-2/12">
|
||||
<span class="text-sm text-gray-600 block">6:00p</span>
|
||||
<span class="text-sm text-gray-600 block">7:30p</span>
|
||||
</div>
|
||||
<div class="w-1/12">
|
||||
<span class="bg-yellow-400 h-2 w-2 rounded-full block mt-2"></span>
|
||||
</div>
|
||||
<div class="w-9/12">
|
||||
<span class="text-sm font-semibold block">Dinner with Mom</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{template "partials/footer" .}}
|
||||
@@ -0,0 +1,10 @@
|
||||
<h1>{{.Title}}</h1>
|
||||
{{if .user}}
|
||||
Hello, {{.user.FirstName}} - ID: {{.user.ID}}!
|
||||
|
||||
|
||||
<script src="/js/payment.js"></script>
|
||||
{{end}}
|
||||
<script src="/js/manifest.js"></script>
|
||||
<script src="/js/vendor.js"></script>
|
||||
{{template "partials/footer" .}}
|
||||
@@ -0,0 +1,401 @@
|
||||
<!-- Container Principal -->
|
||||
<div x-data="modals" @keydown.escape="closeModal" class="bg-white rounded-lg shadow">
|
||||
<div class="container mx-auto p-6 w-full ">
|
||||
<h1 class="text-2xl font-bold mb-4">Lista de inicio </h1>
|
||||
<div class="justify-between w-full md:flex">
|
||||
<p class="mb-4 text-sm">Gestión de inicio.</p>
|
||||
<!-- Campo de Búsqueda -->
|
||||
<div class="mb-4 relative">
|
||||
<input type="text" x-model="searchQuery" placeholder="Buscar..."
|
||||
class="border border-gray-300 rounded w-full md:w-60 p-2 text-sm" @input="loadRegister()">
|
||||
|
||||
<!-- Contenedor para el botón o el ícono de carga -->
|
||||
<div x-show="isLoading" class="absolute right-2 top-2 flex items-center">
|
||||
<!-- SVG de cargando (puedes reemplazarlo con un botón si lo prefieres) -->
|
||||
<svg class="animate-spin h-5 w-5 text-gray-500" xmlns="http://www.w3.org/2000/svg" fill="none"
|
||||
viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4">
|
||||
</circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Botón Nuevo registro -->
|
||||
<div class="flex justify-end mb-4">
|
||||
<button class="bg-[#8eb02f] text-white px-4 py-2 rounded text-sm"
|
||||
x-on:click="addModal=true">Nuevo</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Agregar el GIF de carga -->
|
||||
<div x-show="loading" class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-50 justify-center items-center">
|
||||
<img src="../img/loading.gif" alt="Cargando..." class="w-16 h-16" />
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto max-w-full">
|
||||
<!-- Tabla de Registros -->
|
||||
<table class=" table-auto w-full">
|
||||
<thead class="text-sm text-left py-4 border-b border-gray-300">
|
||||
<tr class="text-left font-semibold border-collapse">
|
||||
<th class="py-2 px-4 border-b">Item</th>
|
||||
<th class="py-2 px-4 border-b">Descripción</th>
|
||||
<th class="py-2 px-4 border-b">Enlace</th>
|
||||
<th class="py-2 px-4 border-b">Imagen</th>
|
||||
<th class="py-2 px-4 border-b w-32"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-gray-500 select-none text-sm ">
|
||||
<!-- Mensaje de Carga Inicial -->
|
||||
<tr class="hover:bg-gray-100" x-show="isLoading">
|
||||
<td colspan="" class="py-2 px-4 border-b text-center w-full">
|
||||
<div class="text-center mx-auto justify-center flex space-x-2">
|
||||
<!-- SVG de cargando (puedes reemplazarlo con un botón si lo prefieres) -->
|
||||
<svg class="animate-spin h-5 w-5 mx-1 text-gray-500" xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor"
|
||||
stroke-width="4">
|
||||
</circle>
|
||||
<path class="opacity-75" fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z">
|
||||
</path>
|
||||
</svg>
|
||||
Cargando registros...
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Itera sobre los roles -->
|
||||
<template x-for="registro in registros" :key="registro.ID">
|
||||
<tr class="hover:bg-gray-100" :data-role-id="registro.ID">
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="registro.ID"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="registro.description"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="registro.enlace"></td>
|
||||
<td class="py-3 text-xs px-4 border-b">
|
||||
<button class="bg-[#8eb02f] text-white px-4 py-2 rounded"
|
||||
x-on:click="window.open(`${window.location.origin}/${registro.ruta}`, '_blank')">
|
||||
Ver imagen
|
||||
</button>
|
||||
</td>
|
||||
<td class="py-3 text-xs px-4 border-b">
|
||||
<div class="flex justify-between gap-2">
|
||||
|
||||
<button
|
||||
@click="viewModal = true; Description = registro.description; Enlace = registro.enlace; Ruta = registro.ruta;"
|
||||
title="Ver">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" class="w-5 text-[#8eb02f]">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
@click="editModal = true; Id = registro.ID; Description = registro.description; Enlace = registro.enlace; Ruta = registro.ruta;"
|
||||
title="Editar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" class="w-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10" />
|
||||
</svg>
|
||||
</button>
|
||||
<button @click="showConfirmModal = true; deleteId = registro.ID;" title="Eliminar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" class="w-5 text-red-500">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<tr x-show="sinregistro">
|
||||
<td colspan="3" class="py-2 px-4 border-b text-center">No hay registros disponibles.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<!-- Los botones de paginación se generarán aquí -->
|
||||
<div id="pagination" class="flex justify-left my-4 text-sm">
|
||||
</div>
|
||||
<!-- Mostrar conteo de registros -->
|
||||
<div id="recordCountDiv" class="text-sm text-gray-700 ml-4">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Ver -->
|
||||
<div x-cloak x-show="viewModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Ver registro</h2>
|
||||
<p class="font-semibold" x-text="Description"></p>
|
||||
<p class="mt-2" x-text="Enlace"></p>
|
||||
<p class="mt-2" x-text="Ruta"></p>
|
||||
<button class="mt-4 bg-[#8eb02f] text-white px-4 py-2 rounded"
|
||||
x-on:click="viewModal = false">Cerrar</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Editar -->
|
||||
<div x-cloak x-show="editModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Editar registro</h2>
|
||||
<form @submit.prevent="submitEdit">
|
||||
|
||||
<label class="block mt-4 mb-2" for="editDescription">Descripción</label>
|
||||
<textarea id="editDescription" x-model="Description" placeholder="Descripción"
|
||||
class="border border-gray-300 rounded w-full p-2" required></textarea>
|
||||
|
||||
<label class="block mt-4 mb-2" for="editEnlace">Enlace</label>
|
||||
<input id="editEnlace" x-model="Enlace" class="border border-gray-300 rounded w-full p-2">
|
||||
|
||||
<label class="block mb-2" for="editRuta">Imagen</label>
|
||||
<input type="file" id="editFile" @change="handleUpdateFileChange"
|
||||
class="border border-gray-300 rounded w-full p-2" accept="image/*">
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar Cambios</button>
|
||||
<button type="button" class="bg-gray-600 text-white px-4 py-2 rounded"
|
||||
x-on:click="editModal = false">Cancelar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Añadir -->
|
||||
<div x-cloak x-show="addModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Agregar registro</h2>
|
||||
<form @submit.prevent="submitAdd">
|
||||
|
||||
<label class="block mt-4 mb-2" for="description">Descripción</label>
|
||||
<textarea id="description" x-model="newDescription" placeholder="Descripción"
|
||||
class="border border-gray-300 rounded w-full p-2" required></textarea>
|
||||
|
||||
<label class="block mt-4 mb-2" for="newEnlace">Enlace</label>
|
||||
<input id="enlace" x-model="newEnlace" class="border border-gray-300 rounded w-full p-2">
|
||||
|
||||
<label class="block mb-2" for="file">Imagen</label>
|
||||
<input type="file" id="file" @change="handleFileChange"
|
||||
class="border border-gray-300 rounded w-full p-2" accept="image/*" required>
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar registro</button>
|
||||
<button type="button" class="bg-gray-600 text-white px-4 py-2 rounded"
|
||||
x-on:click="closeModal">Cancelar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Confirmar Eliminación -->
|
||||
<div x-cloak x-show="showConfirmModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-4">Confirmar Eliminación</h2>
|
||||
<p>¿Estás seguro de que deseas eliminar este registro?</p>
|
||||
<div class="mt-4 flex justify-end">
|
||||
<button class="bg-red-500 text-white px-4 py-2 rounded mr-2" @click="deleteItem()">Eliminar</button>
|
||||
<button @click="closeModal" class="bg-gray-600 text-white px-4 py-2 rounded">Cancelar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alpine.js Script -->
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('modals', () => ({
|
||||
addModal: false,
|
||||
editModal: false,
|
||||
viewModal: false,
|
||||
showConfirmModal: false,
|
||||
|
||||
newDescription: '',
|
||||
newEnlace: '',
|
||||
newRuta: '',
|
||||
newFile: null, // Archivo para la carga
|
||||
|
||||
Description: '',
|
||||
Enlace: '',
|
||||
Ruta: '',
|
||||
updateFile: null, // Archivo para la actualización
|
||||
|
||||
sinregistro: '',
|
||||
Id: null,
|
||||
deleteId: null,
|
||||
loading: false,
|
||||
totalRecords: 0,
|
||||
isLoading: false,
|
||||
registros: '',
|
||||
|
||||
init() {
|
||||
this.loadRegister();
|
||||
},
|
||||
|
||||
searchQuery: '',
|
||||
|
||||
loadRegister(page = 1) {
|
||||
this.isLoading = true;
|
||||
const search = this.searchQuery ? `&search=${this.searchQuery}` : '';
|
||||
fetch(`/loadinicio?page=${page}${search}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
this.totalRecords = data.total;
|
||||
this.registros = data.records;
|
||||
this.totalPages = data.totalPages;
|
||||
this.createPagination(this.totalPages, page);
|
||||
this.sinregistro = data.records.length === 0;
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.isLoading = false;
|
||||
});
|
||||
},
|
||||
|
||||
createPagination(totalPages, currentPage) {
|
||||
const paginationContainer = document.getElementById('pagination');
|
||||
paginationContainer.innerHTML = '';
|
||||
|
||||
const paginationButtonsContainer = document.createElement('div');
|
||||
paginationButtonsContainer.className = "md:flex mx-auto mb-2 md:justify-between items-center w-full";
|
||||
|
||||
const createButton = (text, isDisabled, onClick, additionalClasses = '') => {
|
||||
const button = document.createElement('button');
|
||||
button.textContent = text;
|
||||
button.disabled = isDisabled;
|
||||
button.className = `px-4 py-2 text-black bg-gray-200 ${additionalClasses} ${isDisabled ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-300'}`;
|
||||
if (!isDisabled) {
|
||||
button.onclick = onClick;
|
||||
}
|
||||
return button;
|
||||
};
|
||||
|
||||
const leftContainer = document.createElement('div');
|
||||
leftContainer.className = "md:flex text-center mb-2";
|
||||
leftContainer.appendChild(createButton('Anterior', currentPage === 1, () => this.loadRegister(currentPage - 1), 'rounded-l-md'));
|
||||
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
const pageButton = createButton(i, false, () => this.loadRegister(i), `mx-1 ${i === currentPage ? 'bg-black text-gray-50' : 'bg-white text-black'} rounded-md`);
|
||||
leftContainer.appendChild(pageButton);
|
||||
}
|
||||
|
||||
leftContainer.appendChild(createButton('Siguiente', currentPage === totalPages, () => this.loadRegister(currentPage + 1), 'rounded-r-md'));
|
||||
paginationButtonsContainer.appendChild(leftContainer);
|
||||
|
||||
const recordCountDiv = document.createElement('div');
|
||||
const startRecord = (currentPage - 1) * 10 + 1;
|
||||
const endRecord = Math.min(currentPage * 10, this.totalRecords);
|
||||
recordCountDiv.className = "text-sm text-gray-700 text-center md:ml-auto";
|
||||
recordCountDiv.innerHTML = `Mostrando ${startRecord} a ${endRecord} de ${this.totalRecords} registros`;
|
||||
|
||||
paginationButtonsContainer.appendChild(recordCountDiv);
|
||||
paginationContainer.appendChild(paginationButtonsContainer);
|
||||
},
|
||||
|
||||
closeModal() {
|
||||
this.addModal = false;
|
||||
this.editModal = false;
|
||||
this.viewModal = false;
|
||||
this.showConfirmModal = false;
|
||||
this.newFile = null; // Reiniciar archivo
|
||||
this.updateFile = null; // Reiniciar archivo
|
||||
},
|
||||
|
||||
handleFileChange(event) {
|
||||
this.newFile = event.target.files[0]; // Manejar el archivo seleccionado
|
||||
},
|
||||
|
||||
handleUpdateFileChange(event) {
|
||||
this.updateFile = event.target.files[0]; // Manejar el archivo seleccionado para la actualización
|
||||
},
|
||||
|
||||
submitAdd() {
|
||||
this.loading = true;
|
||||
const formData = new FormData();
|
||||
formData.append('description', this.newDescription);
|
||||
formData.append('enlace', this.newEnlace);
|
||||
if (this.newFile) formData.append('file', this.newFile); // Adjuntar el archivo si existe
|
||||
|
||||
fetch('/app/inicio', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
this.newDescription = '';
|
||||
this.newEnlace = '';
|
||||
this.newRuta = data.ruta; // Guardar la ruta del archivo en la respuesta
|
||||
this.newFile = null; // Reinicia la variable de archivo
|
||||
// Limpia manualmente el input de archivo en el DOM
|
||||
document.getElementById('file').value = '';
|
||||
this.closeModal();
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
submitEdit() {
|
||||
this.loading = true;
|
||||
const formData = new FormData();
|
||||
formData.append('description', this.Description);
|
||||
formData.append('enlace', this.Enlace);
|
||||
|
||||
if (this.updateFile) {
|
||||
// Adjuntar el archivo si existe
|
||||
formData.append('file', this.updateFile);
|
||||
} else if (this.Ruta) {
|
||||
// Adjuntar el string 'Ruta' si no existe el archivo
|
||||
formData.append('file', this.Ruta);
|
||||
}
|
||||
|
||||
|
||||
fetch(`/app/inicio/${this.Id}`, {
|
||||
method: 'PUT',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
this.Description = '';
|
||||
this.Enlace = '';
|
||||
this.Ruta = data.ruta; // Actualizar la ruta del archivo en la respuesta
|
||||
this.updateFile = null; // Reinicia la variable de archivo
|
||||
// Limpia manualmente el input de archivo en el DOM
|
||||
document.getElementById('editFile').value = '';
|
||||
this.closeModal();
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
deleteItem() {
|
||||
this.loading = true;
|
||||
fetch(`/app/inicio/${this.deleteId}`, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
})
|
||||
.then(() => {
|
||||
this.closeModal();
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
@@ -0,0 +1,57 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Main</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||
<style>
|
||||
.profile-action:hover .profile-action-dropdown {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
aside ul li:hover .menu-item-text {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
margin-left: 7rem;
|
||||
width: 10rem;
|
||||
padding: 22px;
|
||||
background-color: rgba(247, 250, 252, var(--bg-opacity));
|
||||
}
|
||||
|
||||
aside .logout:hover .menu-item-text {
|
||||
display: inline-block;
|
||||
padding: 22px;
|
||||
position: absolute;
|
||||
margin-left: 7rem;
|
||||
width: 10rem;
|
||||
}
|
||||
|
||||
.date:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
border-top: 1px solid #e2e8f0;
|
||||
top: 12px;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.date:after {
|
||||
margin-left: 15px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
|
||||
<body class="bg-gray-200 h-screen w-screen flex">
|
||||
<div class="flex-1 flex flex-col" x-data="{ open: false }">
|
||||
<button class="bg-blue-500 text-white p-4" @click="open = !open">Toggle Dropdown</button>
|
||||
<div x-show="open" class="mt-2 p-4 bg-white shadow-lg">
|
||||
Dropdown Content
|
||||
</div>
|
||||
|
||||
{{template "partials/landing-header" .}}
|
||||
{{embed}}
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,66 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<link rel="stylesheet" href="/css/vendor.css">
|
||||
<link rel="stylesheet" href="/css/app.css">
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f4f4f4;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
}
|
||||
.email-container {
|
||||
background-color: #ffffff;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
text-align: center;
|
||||
max-width: 600px;
|
||||
margin: auto;
|
||||
}
|
||||
.email-header {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.email-content {
|
||||
font-size: 16px;
|
||||
color: #555555;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.email-button {
|
||||
display: inline-block;
|
||||
margin-top: 20px;
|
||||
padding: 10px 20px;
|
||||
font-size: 16px;
|
||||
color: #ffffff;
|
||||
background-color: #007bff;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
.email-button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
.footer-note {
|
||||
margin-top: 20px;
|
||||
font-size: 14px;
|
||||
color: #999999;
|
||||
}
|
||||
</style>
|
||||
<head>
|
||||
<title>Main</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{{embed}}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,66 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>FACTURA</title>
|
||||
<!-- Tailwind CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
<!-- PDF.js -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/qrcode/build/qrcode.min.js"></script>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.10.377/pdf.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/jsbarcode@3.11.0/dist/JsBarcode.all.min.js"></script>
|
||||
|
||||
<style>
|
||||
#pdf-container {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
canvas {
|
||||
width: 100% !important;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
#Modalexto {
|
||||
position: absolute;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.notification-hidden {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: opacity 0.5s, visibility 0.5s;
|
||||
}
|
||||
|
||||
.notification-visible {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition: opacity 0.5s, visibility 0.5s;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<style>
|
||||
[x-cloak] {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="bg-gray-100 justify-center items-center min-h-screen">
|
||||
<main class="flex justify-between w-full">
|
||||
|
||||
<div class="w-full">
|
||||
{{embed}}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Gases del Oriente</title>
|
||||
<!-- Alpine.js -->
|
||||
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||
<!-- TailwindCSS -->
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<!-- Select2 CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
|
||||
<!-- Select2 JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
||||
<style>
|
||||
[x-cloak] {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<main class="flex space-x-1 justify-between">
|
||||
<div class="w-full">
|
||||
{{embed}}
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,137 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Gases del Oriente</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<!-- Cargar jQuery primero -->
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<!-- Luego cargar Select2 -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
||||
<style>
|
||||
[x-cloak] {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="bg-gray-200 w-full">
|
||||
<main class="flex justify-between w-full">
|
||||
<!-- Componente Lateral (Barra Lateral) -->
|
||||
{{template "partials/lateral" .}}
|
||||
<div class="w-full">
|
||||
{{template "partials/header" .}}
|
||||
<div class="w-full px-3 py-3 h-[calc(100vh-64px)] overflow-auto">
|
||||
{{embed}}
|
||||
</div>
|
||||
{{template "partials/footer" .}}
|
||||
</div>
|
||||
</main>
|
||||
<div x-data="sessionTimeout" x-init="init()" x-cloak class="hidden sm:block">
|
||||
<!-- Contador General de Inactividad -->
|
||||
<div x-show="!showModal" class="fixed top-2 right-20 border text rounded-lg p-2 bg-gray-100 text-sm">
|
||||
<p>Tiempo restante: <span x-text="formatTime(inactivityCountdown)"></span></p>
|
||||
</div>
|
||||
<!-- Modal -->
|
||||
<div x-show="showModal" class="fixed inset-0 flex items-center justify-center bg-gray-800 bg-opacity-75">
|
||||
<div class="bg-white rounded-lg shadow-md p-8 w-[600px] relative">
|
||||
<h2 class="text-xl font-bold mb-6 text-center">¿Deseas continuar?</h2>
|
||||
<p class="text-gray-600 mb-6 text-center text-base">
|
||||
Has estado inactivo. Elige "Continuar" para seguir con tu sesión o "Cerrar sesión" para salir.
|
||||
</p>
|
||||
<!-- Contador del tiempo para responder -->
|
||||
<p class="text-center text-red-500 font-semibold mb-4">
|
||||
Tiempo para responder: <span x-text="countdown"></span> seg
|
||||
</p>
|
||||
<div class="flex justify-around">
|
||||
<button @click="continueSession"
|
||||
class="px-6 py-3 bg-[#8eb02f] text-white text-base rounded-lg hover:bg-[#698126]">
|
||||
Continuar
|
||||
</button>
|
||||
<form action="/do/logout" method="POST" class="inline-block">
|
||||
<button type="submit"
|
||||
class="px-6 py-3 bg-gray-500 text-white text-base rounded-lg hover:bg-gray-600">
|
||||
Cerrar sesión
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener("alpine:init", () => {
|
||||
Alpine.data("sessionTimeout", () => ({
|
||||
showModal: false,
|
||||
countdown: 60, // 10 segundos para responder
|
||||
inactivityCountdown: 300, // 5 minutos
|
||||
inactivityTimer: null,
|
||||
timer: null,
|
||||
|
||||
init() {
|
||||
this.resetInactivityTimer();
|
||||
|
||||
// Detectar actividad
|
||||
window.addEventListener("mousemove", () => this.resetInactivityTimer());
|
||||
window.addEventListener("keydown", () => this.resetInactivityTimer());
|
||||
},
|
||||
|
||||
resetInactivityTimer() {
|
||||
clearTimeout(this.inactivityTimer);
|
||||
this.inactivityCountdown = 300; // Reiniciar contador a 5 minutos
|
||||
this.startInactivityTimer();
|
||||
},
|
||||
|
||||
startInactivityTimer() {
|
||||
this.inactivityTimer = setInterval(() => {
|
||||
this.inactivityCountdown--;
|
||||
if (this.inactivityCountdown <= 0) {
|
||||
clearInterval(this.inactivityTimer);
|
||||
this.promptLogout();
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
|
||||
promptLogout() {
|
||||
this.showModal = true;
|
||||
this.startCountdown();
|
||||
},
|
||||
|
||||
startCountdown() {
|
||||
this.countdown = 60; // Reiniciar contador del modal
|
||||
clearInterval(this.timer);
|
||||
this.timer = setInterval(() => {
|
||||
this.countdown--;
|
||||
if (this.countdown <= 0) {
|
||||
this.logout();
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
|
||||
continueSession() {
|
||||
clearInterval(this.timer);
|
||||
this.showModal = false;
|
||||
this.resetInactivityTimer();
|
||||
},
|
||||
|
||||
logout() {
|
||||
clearInterval(this.timer);
|
||||
document.querySelector('form[action="/do/logout"]').submit();
|
||||
},
|
||||
|
||||
formatTime(seconds) {
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const remainingSeconds = seconds % 60;
|
||||
return `${minutes}:${remainingSeconds.toString().padStart(2, "0")}`;
|
||||
},
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,151 @@
|
||||
<div x-data="modals" @keydown.escape="closeModal" class="bg-white rounded-lg shadow">
|
||||
|
||||
<div class="container mx-auto p-6 w-full">
|
||||
<h1 class="text-2xl font-bold mb-4">PQRs</h1>
|
||||
<div class="justify-between w-full md:flex">
|
||||
<p class="mb-4 text-sm">Relación de PQRs.</p>
|
||||
</div>
|
||||
|
||||
<!-- GIF de carga -->
|
||||
<div x-show="loading" class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-50 justify-center items-center">
|
||||
<img src="../img/loading.gif" alt="Cargando..." class="w-16 h-16" />
|
||||
</div>
|
||||
|
||||
<!-- Mostrar registros obtenidos -->
|
||||
<div x-show="!loading && records.length > 0" class="overflow-x-auto mt-4">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<template x-for="(record, index) in records" :key="index">
|
||||
<table class="min-w-full border-collapse border border-gray-200 rounded-lg overflow-hidden shadow-sm bg-gray-100 text-sm">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">No. Solicitud</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.No_Solicitud"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Fecha</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="formatDate(record.Fecha)"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Hora</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="formatTime(record.Hora)"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Clase</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.Clase.trim() || '-'"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Causal</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.Causal.trim() || '-'"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Detalle</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.Detalle.trim() || '-'"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Factura</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.Factura.trim() || '-'"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Estado</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.Estado.trim() || '-'"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Observación</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.Observacion.trim() || '-'"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Fecha Solución</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="formatDate(record.Fecha_Sol)"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Hora Solución</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="formatTime(record.Hora_Sol)"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Solución</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.Solucion.trim() || '-'"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Detalle Solución</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.DetalleSol.trim() || '-'"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Lectura</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.Lectura.trim() || '-'"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Observaciones Sol</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.Observaciones_Sol.trim() || '-'"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Mensaje si no hay registros -->
|
||||
<div x-show="!loading && records.length === 0" class="text-center mt-4 text-gray-500">
|
||||
No se encontraron registros.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alpine.js Script -->
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('modals', () => ({
|
||||
usuario: '{{ .user.NombreUsuario }}',
|
||||
records: [],
|
||||
loading: false,
|
||||
|
||||
init() {
|
||||
console.log('init llamado');
|
||||
this.loadRegister();
|
||||
},
|
||||
|
||||
async loadRegister() {
|
||||
try {
|
||||
console.log('loadRegister llamado');
|
||||
this.loading = true;
|
||||
const response = await fetch(`/app/loadpqrsicom/${this.usuario}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Error al cargar registros: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log('Registros obtenidos:', data);
|
||||
this.records = data?.data || [];
|
||||
} catch (error) {
|
||||
console.error('Error al cargar los registros:', error);
|
||||
this.records = [];
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
formatDate(date) {
|
||||
return new Date(date).toLocaleDateString('es-CO', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit'
|
||||
});
|
||||
},
|
||||
|
||||
formatTime(time) {
|
||||
const [hour, minute] = time.slice(11, 16).split(':');
|
||||
return `${hour}:${minute}`;
|
||||
},
|
||||
|
||||
closeModal() {
|
||||
this.loading = false;
|
||||
},
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>{{.title}} Verify.Rest | Validate, Clean and Analyze </title>
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/img/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/img/favicon-32x32.png">
|
||||
<link rel="short icon" type="image/png" sizes="32x32" href="/img/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/img/favicon-16x16.png">
|
||||
</head>
|
||||
<body class="flex flex-col min-h-screen ">
|
||||
{{template "partials/landing/header" .}}
|
||||
<div id="body-wrapper" class="flex-grow min-h-screen mt-32">
|
||||
{{embed}}
|
||||
</div>
|
||||
|
||||
{{template "partials/landing/footer" .}}
|
||||
<link rel="stylesheet" href="/css/vendor.css">
|
||||
<link rel="stylesheet" href="/css/landing.css">
|
||||
<script defer id="slcLiveChat" src="https://widget.sonetel.com/SonetelWidget.min.js" data-account-id="207431552"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,348 @@
|
||||
<!-- Container Principal -->
|
||||
<div x-data="modals" @keydown.escape="closeModal" class="bg-white rounded-lg shadow">
|
||||
<div class="container mx-auto p-6 w-full ">
|
||||
<h1 class="text-2xl font-bold mb-4">Lista de Módulos</h1>
|
||||
<div class="justify-between w-full md:flex">
|
||||
<p class="mb-4 text-sm">Gestión de modulos.</p>
|
||||
<!-- Campo de Búsqueda -->
|
||||
<div class="mb-4 relative">
|
||||
<input type="text" x-model="searchQuery" placeholder="Buscar..."
|
||||
class="border border-gray-300 rounded w-full md:w-60 p-2 text-sm" @input="loadModules()">
|
||||
|
||||
<!-- Contenedor para el botón o el ícono de carga -->
|
||||
<div x-show="isLoading" class="absolute right-2 top-2 flex items-center">
|
||||
<!-- SVG de cargando (puedes reemplazarlo con un botón si lo prefieres) -->
|
||||
<svg class="animate-spin h-5 w-5 text-gray-500" xmlns="http://www.w3.org/2000/svg" fill="none"
|
||||
viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4">
|
||||
</circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Botón Nuevo Módulo -->
|
||||
<div class="flex justify-end mb-4">
|
||||
<button class="bg-[#8eb02f] text-white px-4 py-2 rounded text-sm"
|
||||
x-on:click="addModal=true">Nuevo</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Agregar el GIF de carga -->
|
||||
<div x-show="loading" class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-50 justify-center items-center">
|
||||
<img src="../img/loading.gif" alt="Cargando..." class="w-16 h-16" />
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto max-w-full">
|
||||
<!-- Tabla de Módulos -->
|
||||
<table class=" table-auto w-full">
|
||||
<thead class="text-sm text-left py-4 border-b border-gray-300">
|
||||
<tr class="text-left font-semibold border-collapse">
|
||||
<th class="py-2 px-4 border-b w-52 ">Título</th>
|
||||
<th class="py-2 px-4 border-b">Descripción</th>
|
||||
<th class="py-2 px-4 border-b w-32"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="modulesList" class="text-gray-500 select-none text-sm ">
|
||||
<!-- Mensaje de Carga Inicial -->
|
||||
<tr class="hover:bg-gray-100">
|
||||
<td colspan="" class="py-2 px-4 border-b text-center w-full">
|
||||
<div class="text-center mx-auto justify-center flex space-x-2">
|
||||
<!-- SVG de cargando (puedes reemplazarlo con un botón si lo prefieres) -->
|
||||
<svg class="animate-spin h-5 w-5 mx-1 text-gray-500" xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor"
|
||||
stroke-width="4">
|
||||
</circle>
|
||||
<path class="opacity-75" fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z">
|
||||
</path>
|
||||
</svg>
|
||||
Cargando registros...
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<!-- Los botones de paginación se generarán aquí -->
|
||||
<div id="pagination" class="flex justify-left my-4 text-sm">
|
||||
</div>
|
||||
<!-- Mostrar conteo de registros -->
|
||||
<div id="recordCountDiv" class="text-sm text-gray-700 ml-4">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Ver -->
|
||||
<div x-cloak x-show="viewModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Ver registro</h2>
|
||||
<p class="font-semibold" x-text="Title"></p>
|
||||
<p class="mt-2" x-text="Description"></p>
|
||||
<button class="mt-4 bg-[#8eb02f] text-white px-4 py-2 rounded"
|
||||
x-on:click="viewModal = false">Cerrar</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Editar -->
|
||||
<div x-cloak x-show="editModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Editar registro</h2>
|
||||
<form @submit.prevent="submitEditModule">
|
||||
<label class="block mb-2" for="editTitle">Título</label>
|
||||
<input type="text" id="editTitle" x-model="Title" placeholder="Título"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
<label class="block mt-4 mb-2" for="editDescription">Descripción</label>
|
||||
<textarea id="editDescription" x-model="Description" placeholder="Descripción"
|
||||
class="border border-gray-300 rounded w-full p-2" required></textarea>
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar Cambios</button>
|
||||
<button type="button" class="bg-gray-600 text-white px-4 py-2 rounded"
|
||||
x-on:click="closeModal">Cancelar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Añadir -->
|
||||
<div x-cloak x-show="addModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Agregar registro</h2>
|
||||
<form @submit.prevent="submitAddModule">
|
||||
<label class="block mb-2" for="title">Título</label>
|
||||
<input type="text" id="title" x-model="newTitle" placeholder="Título"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
<label class="block mt-4 mb-2" for="description">Descripción</label>
|
||||
<textarea id="description" x-model="newDescription" placeholder="Descripción"
|
||||
class="border border-gray-300 rounded w-full p-2" required></textarea>
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar registro</button>
|
||||
<button type="button" class="bg-gray-600 text-white px-4 py-2 rounded"
|
||||
x-on:click="closeModal">Cancelar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Confirmar Eliminación -->
|
||||
<div x-cloak x-show="showConfirmModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-4">Confirmar Eliminación</h2>
|
||||
<p>¿Estás seguro de que deseas eliminar este registro?</p>
|
||||
<div class="mt-4 flex justify-end">
|
||||
<button @click="deleteModule()" class="bg-red-500 text-white px-4 py-2 rounded mr-2">Eliminar</button>
|
||||
<button @click="closeModal" class="bg-gray-600 text-white px-4 py-2 rounded">Cancelar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alpine.js Script -->
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('modals', () => ({
|
||||
addModal: false,
|
||||
editModal: false,
|
||||
viewModal: false,
|
||||
showConfirmModal: false,
|
||||
newTitle: '',
|
||||
newDescription: '',
|
||||
Title: '',
|
||||
Description: '',
|
||||
Id: null,
|
||||
deleteId: null,
|
||||
loading: false,
|
||||
totalRecords: 0, // Agregar esta línea
|
||||
isLoading: false,
|
||||
|
||||
|
||||
init() {
|
||||
this.loadModules();
|
||||
},
|
||||
//CARGAR MODULOS
|
||||
searchQuery: '', // Agrega esta línea dentro del objeto Alpine
|
||||
|
||||
// Modifica la función loadModules para incluir la búsqueda
|
||||
loadModules(page = 1) {
|
||||
this.isLoading = true;
|
||||
//this.loading = true;
|
||||
const search = this.searchQuery ? `&search=${this.searchQuery}` : '';
|
||||
fetch(`/app/loadmodules?page=${page}${search}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
this.totalRecords = data.total; // Establece el total de registros aquí
|
||||
this.modules = data.modules; // Asignar módulos
|
||||
this.totalPages = data.totalPages; // Asignar total de páginas
|
||||
this.createPagination(this.totalPages, page);
|
||||
const modulesList = document.getElementById('modulesList');
|
||||
modulesList.innerHTML = ''; // Limpiar la lista actual
|
||||
if (data.modules.length === 0) {
|
||||
modulesList.innerHTML = `<tr><td colspan="3" class="py-2 px-4 border-b text-center">No hay módulos disponibles.</td></tr>`;
|
||||
} else {
|
||||
data.modules.forEach(module => {
|
||||
const row = document.createElement('tr');
|
||||
row.setAttribute('data-module-id', module.ID);
|
||||
row.classList.add('hover:bg-gray-100')
|
||||
row.innerHTML = `
|
||||
<td class="py-3 text-xs px-4 border-b ">${module.title}</td>
|
||||
<td class="py-3 text-xs px-4 border-b ">${module.description}</td>
|
||||
<td class="py-3 text-xs px-4 border-b flex justify-between space-x-1">
|
||||
<button x-on:click="viewModal = true; Title = '${module.title}'; Description = '${module.description}'; " title="Ver">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
||||
stroke="currentColor" class="w-5 text-[#8eb02f]">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
</svg>
|
||||
</button>
|
||||
<button x-on:click="editModal = true; Id = '${module.ID}'; Title = '${module.title}'; Description = '${module.description}';" title="Editar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
||||
stroke="currentColor" class="w-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10" />
|
||||
</svg>
|
||||
</button>
|
||||
<button x-on:click="showConfirmModal = true; deleteId = '${module.ID}';" title="Eliminar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
||||
stroke="currentColor" class="w-5 text-red-500">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
|
||||
</svg>
|
||||
</button>
|
||||
</td>
|
||||
`;
|
||||
modulesList.appendChild(row);
|
||||
});
|
||||
|
||||
// Lógica de paginación
|
||||
const totalPages = Math.ceil(this.totalRecords / data.limit);
|
||||
this.createPagination(totalPages, page)
|
||||
}
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.isLoading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
},
|
||||
createPagination(totalPages, currentPage) {
|
||||
const paginationContainer = document.getElementById('pagination');
|
||||
paginationContainer.innerHTML = ''; // Limpiar la paginación actual
|
||||
|
||||
// Crear un contenedor para los botones de paginación
|
||||
const paginationButtonsContainer = document.createElement('div');
|
||||
paginationButtonsContainer.className = "md:flex mx-auto mb-2 md:justify-between items-center w-full"; // Alinear los botones
|
||||
|
||||
// Función para crear un botón
|
||||
const createButton = (text, isDisabled, onClick, additionalClasses = '') => {
|
||||
const button = document.createElement('button');
|
||||
button.textContent = text;
|
||||
button.disabled = isDisabled;
|
||||
button.className = `px-4 py-2 text-black bg-gray-200 ${additionalClasses} ${isDisabled ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-300'}`;
|
||||
if (!isDisabled) {
|
||||
button.onclick = onClick;
|
||||
}
|
||||
return button;
|
||||
};
|
||||
|
||||
// Botones de paginación
|
||||
const leftContainer = document.createElement('div');
|
||||
leftContainer.className = "md:flex text-center mb-2"; // Contenedor para los botones de paginación a la izquierda
|
||||
leftContainer.appendChild(createButton('Anterior', currentPage === 1, () => this.loadModules(currentPage - 1), 'rounded-l-md'));
|
||||
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
const pageButton = createButton(i, false, () => this.loadModules(i), `mx-1 ${i === currentPage ? 'bg-black text-gray-50' : 'bg-white text-black'} rounded-md`);
|
||||
leftContainer.appendChild(pageButton);
|
||||
}
|
||||
|
||||
leftContainer.appendChild(createButton('Siguiente', currentPage === totalPages, () => this.loadModules(currentPage + 1), 'rounded-r-md'));
|
||||
|
||||
paginationButtonsContainer.appendChild(leftContainer);
|
||||
|
||||
// Agregar el conteo de registros a la derecha
|
||||
const recordCountDiv = document.createElement('div');
|
||||
const startRecord = (currentPage - 1) * 10 + 1; // Primer registro de la página actual
|
||||
const endRecord = Math.min(currentPage * 10, this.totalRecords); // Último registro mostrado
|
||||
recordCountDiv.className = "text-sm text-gray-700 text-center md:ml-auto"; // Sin margen para alineación a la izquierda
|
||||
recordCountDiv.innerHTML = `Mostrando ${startRecord} a ${endRecord} de ${this.totalRecords} registros`;
|
||||
|
||||
paginationButtonsContainer.appendChild(recordCountDiv);
|
||||
|
||||
// Agregar los botones de paginación al contenedor principal
|
||||
paginationContainer.appendChild(paginationButtonsContainer);
|
||||
},
|
||||
|
||||
//CERRAR MODALES
|
||||
closeModal() {
|
||||
this.addModal = false;
|
||||
this.editModal = false;
|
||||
this.viewModal = false;
|
||||
this.showConfirmModal = false;
|
||||
},
|
||||
//CREAR
|
||||
submitAddModule() {
|
||||
this.loading = true;
|
||||
fetch('/app/modules', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ title: this.newTitle, description: this.newDescription })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.newTitle = '';
|
||||
this.newDescription = '';
|
||||
this.closeModal();
|
||||
this.loadModules();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
},
|
||||
//ACTUALIZAR
|
||||
submitEditModule() {
|
||||
this.loading = true;
|
||||
fetch(`/app/modules/${this.Id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ title: this.Title, description: this.Description })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.newTitle = '';
|
||||
this.newDescription = '';
|
||||
this.closeModal();
|
||||
this.loadModules();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
},
|
||||
//ELIMINAR
|
||||
deleteModule() {
|
||||
this.loading = true;
|
||||
fetch(`/app/modules/${this.deleteId}`, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
})
|
||||
.then(() => {
|
||||
this.closeModal();
|
||||
this.loadModules();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
}
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
@@ -0,0 +1,375 @@
|
||||
<!-- Container Principal -->
|
||||
<div x-data="parametrizacionForm" class="bg-white rounded-lg shadow">
|
||||
<div class="container mx-auto p-6 w-full">
|
||||
<h1 class="text-2xl font-bold mb-4">Parametrización del sitio web</h1>
|
||||
<p class="mb-4 text-sm">Gestión de parametrización del sitio web</p>
|
||||
|
||||
<div x-show="loading" class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-50 justify-center items-center">
|
||||
<img src="../img/loading.gif" alt="Cargando..." class="w-16 h-16" />
|
||||
</div>
|
||||
|
||||
<!-- Inicio del contenedor de grid -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<!-- Sección General -->
|
||||
<div class="p-6 rounded-lg border w-full shadow">
|
||||
<h2 class="text-xl font-bold mb-2">General</h2>
|
||||
<!-- Contenido de la sección General -->
|
||||
<label class="block mb-2" for="logo">Logo</label>
|
||||
<input type="file" id="logo" @change="handleFileChange($event, 'logo')"
|
||||
class="border border-gray-300 rounded w-full p-2 mb-2" accept="image/*">
|
||||
<p x-show="logo_path" class="mb-2 text-sm text-gray-600">
|
||||
Logo actual: <a :href="`/${logo_path}`" target="_blank" class="text-blue-500 underline"
|
||||
x-text="logo_path.split('/').pop()"></a>
|
||||
</p>
|
||||
|
||||
<!--<label class="block mb-2" for="video_institucional">Video institucional</label>
|
||||
<input type="file" id="video_institucional" @change="handleFileChange($event, 'video_institucional')" class="border border-gray-300 rounded w-full p-2 mb-2" accept="video/*">
|
||||
<p x-show="video_institucional_path" class="mb-2 text-sm text-gray-600">
|
||||
Logo actual: <a :href="`/${video_institucional_path}`" target="_blank" class="text-blue-500 underline" x-text="video_institucional_path.split('/').pop()"></a>
|
||||
</p>-->
|
||||
|
||||
<label class="block mb-2" for="descripcion_seo">Descripción SEO</label>
|
||||
<textarea type="text" id="descripcion_seo" x-model="descripcion_seo"
|
||||
placeholder="Ingrese la descripción SEO"
|
||||
class="border border-gray-300 rounded w-full p-2 mb-4"></textarea>
|
||||
|
||||
<label class="block mb-2" for="email">Correo electrónico</label>
|
||||
<input type="email" id="email" x-model="email" placeholder="Ingrese el correo electrónico"
|
||||
class="border border-gray-300 rounded w-full p-2 mb-4">
|
||||
|
||||
<label class="block mb-2" for="enlace_pagar_ahora">Enlace de Pagar Ahora</label>
|
||||
<input type="url" id="enlace_pagar_ahora" x-model="enlace_pagar_ahora"
|
||||
placeholder="Ingrese el enlace de pago" class="border border-gray-300 rounded w-full p-2 mb-4">
|
||||
|
||||
<label class="block mb-2" for="imagen_resena">Imagen de la Reseña</label>
|
||||
<input type="file" id="imagen_resena" @change="handleFileChange($event, 'imagen_resena')"
|
||||
class="border border-gray-300 rounded w-full p-2 mb-4" accept="image/*">
|
||||
<!-- Mostrar imagen actual de la reseña -->
|
||||
<p x-show="imagen_resena_path" class="mb-2 text-sm text-gray-600">
|
||||
Imagen actual: <a :href="`/${imagen_resena_path}`" target="_blank" class="text-blue-500 underline"
|
||||
x-text="imagen_resena_path.split('/').pop()"></a>
|
||||
</p>
|
||||
|
||||
<!-- Botón de Guardar para esta sección -->
|
||||
<div class="mt-4 text-right">
|
||||
<button @click.prevent="submitUpdateGeneral"
|
||||
class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar General</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sección Documentos -->
|
||||
<div class="p-6 rounded-lg border w-full shadow">
|
||||
<h2 class="text-xl font-bold mb-2">Documentos</h2>
|
||||
<!-- Contenido de la sección Documentos -->
|
||||
<label class="block mb-2" for="contrato_condiciones">Contrato Condiciones</label>
|
||||
<input type="file" id="contrato_condiciones" @change="handleFileChange($event, 'contrato_condiciones')"
|
||||
class="border border-gray-300 rounded w-full p-2 mb-2" accept=".pdf">
|
||||
<!-- Mostrar contrato de condiciones actual -->
|
||||
<p x-show="contrato_condiciones_path" class="mb-2 text-sm text-gray-600">
|
||||
Archivo actual: <a :href="`/${contrato_condiciones_path}`" target="_blank"
|
||||
class="text-blue-500 underline" x-text="contrato_condiciones_path.split('/').pop()"></a>
|
||||
</p>
|
||||
|
||||
<label class="block mb-2" for="proteccion_datos">Protección de Datos</label>
|
||||
<input type="file" id="proteccion_datos" @change="handleFileChange($event, 'proteccion_datos')"
|
||||
class="border border-gray-300 rounded w-full p-2 mb-2" accept=".pdf">
|
||||
<!-- Mostrar protección de datos actual -->
|
||||
<p x-show="proteccion_datos_path" class="mb-2 text-sm text-gray-600">
|
||||
Archivo actual: <a :href="`/${proteccion_datos_path}`" target="_blank"
|
||||
class="text-blue-500 underline" x-text="proteccion_datos_path.split('/').pop()"></a>
|
||||
</p>
|
||||
|
||||
<label class="block mb-2" for="contrato_condiciones_descripcion">Descripción de Condiciones</label>
|
||||
<input type="text" id="contrato_condiciones_descripcion" x-model="contrato_condiciones_descripcion"
|
||||
placeholder="Ingrese la descripción" class="border border-gray-300 rounded w-full p-2 mb-4">
|
||||
|
||||
<label class="block mb-2" for="proteccion_datos_descripcion">Descripción de Protección de Datos</label>
|
||||
<input type="text" id="proteccion_datos_descripcion" x-model="proteccion_datos_descripcion"
|
||||
placeholder="Ingrese la descripción" class="border border-gray-300 rounded w-full p-2 mb-4">
|
||||
|
||||
<!-- Botón de Guardar para esta sección -->
|
||||
<div class="mt-4 text-right">
|
||||
<button @click.prevent="submitUpdateDocumentos"
|
||||
class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar Documentos</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sección Redes Sociales -->
|
||||
<div class="p-6 rounded-lg border w-full shadow">
|
||||
<h2 class="text-xl font-bold mb-2">Redes Sociales</h2>
|
||||
<!-- Contenido de la sección Redes Sociales -->
|
||||
<label class="block mb-2" for="enlace_facebook">Enlace Facebook</label>
|
||||
<input type="url" id="enlace_facebook" x-model="enlace_facebook"
|
||||
placeholder="Ingrese el enlace de Facebook" class="border border-gray-300 rounded w-full p-2 mb-4">
|
||||
|
||||
<label class="block mb-2" for="enlace_instagram">Enlace Instagram</label>
|
||||
<input type="url" id="enlace_instagram" x-model="enlace_instagram"
|
||||
placeholder="Ingrese el enlace de Instagram" class="border border-gray-300 rounded w-full p-2 mb-4">
|
||||
|
||||
<label class="block mb-2" for="enlace_whatsapp">Whatsapp Principal</label>
|
||||
<input type="url" id="enlace_whatsapp" x-model="enlace_whatsapp"
|
||||
placeholder="Ingrese el número de Whatsapp" class="border border-gray-300 rounded w-full p-2 mb-4">
|
||||
|
||||
<!-- Campo Select para Estado -->
|
||||
<label class="block mb-2" for="estado_redes">Estado</label>
|
||||
<select id="estado_redes" x-model="estado_redes" class="border border-gray-300 rounded w-full p-2 mb-4">
|
||||
<option value="true">Activo</option>
|
||||
<option value="false">Inactivo</option>
|
||||
</select>
|
||||
|
||||
<!-- Botón de Guardar para esta sección -->
|
||||
<div class="mt-4 text-right">
|
||||
<button @click.prevent="submitUpdateRedes" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar
|
||||
Redes Sociales</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sección FNB (ocupa el ancho completo)
|
||||
<div class="p-6 rounded-lg border w-full shadow">
|
||||
<h2 class="text-xl font-bold mb-2">FNB</h2>
|
||||
|
||||
<label class="block mb-2" for="email_notificaciones_fnb">Email Notificaciones FNB</label>
|
||||
<input type="email" id="email_notificaciones_fnb" x-model="email_notificaciones_fnb" placeholder="Ingrese el correo" class="border border-gray-300 rounded w-full p-2 mb-2">
|
||||
<label class="block mb-2" for="descripcion_fnb">Descripción</label>
|
||||
<textarea type="text" id="descripcion_fnb" x-model="descripcion_fnb" placeholder="Ingrese la descripción FNB" class="border border-gray-300 rounded w-full p-2 mb-4"></textarea>
|
||||
|
||||
<label class="block mb-2" for="donde_comprar_fnb">Dónde Comprar FNB</label>
|
||||
<input type="file" id="donde_comprar_fnb" @change="handleFileChange($event, 'donde_comprar_fnb')" class="border border-gray-300 rounded w-full p-2 mb-4" accept=".pdf">
|
||||
|
||||
<p x-show="donde_comprar_fnb_path" class="mb-2 text-sm text-gray-600">
|
||||
Archivo actual: <a :href="`/${donde_comprar_fnb_path}`" target="_blank" class="text-blue-500 underline" x-text="donde_comprar_fnb_path.split('/').pop()"></a>
|
||||
</p>
|
||||
|
||||
|
||||
<div class="mt-4 text-right">
|
||||
<button @click.prevent="submitUpdateFNB" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar FNB</button>
|
||||
</div>
|
||||
</div>-->
|
||||
|
||||
<!-- Sección FNB (ocupa el ancho completo) -->
|
||||
<div class="p-6 rounded-lg border w-full shadow">
|
||||
<h2 class="text-xl font-bold mb-2">Importancia del pago</h2>
|
||||
<!-- Contenido de la sección FNB -->
|
||||
<label class="block mb-2" for="descripcion">Descripción</label>
|
||||
<textarea type="text" id="descripcion" x-model="descripcion" placeholder="Ingrese la descripción SEO"
|
||||
class="border border-gray-300 rounded w-full p-2 mb-4"></textarea>
|
||||
|
||||
<label class="block mb-2" for="descripcion_cuadro_azul">Descripción del cuadro azul</label>
|
||||
<textarea type="text" id="descripcion_cuadro_azul" x-model="descripcion_cuadro_azul"
|
||||
placeholder="Ingrese la descripción SEO"
|
||||
class="border border-gray-300 rounded w-full p-2 mb-4"></textarea>
|
||||
|
||||
<!-- Botón de Guardar para esta sección -->
|
||||
<div class="mt-4 text-right">
|
||||
<button @click.prevent="submitUpdateImportancia"
|
||||
class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar importancia del Pago</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- Fin del contenedor de grid -->
|
||||
</div>
|
||||
|
||||
<!-- Alpine.js Script -->
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('parametrizacionForm', () => ({
|
||||
logo: null,
|
||||
descripcion_seo: '',
|
||||
email: '',
|
||||
enlace_pagar_ahora: '',
|
||||
contrato_condiciones: null,
|
||||
proteccion_datos: null,
|
||||
contrato_condiciones_descripcion: '',
|
||||
proteccion_datos_descripcion: '',
|
||||
enlace_facebook: '',
|
||||
enlace_instagram: '',
|
||||
enlace_whatsapp: '',
|
||||
email_notificaciones_fnb: '',
|
||||
donde_comprar_fnb: null,
|
||||
loading: false,
|
||||
logo_path: '',
|
||||
video_institucional: null,
|
||||
video_institucional_path: '',
|
||||
contrato_condiciones_path: '',
|
||||
proteccion_datos_path: '',
|
||||
donde_comprar_fnb_path: '',
|
||||
descripcion: '',
|
||||
descripcion_cuadro_azul: '',
|
||||
descripcion_fnb: '',
|
||||
estado_redes: true,
|
||||
imagen_resena: null,
|
||||
imagen_resena_path: '',
|
||||
id_dato: 0,
|
||||
|
||||
init() {
|
||||
this.loadData();
|
||||
},
|
||||
|
||||
loadData() {
|
||||
this.loading = true;
|
||||
fetch('/loadparametrizacionweb')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data) {
|
||||
this.id_dato = data.ID;
|
||||
this.descripcion_seo = data.descripcion_seo;
|
||||
this.email = data.email;
|
||||
this.enlace_pagar_ahora = data.enlace_pagar_ahora;
|
||||
this.contrato_condiciones_descripcion = data.contrato_condiciones_descripcion;
|
||||
this.proteccion_datos_descripcion = data.proteccion_datos_descripcion;
|
||||
this.enlace_facebook = data.enlace_facebook;
|
||||
this.enlace_instagram = data.enlace_instagram;
|
||||
this.enlace_whatsapp = data.enlace_whatsapp;
|
||||
this.email_notificaciones_fnb = data.email_notificaciones_fnb;
|
||||
this.logo_path = data.logo;
|
||||
this.video_institucional_path = data.video_institucional;
|
||||
this.contrato_condiciones_path = data.contrato_condiciones;
|
||||
this.proteccion_datos_path = data.proteccion_datos;
|
||||
this.donde_comprar_fnb_path = data.donde_comprar_fnb;
|
||||
this.descripcion = data.descripcion;
|
||||
this.descripcion_cuadro_azul = data.descripcion_cuadro_azul;
|
||||
this.descripcion_fnb = data.descripcion_fnb;
|
||||
this.estado_redes = data.estado_redes;
|
||||
this.imagen_resena_path = data.imagen_resena;
|
||||
}
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
handleFileChange(event, field) {
|
||||
if (field === 'imagen_resena') {
|
||||
this.imagen_resena = event.target.files[0];
|
||||
} else if (field === 'logo') {
|
||||
this.logo = event.target.files[0];
|
||||
} else if (field === 'contrato_condiciones') {
|
||||
this.contrato_condiciones = event.target.files[0];
|
||||
} else if (field === 'proteccion_datos') {
|
||||
this.proteccion_datos = event.target.files[0];
|
||||
} else if (field === 'donde_comprar_fnb') {
|
||||
this.donde_comprar_fnb = event.target.files[0];
|
||||
} else if (field === 'video_institucional') {
|
||||
this.video_institucional = event.target.files[0];
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// Funciones de actualización para cada sección
|
||||
submitUpdateGeneral() {
|
||||
this.loading = true;
|
||||
const formData = new FormData();
|
||||
formData.append('descripcion_seo', this.descripcion_seo);
|
||||
formData.append('email', this.email);
|
||||
formData.append('enlace_pagar_ahora', this.enlace_pagar_ahora);
|
||||
if (this.logo) formData.append('logo', this.logo);
|
||||
//if (this.video_institucional) formData.append('video_institucional', this.video_institucional);
|
||||
if (this.imagen_resena) formData.append('imagen_resena', this.imagen_resena);
|
||||
fetch('/app/parametrizacion-web/'+this.id_dato, {
|
||||
method: 'PUT',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.loadData();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
|
||||
submitUpdateDocumentos() {
|
||||
this.loading = true;
|
||||
const formData = new FormData();
|
||||
formData.append('contrato_condiciones_descripcion', this.contrato_condiciones_descripcion);
|
||||
formData.append('proteccion_datos_descripcion', this.proteccion_datos_descripcion);
|
||||
if (this.contrato_condiciones) formData.append('contrato_condiciones', this.contrato_condiciones);
|
||||
if (this.proteccion_datos) formData.append('proteccion_datos', this.proteccion_datos);
|
||||
|
||||
fetch('/app/parametrizacion-web/'+this.id_dato, {
|
||||
method: 'PUT',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.loadData();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
submitUpdateRedes() {
|
||||
this.loading = true;
|
||||
const formData = new FormData();
|
||||
formData.append('enlace_facebook', this.enlace_facebook);
|
||||
formData.append('enlace_instagram', this.enlace_instagram);
|
||||
formData.append('enlace_whatsapp', this.enlace_whatsapp);
|
||||
formData.append('estado_redes', this.estado_redes);
|
||||
|
||||
fetch('/app/parametrizacion-web/'+this.id_dato, {
|
||||
method: 'PUT',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.loadData();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
submitUpdateFNB() {
|
||||
this.loading = true;
|
||||
const formData = new FormData();
|
||||
formData.append('email_notificaciones_fnb', this.email_notificaciones_fnb);
|
||||
formData.append('descripcion_fnb', this.descripcion_fnb);
|
||||
if (this.donde_comprar_fnb) formData.append('donde_comprar_fnb', this.donde_comprar_fnb);
|
||||
|
||||
fetch('/app/parametrizacion-web/'+this.id_dato, {
|
||||
method: 'PUT',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.loadData();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
submitUpdateImportancia() {
|
||||
this.loading = true;
|
||||
const formData = new FormData();
|
||||
formData.append('descripcion', this.descripcion);
|
||||
formData.append('descripcion_cuadro_azul', this.descripcion_cuadro_azul);
|
||||
|
||||
fetch('/app/parametrizacion-web/'+this.id_dato, {
|
||||
method: 'PUT',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.loadData();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,294 @@
|
||||
<div class="float-right flex-row">
|
||||
<main class="max-w-screen-lg h-full">
|
||||
<!-- file upload modal -->
|
||||
<article aria-label="File Upload Modal" class="relative h-full flex flex-col bg-white shadow-xl rounded-md"
|
||||
ondrop="dropHandler(event);" ondragover="dragOverHandler(event);"
|
||||
ondragleave="dragLeaveHandler(event);" ondragenter="dragEnterHandler(event);">
|
||||
<!-- overlay -->
|
||||
<div id="overlay"
|
||||
class="w-full h-full absolute top-0 left-0 pointer-events-none z-50 flex flex-col items-center justify-center rounded-md">
|
||||
<i>
|
||||
<svg class="fill-current w-12 h-12 mb-3 text-blue-700" xmlns="http://www.w3.org/2000/svg" width="24"
|
||||
height="24" viewBox="0 0 24 24">
|
||||
<path d="M19.479 10.092c-.212-3.951-3.473-7.092-7.479-7.092-4.005 0-7.267 3.141-7.479 7.092-2.57.463-4.521 2.706-4.521 5.408 0 3.037 2.463 5.5 5.5 5.5h13c3.037 0 5.5-2.463 5.5-5.5 0-2.702-1.951-4.945-4.521-5.408zm-7.479-1.092l4 4h-3v4h-2v-4h-3l4-4z"/>
|
||||
</svg>
|
||||
</i>
|
||||
<p class="text-lg text-blue-700">Drop files to upload</p>
|
||||
</div>
|
||||
|
||||
<!-- scroll area -->
|
||||
<section class="h-full overflow-auto p-8 w-full h-full flex flex-col">
|
||||
<header class="border-dashed border-2 border-gray-400 py-12 flex flex-col justify-center items-center">
|
||||
<p class="mb-3 font-semibold text-gray-900 flex flex-wrap justify-center p-2">
|
||||
<span>Drag and drop your</span> <span>files anywhere or</span>
|
||||
</p>
|
||||
<input id="hidden-input" type="file" multiple class="hidden" accept=".csv"/>
|
||||
<button id="button"
|
||||
class="mt-2 rounded-sm px-3 py-1 bg-gray-200 hover:bg-gray-300 focus:shadow-outline focus:outline-none">
|
||||
Upload a file
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<h1 class="pt-8 pb-3 font-semibold sm:text-lg text-gray-900">
|
||||
To Upload
|
||||
</h1>
|
||||
|
||||
<ul id="gallery" class="flex flex-1 flex-wrap -m-1">
|
||||
<li id="empty"
|
||||
class="h-full w-full text-center flex flex-col items-center justify-center items-center">
|
||||
<img class="mx-auto w-32"
|
||||
src="https://user-images.githubusercontent.com/507615/54591670-ac0a0180-4a65-11e9-846c-e55ffce0fe7b.png"
|
||||
alt="no data"/>
|
||||
<span class="text-small text-gray-500">No files selected</span>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<!-- sticky footer -->
|
||||
<footer class="flex justify-end px-8 pb-8 pt-4">
|
||||
<button id="submit"
|
||||
class="rounded-sm px-3 py-1 bg-blue-700 hover:bg-blue-500 text-white focus:shadow-outline focus:outline-none">
|
||||
Upload now
|
||||
</button>
|
||||
<button id="cancel"
|
||||
class="ml-3 rounded-sm px-3 py-1 hover:bg-gray-300 focus:shadow-outline focus:outline-none">
|
||||
Cancel
|
||||
</button>
|
||||
</footer>
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- using two similar templates for simplicity in js code -->
|
||||
<template id="file-template">
|
||||
<li class="block p-1 w-full h-24">
|
||||
<article tabindex="0"
|
||||
class="group w-full h-full rounded-md focus:outline-none focus:shadow-outline elative bg-gray-100 cursor-pointer relative shadow-sm">
|
||||
<img alt="upload preview" class="img-preview hidden w-full h-full sticky object-cover rounded-md bg-fixed"/>
|
||||
|
||||
<section class="flex flex-col rounded-md text-xs break-words w-full h-full z-20 absolute top-0 py-2 px-3">
|
||||
<h1 class="flex-1 group-hover:text-blue-800"></h1>
|
||||
<div class="flex">
|
||||
<span class="p-1 text-blue-800">
|
||||
<i>
|
||||
<svg class="fill-current w-4 h-4 ml-auto pt-1" xmlns="http://www.w3.org/2000/svg" width="24"
|
||||
height="24" viewBox="0 0 24 24">
|
||||
<path d="M15 2v5h5v15h-16v-20h11zm1-2h-14v24h20v-18l-6-6z"/>
|
||||
</svg>
|
||||
</i>
|
||||
</span>
|
||||
<p class="p-1 size text-xs text-gray-700"></p>
|
||||
<button class="delete ml-auto focus:outline-none hover:bg-gray-300 p-1 rounded-md text-gray-800">
|
||||
<svg class="pointer-events-none fill-current w-4 h-4 ml-auto" xmlns="http://www.w3.org/2000/svg"
|
||||
width="24" height="24" viewBox="0 0 24 24">
|
||||
<path class="pointer-events-none"
|
||||
d="M3 6l3 18h12l3-18h-18zm19-4v2h-20v-2h5.711c.9 0 1.631-1.099 1.631-2h5.316c0 .901.73 2 1.631 2h5.711z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<template id="image-template">
|
||||
<li class="block p-1 w-full h-24">
|
||||
<article tabindex="0"
|
||||
class="group hasImage w-full h-full rounded-md focus:outline-none focus:shadow-outline bg-gray-100 cursor-pointer relative text-transparent hover:text-white shadow-sm">
|
||||
<img alt="upload preview" class="img-preview w-full h-full sticky object-cover rounded-md bg-fixed"/>
|
||||
|
||||
<section class="flex flex-col rounded-md text-xs break-words w-full h-full z-20 absolute top-0 py-2 px-3">
|
||||
<h1 class="flex-1"></h1>
|
||||
<div class="flex">
|
||||
<span class="p-1">
|
||||
<i>
|
||||
<svg class="fill-current w-4 h-4 ml-auto pt-" xmlns="http://www.w3.org/2000/svg" width="24"
|
||||
height="24" viewBox="0 0 24 24">
|
||||
<path d="M5 8.5c0-.828.672-1.5 1.5-1.5s1.5.672 1.5 1.5c0 .829-.672 1.5-1.5 1.5s-1.5-.671-1.5-1.5zm9 .5l-2.519 4-2.481-1.96-4 5.96h14l-5-8zm8-4v14h-20v-14h20zm2-2h-24v18h24v-18z"/>
|
||||
</svg>
|
||||
</i>
|
||||
</span>
|
||||
|
||||
<p class="p-1 size text-xs"></p>
|
||||
<button class="delete ml-auto focus:outline-none hover:bg-gray-300 p-1 rounded-md">
|
||||
<svg class="pointer-events-none fill-current w-4 h-4 ml-auto" xmlns="http://www.w3.org/2000/svg"
|
||||
width="24" height="24" viewBox="0 0 24 24">
|
||||
<path class="pointer-events-none"
|
||||
d="M3 6l3 18h12l3-18h-18zm19-4v2h-20v-2h5.711c.9 0 1.631-1.099 1.631-2h5.316c0 .901.73 2 1.631 2h5.711z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const fileTempl = document.getElementById("file-template"),
|
||||
imageTempl = document.getElementById("image-template"),
|
||||
empty = document.getElementById("empty");
|
||||
|
||||
// use to store pre selected files
|
||||
let FILES = {};
|
||||
|
||||
// check if file is of type image and prepend the initialied
|
||||
// template to the target element
|
||||
function addFile(target, file) {
|
||||
const isImage = file.type.match("image.*"),
|
||||
objectURL = URL.createObjectURL(file);
|
||||
|
||||
const clone = isImage
|
||||
? imageTempl.content.cloneNode(true)
|
||||
: fileTempl.content.cloneNode(true);
|
||||
|
||||
clone.querySelector("h1").textContent = file.name;
|
||||
clone.querySelector("li").id = objectURL;
|
||||
clone.querySelector(".delete").dataset.target = objectURL;
|
||||
clone.querySelector(".size").textContent =
|
||||
file.size > 1024
|
||||
? file.size > 1048576
|
||||
? Math.round(file.size / 1048576) + "mb"
|
||||
: Math.round(file.size / 1024) + "kb"
|
||||
: file.size + "b";
|
||||
|
||||
isImage &&
|
||||
Object.assign(clone.querySelector("img"), {
|
||||
src: objectURL,
|
||||
alt: file.name
|
||||
});
|
||||
|
||||
empty.classList.add("hidden");
|
||||
target.prepend(clone);
|
||||
|
||||
FILES[objectURL] = file;
|
||||
}
|
||||
|
||||
const gallery = document.getElementById("gallery"),
|
||||
overlay = document.getElementById("overlay");
|
||||
|
||||
// click the hidden input of type file if the visible button is clicked
|
||||
// and capture the selected files
|
||||
const hidden = document.getElementById("hidden-input");
|
||||
document.getElementById("button").onclick = () => hidden.click();
|
||||
hidden.onchange = (e) => {
|
||||
for (const file of e.target.files) {
|
||||
addFile(gallery, file);
|
||||
}
|
||||
};
|
||||
|
||||
// use to check if a file is being dragged
|
||||
const hasFiles = ({dataTransfer: {types = []}}) =>
|
||||
types.indexOf("Files") > -1;
|
||||
|
||||
// use to drag dragenter and dragleave events.
|
||||
// this is to know if the outermost parent is dragged over
|
||||
// without issues due to drag events on its children
|
||||
let counter = 0;
|
||||
|
||||
// reset counter and append file to gallery when file is dropped
|
||||
function dropHandler(ev) {
|
||||
ev.preventDefault();
|
||||
for (const file of ev.dataTransfer.files) {
|
||||
addFile(gallery, file);
|
||||
overlay.classList.remove("draggedover");
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// only react to actual files being dragged
|
||||
function dragEnterHandler(e) {
|
||||
e.preventDefault();
|
||||
if (!hasFiles(e)) {
|
||||
return;
|
||||
}
|
||||
++counter && overlay.classList.add("draggedover");
|
||||
}
|
||||
|
||||
function dragLeaveHandler(e) {
|
||||
1 > --counter && overlay.classList.remove("draggedover");
|
||||
}
|
||||
|
||||
function dragOverHandler(e) {
|
||||
if (hasFiles(e)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
// event delegation to caputre delete events
|
||||
// fron the waste buckets in the file preview cards
|
||||
gallery.onclick = ({target}) => {
|
||||
if (target.classList.contains("delete")) {
|
||||
const ou = target.dataset.target;
|
||||
document.getElementById(ou).remove(ou);
|
||||
gallery.children.length === 1 && empty.classList.remove("hidden");
|
||||
delete FILES[ou];
|
||||
}
|
||||
};
|
||||
|
||||
// print all selected files
|
||||
document.getElementById("submit").onclick = () => {
|
||||
var data = new FormData();
|
||||
let files = Object.values(FILES);
|
||||
for (var x = 0; x < files.length; x++) {
|
||||
|
||||
data.append('files', files[x], files[x].name);
|
||||
}
|
||||
var request = new XMLHttpRequest();
|
||||
request.open('post', '/account/file-manager/upload', true);
|
||||
// upload progress event
|
||||
request.upload.addEventListener('progress', function (e) {
|
||||
var percent_complete = (e.loaded / e.total) * 100;
|
||||
|
||||
// Percentage of upload completed
|
||||
console.log(percent_complete);
|
||||
});
|
||||
|
||||
// AJAX request finished event
|
||||
request.addEventListener('load', function (e) {
|
||||
clearUploads()
|
||||
});
|
||||
request.send(data);
|
||||
};
|
||||
|
||||
// clear entire selection
|
||||
document.getElementById("cancel").onclick = () => {
|
||||
clearUploads()
|
||||
};
|
||||
|
||||
function clearUploads() {
|
||||
while (gallery.children.length > 0) {
|
||||
gallery.lastChild.remove();
|
||||
}
|
||||
FILES = {};
|
||||
empty.classList.remove("hidden");
|
||||
gallery.append(empty);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.hasImage:hover section {
|
||||
background-color: rgba(5, 5, 5, 0.4);
|
||||
}
|
||||
|
||||
.hasImage:hover button:hover {
|
||||
background: rgba(5, 5, 5, 0.45);
|
||||
}
|
||||
|
||||
#overlay p,
|
||||
i {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
#overlay.draggedover {
|
||||
background-color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
#overlay.draggedover p,
|
||||
#overlay.draggedover i {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.group:hover .group-hover\:text-blue-800 {
|
||||
color: #2b6cb0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,120 @@
|
||||
<!-- container -->
|
||||
<nav
|
||||
class="fixed bottom-0 w-full border bg-white hidden
|
||||
overflow-x-auto">
|
||||
<!-- Bottom Icon Navigation Menu -->
|
||||
|
||||
<a
|
||||
href="."
|
||||
class="flex flex-col flex-grow items-center justify-center
|
||||
overflow-hidden whitespace-no-wrap text-sm transition-colors
|
||||
duration-100 ease-in-out hover:bg-gray-200 focus:text-orange-500">
|
||||
|
||||
<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">
|
||||
<polyline points="22 12 16 12 14 15 10 15 8 12 2 12"></polyline>
|
||||
<path
|
||||
d="M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0
|
||||
2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"></path>
|
||||
</svg>
|
||||
|
||||
<span class="hidden text-sm capitalize">Inbox</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="."
|
||||
class="flex flex-col flex-grow items-center justify-center
|
||||
overflow-hidden whitespace-no-wrap text-sm transition-colors
|
||||
duration-100 ease-in-out hover:bg-gray-200 text-orange-500">
|
||||
|
||||
<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-github">
|
||||
<path
|
||||
d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0
|
||||
0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77
|
||||
5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7
|
||||
0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0
|
||||
0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
|
||||
</svg>
|
||||
|
||||
<span class="text-sm capitalize">github</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="."
|
||||
class="flex flex-col flex-grow items-center justify-center
|
||||
overflow-hidden whitespace-no-wrap text-sm transition-colors
|
||||
duration-100 ease-in-out hover:bg-gray-200 focus:text-orange-500">
|
||||
|
||||
<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-bookmark">
|
||||
<path
|
||||
d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"></path>
|
||||
</svg>
|
||||
|
||||
<span class="hidden text-sm capitalize">bookmark</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="."
|
||||
class="flex flex-col flex-grow items-center justify-center
|
||||
overflow-hidden whitespace-no-wrap text-sm transition-colors
|
||||
duration-100 ease-in-out hover:bg-gray-200 focus:text-orange-500">
|
||||
|
||||
<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">
|
||||
<circle cx="12" cy="12" r="3"></circle>
|
||||
<path
|
||||
d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83
|
||||
2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65
|
||||
0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0
|
||||
0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2
|
||||
2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0
|
||||
0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0
|
||||
4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2
|
||||
0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0
|
||||
1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1
|
||||
1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0
|
||||
0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0
|
||||
1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0
|
||||
0-1.51 1z"></path>
|
||||
</svg>
|
||||
|
||||
<span class="hidden text-sm capitalize">Settings</span>
|
||||
</a>
|
||||
|
||||
</nav>
|
||||
@@ -0,0 +1,41 @@
|
||||
<nav class="px-1 md:px-4 flex justify-between bg-white h-16 border-b-2" x-data="{
|
||||
open: false,
|
||||
}">
|
||||
<!-- top bar -->
|
||||
|
||||
<ul class="flex items-center md:hidden">
|
||||
<!-- top bar left -->
|
||||
<div class="items-center justify-start h-16 md:px-10 py-2 object-cover">
|
||||
<img src="/img/logo.webp" alt="" class="w-20 ml-11 mt-1 md:mt-0 md:ml-0">
|
||||
</div>
|
||||
</ul>
|
||||
|
||||
<ul class="flex items-center">
|
||||
<!-- top bar center -->
|
||||
<li>
|
||||
<h1 class="mx-2 lg:pl-0 text-gray-700 md:text-sm text-xs" >{{ .user.NombreUsuario }} - {{ .user.Role.Name }}</h1>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="flex items-center">
|
||||
<!-- top bar right -->
|
||||
<li class="h-8 w-8 relative profile-action">
|
||||
<button @click="open = !open" class="block h-8 w-8 rounded-full overflow-hidden border-1 border-gray-600 focus:outline-none focus:border-white">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-7 h-7">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<!-- dropdown menu -->
|
||||
<div x-show="open" @click.outside="open = false" class="profile-action-dropdown absolute bg-gray-100 border border-t-0 shadow-xl text-gray-700 rounded-lg overflow-hidden w-48 top-10 right-0 mr-6 z-10">
|
||||
<a href="/app/profile" class="block px-4 py-2 hover:bg-gray-200">Mi cuenta</a>
|
||||
<a href="/do/logout" class="block px-4 py-2 hover:bg-gray-200"
|
||||
onclick="event.preventDefault(); document.getElementById('logout-form-profile').submit();">
|
||||
Cerrar sesión
|
||||
</a>
|
||||
<form id="logout-form-profile" action="/do/logout" method="POST" style="display: none;"></form>
|
||||
</div>
|
||||
<!-- dropdown menu end -->
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
@@ -0,0 +1,54 @@
|
||||
<footer class="text-gray-700 body-font bg-white absolute w-full bottom-0 left-0">
|
||||
<div class="container mx-auto flex items-center sm:flex-row flex-col">
|
||||
<a class="flex title-font font-medium items-center md:justify-start justify-center text-gray-900">
|
||||
<span class="ml-3 text-xl">Boilerplate</span>
|
||||
</a>
|
||||
<p class="text-sm text-gray-500 sm:ml-4 sm:pl-4 sm:border-l-2 sm:border-gray-200 sm:py-2 sm:mt-0 mt-4">© 2020
|
||||
Boilerplate —
|
||||
<a href="https://twitter.com/Company" class="text-gray-600 ml-1" rel="noopener noreferrer"
|
||||
target="_blank">@Company</a>
|
||||
</p>
|
||||
<p class="text-sm text-gray-500 sm:ml-4 sm:pl-4 sm:border-l-2 sm:border-gray-200 sm:py-2 sm:mt-0 mt-4">
|
||||
<a href="/faq" class="text-gray-600 ml-1" rel="noopener noreferrer">FAQ</a>
|
||||
</p>
|
||||
<p class="text-sm text-gray-500 sm:ml-4 sm:pl-4 sm:border-l-2 sm:border-gray-200 sm:py-2 sm:mt-0 mt-4">
|
||||
<a href="/contact-us" class="text-gray-600 ml-1" rel="noopener noreferrer" target="_blank">Contact Us</a>
|
||||
</p>
|
||||
<p class="text-sm text-gray-500 sm:ml-4 sm:pl-4 sm:border-l-2 sm:border-gray-200 sm:py-2 sm:mt-0 mt-4">
|
||||
<a href="/about-us" class="text-gray-600 ml-1" rel="noopener noreferrer" target="_blank">About Us</a>
|
||||
</p>
|
||||
<p class="text-sm text-gray-500 sm:ml-4 sm:pl-4 sm:border-l-2 sm:border-gray-200 sm:py-2 sm:mt-0 mt-4">
|
||||
<a href="/feature-request" class="text-gray-600 ml-1" rel="noopener noreferrer" target="_blank">Feature
|
||||
Request</a>
|
||||
</p>
|
||||
<span class="inline-flex sm:ml-auto sm:mt-0 mt-4 justify-center sm:justify-start">
|
||||
<a class="text-gray-500">
|
||||
<svg fill="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-5 h-5"
|
||||
viewBox="0 0 24 24">
|
||||
<path d="M18 2h-3a5 5 0 00-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 011-1h3z"></path>
|
||||
</svg>
|
||||
</a>
|
||||
<a class="ml-3 text-gray-500">
|
||||
<svg fill="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-5 h-5"
|
||||
viewBox="0 0 24 24">
|
||||
<path d="M23 3a10.9 10.9 0 01-3.14 1.53 4.48 4.48 0 00-7.86 3v1A10.66 10.66 0 013 4s-4 9 5 13a11.64 11.64 0 01-7 2c9 5 20 0 20-11.5a4.5 4.5 0 00-.08-.83A7.72 7.72 0 0023 3z"></path>
|
||||
</svg>
|
||||
</a>
|
||||
<a class="ml-3 text-gray-500">
|
||||
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
class="w-5 h-5" viewBox="0 0 24 24">
|
||||
<rect width="20" height="20" x="2" y="2" rx="5" ry="5"></rect>
|
||||
<path d="M16 11.37A4 4 0 1112.63 8 4 4 0 0116 11.37zm1.5-4.87h.01"></path>
|
||||
</svg>
|
||||
</a>
|
||||
<a class="ml-3 text-gray-500">
|
||||
<svg fill="currentColor" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="0"
|
||||
class="w-5 h-5" viewBox="0 0 24 24">
|
||||
<path stroke="none"
|
||||
d="M16 8a6 6 0 016 6v7h-4v-7a2 2 0 00-2-2 2 2 0 00-2 2v7h-4v-7a6 6 0 016-6zM2 9h4v12H2z"></path>
|
||||
<circle cx="4" cy="4" r="2" stroke="none"></circle>
|
||||
</svg>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</footer>
|
||||
@@ -0,0 +1,58 @@
|
||||
<nav class="p-6 flex justify-between bg-white h-16 border-b-2">
|
||||
<!-- top bar -->
|
||||
|
||||
<ul class="flex items-center lg:hidden">
|
||||
<!-- top bar left -->
|
||||
<li class="h-6 w-6">
|
||||
<img
|
||||
class="h-full w-full mx-auto"
|
||||
src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1b/Svelte_Logo.svg/512px-Svelte_Logo.svg.png"
|
||||
alt="svelte logo"/>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="flex items-center">
|
||||
<!-- top bar center -->
|
||||
<li>
|
||||
<h1 class="pl-10 lg:pl-0 text-gray-700">
|
||||
<a href="/">Boilerplate</a>
|
||||
</h1>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="flex items-center">
|
||||
{{if .auth}}
|
||||
<li class="h-8 w-8 profile-action">
|
||||
<button class="block h-8 w-8 rounded-full overflow-hidden border-1 border-gray-600 focus:outline-none focus:border-white">
|
||||
<img class="h-full w-full object-cover"
|
||||
src="https://images.unsplash.com/photo-1487412720507-e7ab37603c6f?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=256&q=80"
|
||||
alt="Your avatar">
|
||||
</button>
|
||||
<!-- dropdown menu -->
|
||||
<div class="profile-action-dropdown absolute bg-gray-100 border border-t-0 shadow-xl text-gray-700 rounded-b-lg w-48 z-10 right-0 mr-6 hidden">
|
||||
<a href="/app/files" class="block px-4 py-2 hover:bg-gray-200">Files</a>
|
||||
<a href="#" class="block px-4 py-2 hover:bg-gray-200">Settings</a>
|
||||
{{if .auth}}
|
||||
<a href="/do/logout" class="block px-4 py-2 hover:bg-gray-200"
|
||||
onclick="event.preventDefault(); document.getElementById('logout-form-profile').submit();">
|
||||
Logout
|
||||
</a>
|
||||
<form id="logout-form-profile" action="/do/logout" method="POST" style="display: none;"></form>
|
||||
{{end}}
|
||||
</div>
|
||||
<!-- dropdown menu end -->
|
||||
</li>
|
||||
{{else}}
|
||||
<li class="mr-2">
|
||||
<a href="/login">Login</a>
|
||||
<!-- dropdown menu end -->
|
||||
</li>
|
||||
<li>
|
||||
<a href="/register">Register</a>
|
||||
<!-- dropdown menu end -->
|
||||
</li>
|
||||
{{end}}
|
||||
|
||||
</ul>
|
||||
|
||||
</nav>
|
||||
@@ -0,0 +1,22 @@
|
||||
<!---Global Footer-->
|
||||
<footer class="text-black sm:content-center border-t border-gray-300">
|
||||
<div class="bg-white">
|
||||
<div class="container text-center lg:px-5 lg:py-6 mx-auto flex items-center sm:flex-row flex-col mb-2">
|
||||
<a href="https://verify.rest/login"
|
||||
class="flex title-font font-medium items-center md:justify-start justify-center text-gray-900">
|
||||
<img src="/img/logo.svg" style="height: 40px" alt="">
|
||||
</a>
|
||||
<nav class="md:ml-auto md:mr-auto flex flex-wrap items-center text-base justify-center hidden md:block">
|
||||
<a class="mr-5 hover:text-indigo font-mono" href="/about-us">About Us</a>
|
||||
<a href="/terms" class="mr-5 hover:text-indigo font-mono">Terms</a>
|
||||
<a href="/privacy-policy" class="mr-5 hover:text-indigo font-mono">Privacy Policy</a>
|
||||
<a href="/disclaimer" class="mr-5 hover:text-indigo font-mono">Disclaimer</a>
|
||||
</nav>
|
||||
<span
|
||||
class="text-sm text-gray-600 font-bold inline-flex sm:ml-auto sm:mt-0 mt-4 justify-center sm:justify-start">
|
||||
© Copyright 2020
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<!--- End Global Footer-->
|
||||
@@ -0,0 +1,44 @@
|
||||
<!---Global Header-->
|
||||
<header class="text-gray-700 body-font border-b border-gray-300 fixed w-full z-10 bg-white">
|
||||
<div class="container mx-auto flex flex-wrap p-5 flex-col md:flex-row items-center">
|
||||
<a href="/" class="flex title-font font-medium items-center text-gray-900 mb-4 md:mb-0">
|
||||
<img src="/img/logo.svg" alt="" style="height:50px;">
|
||||
</a>
|
||||
<nav class="md:ml-auto md:mr-auto flex flex-wrap items-center text-base justify-center hidden md:block">
|
||||
<a class="mr-5 hover:text-indigo-700 font-mono" href="/#validate-block">Validate</a>
|
||||
<a class="mr-5 hover:text-indigo-700 font-mono" href="/#feature-block">Features</a>
|
||||
<a class="mr-5 hover:text-indigo-700 font-mono" href="/#price-block">Price</a>
|
||||
<a class="mr-5 hover:text-indigo-700 font-mono" href="/#contact-block">Contact Us</a>
|
||||
</nav>
|
||||
{{if not .auth}}
|
||||
<a href="/login">
|
||||
<button
|
||||
class="inline-flex hero_button items-center global-header border-0 py-1 px-3 focus:outline-none hover:bg-indigo-700 rounded text-white mt-4 md:mt-0">
|
||||
Login
|
||||
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
class="w-4 h-4 ml-1" viewBox="0 0 24 24">
|
||||
<path d="M5 12h14M12 5l7 7-7 7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</a>
|
||||
<a href="/register" class="ml-3">
|
||||
<button
|
||||
class="inline-flex hero_button items-center global-header border-0 py-1 px-3 focus:outline-none hover:bg-indigo-700 rounded text-white mt-4 md:mt-0">
|
||||
Register
|
||||
</button>
|
||||
</a>
|
||||
{{else}}
|
||||
<a href="/app" class="ml-3">
|
||||
<button
|
||||
class="inline-flex hero_button items-center global-header border-0 py-1 px-3 focus:outline-none hover:bg-indigo-700 rounded text-white mt-4 md:mt-0">
|
||||
Dashboard
|
||||
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
class="w-4 h-4 ml-1" viewBox="0 0 24 24">
|
||||
<path d="M5 12h14M12 5l7 7-7 7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</a>
|
||||
{{end}}
|
||||
</div>
|
||||
</header>
|
||||
<!---End Global Header-->
|
||||
@@ -0,0 +1,89 @@
|
||||
<div x-data="{
|
||||
isSidebarOpen: false,
|
||||
}" class="flex min-h-screen">
|
||||
|
||||
<!-- Botón de menú para dispositivos móviles -->
|
||||
<div class="md:hidden fixed top-4 left-4 z-50">
|
||||
<button @click="isSidebarOpen = !isSidebarOpen" class="text-black focus:outline-none">
|
||||
<svg x-show="!isSidebarOpen" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none"
|
||||
viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
||||
</svg>
|
||||
<svg x-show="isSidebarOpen" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none"
|
||||
viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Overlay para dispositivos móviles -->
|
||||
<div x-show="isSidebarOpen" @click="isSidebarOpen = false"
|
||||
class="fixed inset-0 bg-black bg-opacity-50 z-40 md:hidden"></div>
|
||||
|
||||
<!-- Barra lateral -->
|
||||
<div :class="{'translate-x-0': isSidebarOpen, '-translate-x-full': !isSidebarOpen}"
|
||||
class="fixed z-50 md:relative transform md:translate-x-0 transition-transform duration-300 ease-in-out w-64 md:w-52 drop-shadow-md text-black shadow flex flex-col justify-between bg-white h-screen">
|
||||
|
||||
<!-- Encabezado de la barra lateral -->
|
||||
<div class="flex items-center justify-between h-16 px-10 py-2">
|
||||
<img src="/img/logo.webp" alt="Logo" class="w-36 mt-4 mb-2">
|
||||
<div class="md:hidden">
|
||||
<button @click="isSidebarOpen = false" class="text-black focus:outline-none">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" fill="none" viewBox="0 0 24 24"
|
||||
stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Contenido de la barra lateral -->
|
||||
<div class="overflow-y-auto h-full">
|
||||
<nav class="px-4 py-2">
|
||||
<ul>
|
||||
<!-- Recorrer módulos -->
|
||||
{{range $moduleName, $submodules := .modules}}
|
||||
<li class="my-1 cursor-pointer" x-data="{ showSubMenu: true }">
|
||||
<div class="flex items-center hover:bg-gray-200 px-2 rounded-lg py-2 font-semibold border" @click="showSubMenu = !showSubMenu">
|
||||
<div class="flex-shrink-0">
|
||||
<svg x-show="showSubMenu" xmlns="http://www.w3.org/2000/svg" fill="none"
|
||||
viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
|
||||
</svg>
|
||||
<svg x-show="!showSubMenu" xmlns="http://www.w3.org/2000/svg" fill="none"
|
||||
viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M8.25 4.5l7.5 7.5-7.5 7.5" />
|
||||
</svg>
|
||||
</div>
|
||||
<span class="ml-2 text-sm font-medium">
|
||||
{{ $moduleName }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Submenú -->
|
||||
<ul class="pl-6" x-show="showSubMenu" x-transition>
|
||||
{{range $submodule := $submodules}}
|
||||
<li>
|
||||
<a href="{{ $submodule.url }}"
|
||||
class="block hover:bg-gray-200 hover:font-semibold rounded-md px-3 py-2 text-sm text-black">
|
||||
{{ $submodule.title }}
|
||||
</a>
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Contenido principal -->
|
||||
<div class="flex-1">
|
||||
<!-- Tu contenido principal aquí -->
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,135 @@
|
||||
<aside
|
||||
class="hidden lg:flex flex-col items-center bg-black text-gray-700 shadow
|
||||
h-full">
|
||||
<!-- Side Nav Bar-->
|
||||
|
||||
<div class="h-16 flex items-center w-full hover:bg-white">
|
||||
<!-- Logo Section -->
|
||||
<a class="h-6 w-6 mx-auto" href="/">
|
||||
<img
|
||||
class="h-6 w-6 mx-auto"
|
||||
src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1b/Svelte_Logo.svg/512px-Svelte_Logo.svg.png"
|
||||
alt="svelte logo"/>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
<!-- Items Section -->
|
||||
<li class="hover:bg-gray-100">
|
||||
<a
|
||||
href="/account/file-manager"
|
||||
class="h-16 px-6 flex flex justify-center items-center w-full
|
||||
focus:text-orange-500">
|
||||
<svg
|
||||
class="h-5 w-5"
|
||||
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">
|
||||
<polyline
|
||||
points="22 12 16 12 14 15 10 15 8 12 2 12"></polyline>
|
||||
<path
|
||||
d="M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0
|
||||
2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0
|
||||
0-1.79 1.11z"></path>
|
||||
</svg>
|
||||
<span class="text-sm capitalize menu-item-text hidden">File Manager</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="hover:bg-gray-100">
|
||||
<a
|
||||
href="."
|
||||
class="h-16 px-6 flex flex justify-center items-center w-full
|
||||
focus:text-orange-500">
|
||||
<svg
|
||||
class="h-5 w-5"
|
||||
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">
|
||||
<path
|
||||
d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"></path>
|
||||
</svg>
|
||||
<span class="text-sm capitalize menu-item-text hidden">Settings</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="hover:bg-gray-100">
|
||||
<a
|
||||
href="."
|
||||
class="h-16 px-6 flex flex justify-center items-center w-full
|
||||
focus:text-orange-500">
|
||||
<svg
|
||||
class="h-5 w-5"
|
||||
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">
|
||||
<circle cx="12" cy="12" r="3"></circle>
|
||||
<path
|
||||
d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1
|
||||
0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0
|
||||
0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2
|
||||
2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0
|
||||
0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1
|
||||
0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0
|
||||
0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65
|
||||
0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0
|
||||
1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0
|
||||
1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2
|
||||
0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0
|
||||
1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0
|
||||
2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0
|
||||
0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65
|
||||
1.65 0 0 0-1.51 1z"></path>
|
||||
</svg>
|
||||
<span class="text-sm capitalize menu-item-text hidden">Settings</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<div class="mt-auto h-16 flex items-center w-full">
|
||||
{{if .auth}}
|
||||
<a href="/do/logout"
|
||||
class="logout h-16 w-10 mx-auto flex flex justify-center items-center
|
||||
w-full text-white-500 bg-red-500 focus:outline-none"
|
||||
onclick="event.preventDefault(); document.getElementById('logout-form').submit();">
|
||||
<svg
|
||||
class="h-5 w-5 text-white"
|
||||
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">
|
||||
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path>
|
||||
<polyline points="16 17 21 12 16 7"></polyline>
|
||||
<line x1="21" y1="12" x2="9" y2="12"></line>
|
||||
</svg>
|
||||
<span class="text-sm capitalize menu-item-text hidden bg-red-500 text-white">Logout</span>
|
||||
</a>
|
||||
<form id="logout-form" action="/do/logout" method="POST" style="display: none;"></form>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
</aside>
|
||||
@@ -0,0 +1,11 @@
|
||||
{{define "PrimaryButton"}}
|
||||
<button type="{{.Type}}" class="primary-button py-2 px-5 bg-[#284c91] text-white font-medium rounded shadow-sm">
|
||||
{{.Label}}
|
||||
</button>
|
||||
{{end}}
|
||||
|
||||
{{define "SecondaryButton"}}
|
||||
<button type="{{.Type}}" class="secondary-button w-full py-2 px-5 bg-[#beda75] text-[#284c91] font-medium rounded shadow-sm hover:bg-[#aecc5b] my-auto">
|
||||
{{.Label}}
|
||||
</button>
|
||||
{{end}}
|
||||
@@ -0,0 +1,289 @@
|
||||
<!-- Container Principal -->
|
||||
<div x-data="modals" @keydown.escape="closeModal" class="bg-white rounded-lg shadow">
|
||||
<div class="container mx-auto p-6 w-full">
|
||||
<div class="w-full ">
|
||||
<h1 class="text-2xl font-bold mb-4">Registrar PQR</h1>
|
||||
<div class="justify-between w-full md:flex mb-4">
|
||||
<p class="text-sm text-center md:text-left">Petición, Queja o Reclamo</p>
|
||||
</div>
|
||||
|
||||
<!-- Contenedor de Notificación -->
|
||||
<div x-show="mensaje" x-transition
|
||||
class="fixed top-0 left-1/2 transform -translate-x-1/2 mt-4 bg-green-500 text-white px-4 py-2 rounded shadow z-50">
|
||||
<p x-text="mensaje"></p>
|
||||
</div>
|
||||
|
||||
<!-- Agregar el GIF de carga -->
|
||||
<div x-show="loading" class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-50 justify-center items-center">
|
||||
<img src="../img/loading.gif" alt="Cargando..." class="w-16 h-16" />
|
||||
</div>
|
||||
<!-- Contenedor con Flex para Formulario e Información -->
|
||||
<div class="flex flex-col md:flex-row md:space-x-8">
|
||||
<!-- Contenedor del Formulario -->
|
||||
<div class=" p-6 rounded-lg border w-full shadow ">
|
||||
<h2 class="text-xl font-bold mb-2">Agregar registro</h2>
|
||||
<form @submit.prevent="submitAdd" class="text-sm">
|
||||
<div class="md:flex justify-between w-full md:space-x-2">
|
||||
<div class="w-full" x-init="newUsuario = '{{ .user.NombreUsuario }}'">
|
||||
<label class="block mt-4 mb-2" for="addUsuario">Usuario</label>
|
||||
<input type="text" id="addUsuario" x-model="newUsuario" placeholder="Usuario"
|
||||
class="border border-gray-300 rounded w-full p-2" required disabled>
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<label class="block mt-4 mb-2" for="addNombre">Nombre</label>
|
||||
<input type="text" id="addNombre" x-model="newNombre" placeholder="Nombre"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md:flex justify-between w-full md:space-x-2">
|
||||
<div class="w-full">
|
||||
<label class="block mt-4 mb-2" for="addCedula">Cédula</label>
|
||||
<input type="number" id="addCedula" x-model="newCedula" placeholder="Cédula"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<label class="block mt-4 mb-2" for="addTelefono">Teléfono</label>
|
||||
<input type="number" id="addTelefono" x-model="newTelefono" placeholder="Teléfono"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md:flex justify-between w-full md:space-x-2">
|
||||
<div class="w-full">
|
||||
<label class="block mt-4 mb-2" for="addDepartamento">Departamento</label>
|
||||
<input type="text" id="addDepartamento" x-model="newDepartamento"
|
||||
placeholder="Departamento" class="border border-gray-300 rounded w-full p-2"
|
||||
required>
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<label class="block mt-4 mb-2" for="addCiudad">Ciudad</label>
|
||||
<input type="text" id="addCiudad" x-model="newCiudad" placeholder="Ciudad"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
</div>
|
||||
</div>
|
||||
<label class="block mt-4 mb-2" for="addDireccion">Dirección</label>
|
||||
<input type="text" id="addDireccion" x-model="newDireccion" placeholder="Dirección"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
<div class="md:flex justify-between w-full md:space-x-2">
|
||||
<div class="w-full">
|
||||
<label class="block mt-4 mb-2" for="addBarrio">Barrio</label>
|
||||
<input type="text" id="addBarrio" x-model="newBarrio" placeholder="Barrio"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<label class="block mt-4 mb-2" for="addPqrsEmail">Email</label>
|
||||
<input type="email" id="addPqrsEmail" x-model="newPqrsEmail" placeholder="Email"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
</div>
|
||||
</div>
|
||||
<label class="block mt-4 mb-2" for="addSolicitud">Solicitud</label>
|
||||
<select id="addSolicitud" x-model="newSolicitud"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
<option value="">Seleccione una opción</option>
|
||||
<option value="P">Petición</option>
|
||||
<option value="Q">Queja</option>
|
||||
<option value="R">Reclamo</option>
|
||||
<option value="R">Recursos</option>
|
||||
</select>
|
||||
|
||||
<label class="block mt-4 mb-2" for="addDescripcion">Descripción</label>
|
||||
<textarea id="addDescripcion" x-model="newDescripcion" placeholder="Descripción"
|
||||
class="border border-gray-300 rounded w-full p-2" required></textarea>
|
||||
|
||||
<div class="mt-4">
|
||||
<label class="block mb-2" for="addImagen">Imagen (opcional)</label>
|
||||
<input type="file" id="addImagen" @change="handleImageUpload" accept=".jpg,.jpeg,.png,.pdf"
|
||||
class="border border-gray-300 rounded w-full p-2">
|
||||
<div class="mt-2" x-show="previewImage || previewPdf">
|
||||
<!-- Previsualización de imagen -->
|
||||
<img x-show="previewImage" :src="previewImage" alt="Vista previa de imagen"
|
||||
class="max-w-full max-h-32 rounded shadow">
|
||||
<!-- Previsualización de PDF -->
|
||||
<iframe x-show="previewPdf" :src="previewPdf"
|
||||
class="w-full h-32 border rounded"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<label class="flex items-center">
|
||||
<input type="checkbox" id="addIsAcept" x-model="newIsAcept" class="mr-2">
|
||||
Acepto ser notificado en conformidad con el artículo 56 de la ley 1437 del 2011 a mi correo electrónico con la
|
||||
respuesta a mi solicitud.
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Enviar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Contenedor de Información -->
|
||||
<div class="bg-gray-100 border p-6 rounded-lg h-auto w-full mt-8 md:mt-0 my-auto ">
|
||||
<h2 class="text-xl font-bold mb-4">Información sobre PQR</h2>
|
||||
<p class="mb-4"><strong>Señor usuario:</strong> Gases del Oriente SA ESP ha dispuesto esta oficina
|
||||
virtual para facilitar y agilizar sus peticiones, quejas y reclamos, de una manera rápida y
|
||||
sencilla. Es importante que comprenda los siguientes conceptos para tramitar una PQR:</p>
|
||||
|
||||
<p class="mt-4"><strong>Petición:</strong> Es cualquier solicitud que hace un usuario relacionado
|
||||
con el servicio de Gas Natural, puede ser un cambio de suscriptor, actualización de dirección,
|
||||
duplicado de facturas, etc.</p>
|
||||
|
||||
<p class="mt-4"><strong>Queja:</strong> Cualquier expresión verbal o escrita referente a un mal
|
||||
comportamiento de algún funcionario o inconformidad en la forma en que se presta el servicio de
|
||||
Gas Natural.</p>
|
||||
|
||||
<p class="mt-4"><strong>Reclamo:</strong> Requerimiento mediante el cual el usuario manifiesta su
|
||||
inconformidad por algún valor facturado.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alpine.js Script -->
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('modals', () => ({
|
||||
addModal: false,
|
||||
editModal: false,
|
||||
viewModal: false,
|
||||
showConfirmModal: false,
|
||||
mensaje: '',
|
||||
|
||||
newUsuario: '',
|
||||
newNombre: '',
|
||||
newCedula: '',
|
||||
newSolicitud: '',
|
||||
newDepartamento: '',
|
||||
newCiudad: '',
|
||||
newDireccion: '',
|
||||
newTelefono: '',
|
||||
newBarrio: '',
|
||||
newPqrsEmail: '',
|
||||
newDescripcion: '',
|
||||
newNotas: '',
|
||||
newRevisado: false,
|
||||
|
||||
Usuario: '',
|
||||
Nombre: '',
|
||||
Cedula: '',
|
||||
Solicitud: '',
|
||||
Departamento: '',
|
||||
Ciudad: '',
|
||||
Direccion: '',
|
||||
Telefono: '',
|
||||
Barrio: '',
|
||||
PqrsEmail: '',
|
||||
Descripcion: '',
|
||||
Notas: '',
|
||||
Revisado: false,
|
||||
|
||||
previewImage: null,
|
||||
previewPdf: null,
|
||||
newImagen: null,
|
||||
newIsAcept: false,
|
||||
|
||||
Id: null,
|
||||
deleteId: null,
|
||||
loading: false,
|
||||
totalRecords: 0, // Agregar esta línea
|
||||
isLoading: false,
|
||||
|
||||
//CERRAR MODALES
|
||||
closeModal() {
|
||||
this.addModal = false;
|
||||
this.editModal = false;
|
||||
this.viewModal = false;
|
||||
this.showConfirmModal = false;
|
||||
},
|
||||
//CREAR
|
||||
submitAdd() {
|
||||
this.loading = true;
|
||||
fetch('/app/pqr', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
usuario: this.newUsuario,
|
||||
nombre: this.newNombre,
|
||||
cedula: this.newCedula,
|
||||
solicitud: this.newSolicitud,
|
||||
departamento: this.newDepartamento,
|
||||
ciudad: this.newCiudad,
|
||||
direccion: this.newDireccion,
|
||||
telefono: this.newTelefono,
|
||||
barrio: this.newBarrio,
|
||||
pqremail: this.newPqrsEmail,
|
||||
descripcion: this.newDescripcion,
|
||||
notas: this.newNotas,
|
||||
revisado: this.newRevisado,
|
||||
imagen: this.newImagen || null,
|
||||
is_acept: this.newIsAcept || false
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
// Limpiar los campos después de guardar
|
||||
this.newNombre = '';
|
||||
this.newCedula = '';
|
||||
this.newSolicitud = '';
|
||||
this.newDepartamento = '';
|
||||
this.newCiudad = '';
|
||||
this.newDireccion = '';
|
||||
this.newTelefono = '';
|
||||
this.newBarrio = '';
|
||||
this.newPqrsEmail = '';
|
||||
this.newDescripcion = '';
|
||||
this.newNotas = '';
|
||||
this.newRevisado = '';
|
||||
this.mensaje = 'Registro guardado exitosamente';
|
||||
this.newImagen = null,
|
||||
this.newIsAcept = false
|
||||
this.closeModal();
|
||||
|
||||
|
||||
// Mostrar el mensaje de notificación durante unos segundos
|
||||
setTimeout(() => {
|
||||
this.mensaje = ''; // Borrar el mensaje después de 3 segundos
|
||||
}, 3000);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
this.mensaje = error;
|
||||
// Mostrar el mensaje de error durante unos segundos
|
||||
setTimeout(() => {
|
||||
this.mensaje = ''; // Borrar el mensaje después de 3 segundos
|
||||
}, 3000);
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
},
|
||||
handleImageUpload(event) {
|
||||
const file = event.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
const validFormats = ["image/jpeg", "image/png", "application/pdf"];
|
||||
if (!validFormats.includes(file.type)) {
|
||||
alert("Solo se aceptan archivos en formato JPG, PNG o PDF.");
|
||||
return;
|
||||
}
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
if (file.type === "application/pdf") {
|
||||
this.previewPdf = e.target.result;
|
||||
this.previewImage = null; // Limpiar vista previa de imagen
|
||||
} else {
|
||||
this.previewImage = e.target.result;
|
||||
this.previewPdf = null; // Limpiar vista previa de PDF
|
||||
}
|
||||
this.newImagen = e.target.result; // Base64 de la imagen o PDF
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
},
|
||||
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
@@ -0,0 +1,151 @@
|
||||
<div x-data="modals" @keydown.escape="closeModal" class="bg-white rounded-lg shadow">
|
||||
|
||||
<div class="container mx-auto p-6 w-full">
|
||||
<h1 class="text-2xl font-bold mb-4">PQRs</h1>
|
||||
<div class="justify-between w-full md:flex">
|
||||
<p class="mb-4 text-sm">Relación de PQRs.</p>
|
||||
</div>
|
||||
|
||||
<!-- GIF de carga -->
|
||||
<div x-show="loading" class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-50 justify-center items-center">
|
||||
<img src="../img/loading.gif" alt="Cargando..." class="w-16 h-16" />
|
||||
</div>
|
||||
|
||||
<!-- Mostrar registros obtenidos -->
|
||||
<div x-show="!loading && records.length > 0" class="overflow-x-auto mt-4">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<template x-for="(record, index) in records" :key="index">
|
||||
<table class="min-w-full border-collapse border border-gray-200 rounded-lg overflow-hidden shadow-sm bg-gray-100 text-sm">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">No. Solicitud</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.No_Solicitud"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Fecha</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="formatDate(record.Fecha)"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Hora</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="formatTime(record.Hora)"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Clase</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.Clase.trim() || '-'"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Causal</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.Causal.trim() || '-'"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Detalle</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.Detalle.trim() || '-'"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Factura</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.Factura.trim() || '-'"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Estado</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.Estado.trim() || '-'"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Observación</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.Observacion.trim() || '-'"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Fecha Solución</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="formatDate(record.Fecha_Sol)"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Hora Solución</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="formatTime(record.Hora_Sol)"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Solución</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.Solucion.trim() || '-'"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Detalle Solución</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.DetalleSol.trim() || '-'"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Lectura</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.Lectura.trim() || '-'"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left font-bold">Observaciones Sol</td>
|
||||
<td class="border border-gray-300 px-4 py-2 text-left" x-text="record.Observaciones_Sol.trim() || '-'"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Mensaje si no hay registros -->
|
||||
<div x-show="!loading && records.length === 0" class="text-center mt-4 text-gray-500">
|
||||
No se encontraron registros.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alpine.js Script -->
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('modals', () => ({
|
||||
usuario: '{{ .user.NombreUsuario }}',
|
||||
records: [],
|
||||
loading: false,
|
||||
|
||||
init() {
|
||||
console.log('init llamado');
|
||||
this.loadRegister();
|
||||
},
|
||||
|
||||
async loadRegister() {
|
||||
try {
|
||||
console.log('loadRegister llamado');
|
||||
this.loading = true;
|
||||
const response = await fetch(`/app/loadpqrsicom/${this.usuario}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Error al cargar registros: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log('Registros obtenidos:', data);
|
||||
this.records = data?.data || [];
|
||||
} catch (error) {
|
||||
console.error('Error al cargar los registros:', error);
|
||||
this.records = [];
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
formatDate(date) {
|
||||
return new Date(date).toLocaleDateString('es-CO', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit'
|
||||
});
|
||||
},
|
||||
|
||||
formatTime(time) {
|
||||
const [hour, minute] = time.slice(11, 16).split(':');
|
||||
return `${hour}:${minute}`;
|
||||
},
|
||||
|
||||
closeModal() {
|
||||
this.loading = false;
|
||||
},
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
@@ -0,0 +1,136 @@
|
||||
<div x-data="modals" @keydown.escape="closeModal"
|
||||
class="bg-white rounded-lg shadow">
|
||||
<div class="container mx-auto p-6 w-full ">
|
||||
<h1 class="text-2xl font-bold mb-4">Perfil</h1>
|
||||
<form @submit.prevent="submitForm">
|
||||
<div>
|
||||
<label class="block mb-2" for="name">Nombre</label>
|
||||
<input type="text" id="name" x-model="Name" placeholder="Nombre"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block mt-4 mb-2" for="Email">Email</label>
|
||||
<input id="Email" x-model="Email" placeholder="Email" class="border border-gray-300 rounded w-full p-2"
|
||||
required>
|
||||
</div>
|
||||
<div class="bg-[#8eb02f] text-white px-4 py-2 my-4 rounded text-center cursor-pointer"
|
||||
x-on:click="showPasswordModal = true;" title="Cambiar contraseña">Cambiar contraseña</div>
|
||||
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded" :disabled="isLoading">
|
||||
<span x-show="!isLoading">Guardar Cambios</span>
|
||||
<span x-show="isLoading">Cargando...</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<!-- Modal cambiar contraseña -->
|
||||
<div x-cloak x-show="showPasswordModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<form @submit.prevent="changePass">
|
||||
<label class="block mb-2" for="password">Nueva contraseña</label>
|
||||
<input type="text" id="password" x-model="password" placeholder="Ingrese una contraseña"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar </button>
|
||||
<button type="button" class="bg-gray-600 text-white px-4 py-2 rounded"
|
||||
x-on:click="closeModal">Cancelar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Alpine.js Script -->
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('modals', () => ({
|
||||
showPasswordModal: false,
|
||||
Name: '',
|
||||
Email: '',
|
||||
password: '',
|
||||
Usuario: '',
|
||||
rolID: '',
|
||||
Id: null,
|
||||
isLoading: false,
|
||||
usuarioID: '{{ .user.ID }}', // Inicializar directamente en el Alpine.js
|
||||
|
||||
init() {
|
||||
this.loadRegister();
|
||||
},
|
||||
|
||||
loadRegister() {
|
||||
this.isLoading = true;
|
||||
fetch(`/app/user/` + this.usuarioID)
|
||||
.then(response => {
|
||||
if (!response.ok) throw new Error('Error al cargar el usuario');
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
this.Name = data.user.name || '';
|
||||
this.Email = data.user.email || '';
|
||||
this.Usuario = data.user.nombre_usuario || '';
|
||||
this.rolID = data.user.role_id || '';
|
||||
})
|
||||
.catch(error => alert(`Error: ${error.message}`)) // Manejo de errores
|
||||
.finally(() => {
|
||||
this.isLoading = false;
|
||||
});
|
||||
},
|
||||
|
||||
closeModal() {
|
||||
this.showPasswordModal = false;
|
||||
},
|
||||
|
||||
submitForm() {
|
||||
this.isLoading = true;
|
||||
fetch(`/app/users/` + this.usuarioID, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
name: this.Name,
|
||||
email: this.Email,
|
||||
nombre_usuario: this.Usuario,
|
||||
role_id: this.rolID,
|
||||
})
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) throw new Error('Error al actualizar el usuario');
|
||||
this.loadRegister();
|
||||
return response.json();
|
||||
})
|
||||
.then(() => {
|
||||
alert('Usuario actualizado con éxito');
|
||||
})
|
||||
.catch(error => alert(`Error: ${error.message}`))
|
||||
.finally(() => {
|
||||
this.isLoading = false;
|
||||
});
|
||||
},
|
||||
|
||||
changePass() {
|
||||
this.isLoading = true;
|
||||
fetch(`/app/password/` + this.usuarioID, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
password: this.password,
|
||||
})
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) throw new Error('Error al cambiar la contraseña');
|
||||
return response.json();
|
||||
})
|
||||
.then(() => {
|
||||
this.password = '';
|
||||
this.closeModal();
|
||||
alert('Contraseña cambiada con éxito');
|
||||
})
|
||||
.catch(error => alert(`Error: ${error.message}`))
|
||||
.finally(() => {
|
||||
this.isLoading = false;
|
||||
});
|
||||
},
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
@@ -0,0 +1,506 @@
|
||||
<!-- Container Principal -->
|
||||
<div x-data="modals" @keydown.escape="closeModal" class="bg-white rounded-lg shadow">
|
||||
<div class="container mx-auto p-6 w-full ">
|
||||
<h1 class="text-2xl font-bold mb-4">Lista de Roles</h1>
|
||||
<div class="justify-between w-full md:flex">
|
||||
<p class="mb-4 text-sm">Gestión de roles.</p>
|
||||
<!-- Campo de Búsqueda -->
|
||||
<div class="mb-4 relative">
|
||||
<input type="text" x-model="searchQuery" placeholder="Buscar..."
|
||||
class="border border-gray-300 rounded w-full md:w-60 p-2 text-sm" @input="loadRegister()">
|
||||
|
||||
<!-- Contenedor para el botón o el ícono de carga -->
|
||||
<div x-show="isLoading" class="absolute right-2 top-2 flex items-center">
|
||||
<!-- SVG de cargando (puedes reemplazarlo con un botón si lo prefieres) -->
|
||||
<svg class="animate-spin h-5 w-5 text-gray-500" xmlns="http://www.w3.org/2000/svg" fill="none"
|
||||
viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4">
|
||||
</circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Botón Nuevo Módulo -->
|
||||
<div class="flex justify-end mb-4">
|
||||
<button class="bg-[#8eb02f] text-white px-4 py-2 rounded text-sm"
|
||||
x-on:click="addModal=true">Nuevo</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Agregar el GIF de carga -->
|
||||
<div x-show="loading" class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-50 justify-center items-center">
|
||||
<img src="../img/loading.gif" alt="Cargando..." class="w-16 h-16" />
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto max-w-full">
|
||||
<!-- Tabla de registros -->
|
||||
<table class=" table-auto w-full">
|
||||
<thead class="text-sm text-left py-4 border-b border-gray-300">
|
||||
<tr class="text-left font-semibold border-collapse">
|
||||
<th class="py-2 px-4 border-b w-52 ">Nombre</th>
|
||||
<th class="py-2 px-4 border-b">Descripción</th>
|
||||
<th class="py-2 px-4 border-b">Submodulos</th>
|
||||
<th class="py-2 px-4 border-b w-32"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-gray-500 select-none text-sm ">
|
||||
<!-- Mensaje de Carga Inicial -->
|
||||
<tr class="hover:bg-gray-100" x-show="isLoading">
|
||||
<td colspan="" class="py-2 px-4 border-b text-center w-full">
|
||||
<div class="text-center mx-auto justify-center flex space-x-2">
|
||||
<!-- SVG de cargando (puedes reemplazarlo con un botón si lo prefieres) -->
|
||||
<svg class="animate-spin h-5 w-5 mx-1 text-gray-500" xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor"
|
||||
stroke-width="4">
|
||||
</circle>
|
||||
<path class="opacity-75" fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z">
|
||||
</path>
|
||||
</svg>
|
||||
Cargando registros...
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Itera sobre los roles -->
|
||||
<template x-for="registro in registros" :key="registro.ID">
|
||||
<tr class="hover:bg-gray-100" :data-role-id="registro.ID">
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="registro.name"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="registro.description"></td>
|
||||
<td class="py-3 text-xs px-4 border-b">
|
||||
<!-- Itera sobre los submódulos de un rol -->
|
||||
<template x-for="submodule in registro.submodules" :key="submodule.ID">
|
||||
<span x-text="submodule.title"
|
||||
class="rounded bg-green-100 text-green-600 p-1 mr-2 mb-1 inline-block">
|
||||
</span>
|
||||
</template>
|
||||
</td>
|
||||
<td class="py-3 text-xs px-4 border-b ">
|
||||
<div class="flex justify-between space-x-1">
|
||||
<button
|
||||
@click="viewModal = true; Name = registro.name; Description = registro.description; Submodules = registro.submodules;"
|
||||
title="Ver">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" class="w-5 text-[#8eb02f]">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
</svg>
|
||||
</button>
|
||||
<button @click="
|
||||
editModal = true;
|
||||
Id = registro.ID;
|
||||
Name = registro.name;
|
||||
Description = registro.description;
|
||||
Submodules = [...registro.submodules];
|
||||
modulos.forEach(modulo => {
|
||||
modulo.submodules.forEach(submodulo => {
|
||||
submodulo.checked = Submodules.some(sm => sm.ID === submodulo.ID);
|
||||
});
|
||||
});
|
||||
" title="Editar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" class="w-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10" />
|
||||
</svg>
|
||||
</button>
|
||||
<button @click="showConfirmModal = true; deleteId = registro.ID;" title="Eliminar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" class="w-5 text-red-500">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<tr x-show="sinregistro">
|
||||
<td colspan="3" class="py-2 px-4 border-b text-center">No hay registros disponibles.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<!-- Los botones de paginación se generarán aquí -->
|
||||
<div id="pagination" class="flex justify-left my-4 text-sm">
|
||||
</div>
|
||||
<!-- Mostrar conteo de registros -->
|
||||
<div id="recordCountDiv" class="text-sm text-gray-700 ml-4">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Ver -->
|
||||
<div x-cloak x-show="viewModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-lg w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Ver registro</h2>
|
||||
<p class="font-semibold" x-text="Name"></p>
|
||||
<p class="mt-2" x-text="Description"></p>
|
||||
|
||||
<h3 class="mt-4 font-bold">Submódulos:</h3>
|
||||
|
||||
<div class="mt-2 flex flex-wrap gap-2">
|
||||
<template x-for="submodule in Submodules" :key="submodule.ID">
|
||||
<span x-text="submodule.title" class="block rounded bg-green-100 text-green-600 p-1"></span>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<button class="mt-4 bg-[#8eb02f] text-white px-4 py-2 rounded"
|
||||
x-on:click="viewModal = false">Cerrar</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Modal Editar -->
|
||||
<div x-cloak x-show="editModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-lg w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Editar registro</h2>
|
||||
<form @submit.prevent="submitEdit">
|
||||
<label class="block mb-2" for="editName">Nombre</label>
|
||||
<input type="text" id="editName" x-model="Name" placeholder="Nombre"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
<label class="block mt-4 mb-2" for="editDescription">Descripción</label>
|
||||
<textarea id="editDescription" x-model="Description" placeholder="Descripción"
|
||||
class="border border-gray-300 rounded w-full p-2" required></textarea>
|
||||
<div class="mt-4">
|
||||
<label class="block mt-4 mb-2 col-span-2">Seleccionar Submódulos</label>
|
||||
|
||||
<template x-for="modulo in modulos" :key="modulo.ID">
|
||||
<div>
|
||||
<!-- Nombre del módulo -->
|
||||
<div class="mb-1">
|
||||
<label :for="'modulo-' + modulo.ID" x-text="modulo.title"
|
||||
class="font-bold text-sm"></label>
|
||||
</div>
|
||||
|
||||
<!-- Lista de submódulos -->
|
||||
<div class="grid grid-cols-2 gap-1 p-2 mb-2 border rounded-md">
|
||||
<template x-for="submodulo in modulo.submodules" :key="submodulo.ID">
|
||||
<div>
|
||||
<!-- Sincronizar el estado del checkbox con los submódulos seleccionados -->
|
||||
<input type="checkbox" :value="submodulo.ID" :id="'submodulo-' + submodulo.ID"
|
||||
x-model="submodulo.checked"
|
||||
:checked="Submodules.some(sm => sm.ID === submodulo.ID)" class="mr-2">
|
||||
<label :for="'submodulo-' + submodulo.ID" x-text="submodulo.title"></label>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar Cambios</button>
|
||||
<button type="button" class="bg-gray-600 text-white px-4 py-2 rounded"
|
||||
x-on:click="editModal = false">Cancelar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Modal Añadir -->
|
||||
<div x-cloak x-show="addModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-lg w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Agregar registro</h2>
|
||||
<form @submit.prevent="submitAdd">
|
||||
<label class="block mb-2" for="name">Título</label>
|
||||
<input type="text" id="name" x-model="newName" placeholder="Nombre"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
|
||||
<label class="block mt-4 mb-2" for="description">Descripción</label>
|
||||
<textarea id="description" x-model="newDescription" placeholder="Descripción"
|
||||
class="border border-gray-300 rounded w-full p-2" required></textarea>
|
||||
|
||||
<!-- Checkboxes para seleccionar submódulos -->
|
||||
<label class="block mt-4 mb-2 col-span-2">Seleccionar Submódulos</label>
|
||||
|
||||
<template x-for="modulo in modulos" :key="modulo.ID">
|
||||
<div>
|
||||
<div class="mb-1">
|
||||
<label :for="'modulo-' + modulo.ID" x-text="modulo.title" class="font-bold text-sm"></label>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-1 p-2 mb-2 border rounded-md">
|
||||
<template x-for="submodulo in modulo.submodules" :key="submodulo.ID">
|
||||
<div>
|
||||
<input type="checkbox" :value="submodulo.ID" :id="'submodulo-' + submodulo.ID"
|
||||
x-model="submodulo.checked" class="mr-2">
|
||||
<label :for="'submodulo-' + submodulo.ID" x-text="submodulo.title"></label>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar</button>
|
||||
<button type="button" class="bg-gray-600 text-white px-4 py-2 rounded"
|
||||
x-on:click="closeModal">Cancelar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Modal Confirmar Eliminación -->
|
||||
<div x-cloak x-show="showConfirmModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-4">Confirmar Eliminación</h2>
|
||||
<p>¿Estás seguro de que deseas eliminar este registro?</p>
|
||||
<div class="mt-4 flex justify-end">
|
||||
<button class="bg-red-500 text-white px-4 py-2 rounded mr-2" @click="deleteItem()">Eliminar</button>
|
||||
<button @click="closeModal" class="bg-gray-600 text-white px-4 py-2 rounded">Cancelar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alpine.js Script -->
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('modals', () => ({
|
||||
viewModal: false,
|
||||
addModal: false,
|
||||
editModal: false,
|
||||
showConfirmModal: false,
|
||||
|
||||
newName: '',
|
||||
newDescription: '',
|
||||
|
||||
Name: '',
|
||||
Description: '',
|
||||
modulos: [],
|
||||
Submodules: [],
|
||||
submodulos: [],
|
||||
|
||||
sinregistro: '',
|
||||
modules: [],
|
||||
|
||||
|
||||
|
||||
Id: null,
|
||||
deleteId: null,
|
||||
loading: false,
|
||||
totalRecords: 0, // Agregar esta línea
|
||||
isLoading: false,
|
||||
selectedModules: '',
|
||||
selectedSubmodules: '',
|
||||
registros: '',
|
||||
|
||||
|
||||
init() {
|
||||
this.loadRegister();
|
||||
},
|
||||
//CARGAR registros
|
||||
searchQuery: '', // Agrega esta línea dentro del objeto Alpine
|
||||
|
||||
// Modifica la función loadRegister para incluir la búsqueda
|
||||
loadRegister(page = 1) {
|
||||
this.isLoading = true;
|
||||
//this.loading = true;
|
||||
const search = this.searchQuery ? `&search=${this.searchQuery}` : '';
|
||||
fetch(`/app/loadroles?page=${page}${search}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
this.totalRecords = data.total; // Establece el total de registros aquí
|
||||
this.modulos = data.modules;
|
||||
this.registros = data.roles; // Asignar
|
||||
this.totalPages = data.totalPages; // Asignar total de páginas
|
||||
this.createPagination(this.totalPages, page);
|
||||
if (data.roles.length === 0) {
|
||||
this.sinregistro = true;
|
||||
} else {
|
||||
// Lógica de paginación
|
||||
const totalPages = Math.ceil(this.totalRecords / data.limit);
|
||||
this.createPagination(totalPages, page)
|
||||
}
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.isLoading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
},
|
||||
createPagination(totalPages, currentPage) {
|
||||
const paginationContainer = document.getElementById('pagination');
|
||||
paginationContainer.innerHTML = ''; // Limpiar la paginación actual
|
||||
|
||||
// Crear un contenedor para los botones de paginación
|
||||
const paginationButtonsContainer = document.createElement('div');
|
||||
paginationButtonsContainer.className = "md:flex mx-auto mb-2 md:justify-between items-center w-full"; // Alinear los botones
|
||||
|
||||
// Función para crear un botón
|
||||
const createButton = (text, isDisabled, onClick, additionalClasses = '') => {
|
||||
const button = document.createElement('button');
|
||||
button.textContent = text;
|
||||
button.disabled = isDisabled;
|
||||
button.className = `px-4 py-2 text-black bg-gray-200 ${additionalClasses} ${isDisabled ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-300'}`;
|
||||
if (!isDisabled) {
|
||||
button.onclick = onClick;
|
||||
}
|
||||
return button;
|
||||
};
|
||||
|
||||
// Botones de paginación
|
||||
const leftContainer = document.createElement('div');
|
||||
leftContainer.className = "md:flex text-center mb-2"; // Contenedor para los botones de paginación a la izquierda
|
||||
leftContainer.appendChild(createButton('Anterior', currentPage === 1, () => this.loadRegister(currentPage - 1), 'rounded-l-md'));
|
||||
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
const pageButton = createButton(i, false, () => this.loadRegister(i), `mx-1 ${i === currentPage ? 'bg-black text-gray-50' : 'bg-white text-black'} rounded-md`);
|
||||
leftContainer.appendChild(pageButton);
|
||||
}
|
||||
|
||||
leftContainer.appendChild(createButton('Siguiente', currentPage === totalPages, () => this.loadRegister(currentPage + 1), 'rounded-r-md'));
|
||||
|
||||
paginationButtonsContainer.appendChild(leftContainer);
|
||||
|
||||
// Agregar el conteo de registros a la derecha
|
||||
const recordCountDiv = document.createElement('div');
|
||||
const startRecord = (currentPage - 1) * 10 + 1; // Primer registro de la página actual
|
||||
const endRecord = Math.min(currentPage * 10, this.totalRecords); // Último registro mostrado
|
||||
recordCountDiv.className = "text-sm text-gray-700 text-center md:ml-auto"; // Sin margen para alineación a la izquierda
|
||||
recordCountDiv.innerHTML = `Mostrando ${startRecord} a ${endRecord} de ${this.totalRecords} registros`;
|
||||
|
||||
paginationButtonsContainer.appendChild(recordCountDiv);
|
||||
|
||||
// Agregar los botones de paginación al contenedor principal
|
||||
paginationContainer.appendChild(paginationButtonsContainer);
|
||||
},
|
||||
|
||||
//CERRAR MODALES
|
||||
closeModal() {
|
||||
this.addModal = false;
|
||||
this.editModal = false;
|
||||
this.viewModal = false;
|
||||
this.showConfirmModal = false;
|
||||
},
|
||||
//CREAR
|
||||
submitAdd() {
|
||||
this.loading = true;
|
||||
|
||||
const selectedSubmodules = this.modulos
|
||||
.map(modulo => {
|
||||
return {
|
||||
...modulo,
|
||||
submodules: modulo.submodules.filter(submodulo => submodulo.checked)
|
||||
};
|
||||
})
|
||||
.filter(modulo => modulo.submodules.length > 0);
|
||||
|
||||
const requestData = {
|
||||
name: this.newName,
|
||||
description: this.newDescription,
|
||||
submodules: selectedSubmodules.flatMap(modulo => modulo.submodules)
|
||||
};
|
||||
|
||||
fetch('/app/roles', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(requestData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.newName = '';
|
||||
this.newDescription = '';
|
||||
this.modulos.forEach(modulo => {
|
||||
modulo.submodules.forEach(submodulo => submodulo.checked = false); // Reset checkboxes
|
||||
});
|
||||
|
||||
this.closeModal();
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
,
|
||||
|
||||
//ACTUALIZAR
|
||||
submitEdit() {
|
||||
this.loading = true;
|
||||
|
||||
const submodulosSeleccionados = new Set();
|
||||
|
||||
this.modulos.forEach(modulo => {
|
||||
modulo.submodules.forEach(submodulo => {
|
||||
if (submodulo.checked) {
|
||||
submodulosSeleccionados.add(submodulo.ID);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (submodulosSeleccionados.size === 0) {
|
||||
this.submodulos = [];
|
||||
} else {
|
||||
this.submodulos = Array.from(submodulosSeleccionados).map(id => {
|
||||
return this.modulos.flatMap(modulo => modulo.submodules).find(sub => sub.ID === id);
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Submódulos seleccionados despues:', this.submodulos);
|
||||
|
||||
fetch(`/app/roles/${this.Id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
name: this.Name,
|
||||
description: this.Description,
|
||||
submodules: this.submodulos
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.Name = '';
|
||||
this.Description = '';
|
||||
this.submodulos = [];
|
||||
this.modulos.forEach(modulo => {
|
||||
modulo.submodules.forEach(submodulo => {
|
||||
submodulo.checked = false;
|
||||
});
|
||||
});
|
||||
this.closeModal();
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
//ELIMINAR
|
||||
deleteItem() {
|
||||
this.loading = true;
|
||||
fetch(`/app/roles/${this.deleteId}`, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
})
|
||||
.then(() => {
|
||||
this.closeModal();
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
},
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
@@ -0,0 +1,395 @@
|
||||
<!-- Container Principal -->
|
||||
<div x-data="modals" @keydown.escape="closeModal" class="bg-white rounded-lg shadow">
|
||||
<div class="container mx-auto p-6 w-full ">
|
||||
<h1 class="text-2xl font-bold mb-4">Lista de Submodulos</h1>
|
||||
<div class="justify-between w-full md:flex">
|
||||
<p class="mb-4 text-sm">Gestión de Submodulos.</p>
|
||||
<!-- Campo de Búsqueda -->
|
||||
<div class="mb-4 relative">
|
||||
<input type="text" x-model="searchQuery" placeholder="Buscar..."
|
||||
class="border border-gray-300 rounded w-full md:w-60 p-2 text-sm" @input="loadModules()">
|
||||
|
||||
<!-- Contenedor para el botón o el ícono de carga -->
|
||||
<div x-show="isLoading" class="absolute right-2 top-2 flex items-center">
|
||||
<!-- SVG de cargando (puedes reemplazarlo con un botón si lo prefieres) -->
|
||||
<svg class="animate-spin h-5 w-5 text-gray-500" xmlns="http://www.w3.org/2000/svg" fill="none"
|
||||
viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4">
|
||||
</circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Botón Nuevo Módulo -->
|
||||
<div class="flex justify-end mb-4">
|
||||
<button class="bg-[#8eb02f] text-white px-4 py-2 rounded text-sm"
|
||||
x-on:click="addModal=true">Nuevo</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Agregar el GIF de carga -->
|
||||
<div x-show="loading" class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-50 justify-center items-center">
|
||||
<img src="../img/loading.gif" alt="Cargando..." class="w-16 h-16" />
|
||||
</div>
|
||||
<div class="overflow-x-auto max-w-full">
|
||||
<!-- Tabla de Módulos -->
|
||||
<table class=" table-auto w-full">
|
||||
<thead class="text-sm text-left py-4 border-b border-gray-300">
|
||||
<tr class="text-left font-semibold border-collapse">
|
||||
<th class="py-2 px-4 border-b w-52 ">Título</th>
|
||||
<th class="py-2 px-4 border-b">Descripción</th>
|
||||
<th class="py-2 px-4 border-b w-52 ">URL</th>
|
||||
<th class="py-2 px-4 border-b">Modulo</th>
|
||||
<th class="py-2 px-4 border-b w-32"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="modulesList" class="text-gray-500 select-none text-sm ">
|
||||
<!-- Mensaje de Carga Inicial -->
|
||||
<tr class="hover:bg-gray-100">
|
||||
<td colspan="" class="py-2 px-4 border-b text-center w-full">
|
||||
<div class="text-center mx-auto justify-center flex space-x-2">
|
||||
<!-- SVG de cargando (puedes reemplazarlo con un botón si lo prefieres) -->
|
||||
<svg class="animate-spin h-5 w-5 mx-1 text-gray-500" xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor"
|
||||
stroke-width="4">
|
||||
</circle>
|
||||
<path class="opacity-75" fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z">
|
||||
</path>
|
||||
</svg>
|
||||
Cargando registros...
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<!-- Los botones de paginación se generarán aquí -->
|
||||
<div id="pagination" class="flex justify-left my-4 text-sm">
|
||||
</div>
|
||||
<!-- Mostrar conteo de registros -->
|
||||
<div id="recordCountDiv" class="text-sm text-gray-700 ml-4">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Ver -->
|
||||
<div x-cloak x-show="viewModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Ver registro</h2>
|
||||
<p class="font-semibold" x-text="Title"></p>
|
||||
<p class="mt-2" x-text="Description"></p>
|
||||
<p class="mt-2" x-text="URL"></p>
|
||||
<p class="mt-2" x-text="ModuleTitle"></p>
|
||||
<button class="mt-4 bg-[#8eb02f] text-white px-4 py-2 rounded"
|
||||
x-on:click="viewModal = false">Cerrar</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Editar -->
|
||||
<div x-cloak x-show="editModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Editar registro</h2>
|
||||
<form @submit.prevent="submitEditModule">
|
||||
<label class="block mb-2" for="editTitle">Título</label>
|
||||
<input type="text" id="editTitle" x-model="Title" placeholder="Título"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
<label class="block mt-4 mb-2" for="editDescription">Descripción</label>
|
||||
<textarea id="editDescription" x-model="Description" placeholder="Descripción"
|
||||
class="border border-gray-300 rounded w-full p-2" required></textarea>
|
||||
<label class="block mb-2" for="editURL">URL</label>
|
||||
<input type="text" id="editURL" x-model="URL" placeholder="URL"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
<label class="block mt-4 mb-2" for="editRole">Modulo</label>
|
||||
<select id="editModule" x-model="ModuleTitle" class="border border-gray-300 rounded w-full p-2"
|
||||
required>
|
||||
<option value="" disabled selected>Selecciona un modulo</option> <!-- Opción predeterminada -->
|
||||
<template x-for="module in modules" :key="module.ID">
|
||||
<option :value="module.ID" x-text="module.title"></option>
|
||||
<!-- Asegúrate de que 'name' y 'id' existen en tus roles -->
|
||||
</template>
|
||||
</select>
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar Cambios</button>
|
||||
<button type="button" class="bg-gray-600 text-white px-4 py-2 rounded"
|
||||
x-on:click="closeModal">Cancelar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Añadir -->
|
||||
<div x-cloak x-show="addModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Agregar registro</h2>
|
||||
<form @submit.prevent="submitAddModule">
|
||||
<label class="block mb-2" for="title">Título</label>
|
||||
<input type="text" id="title" x-model="newTitle" placeholder="Título"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
<label class="block mt-4 mb-2" for="description">Descripción</label>
|
||||
<textarea id="description" x-model="newDescription" placeholder="Descripción"
|
||||
class="border border-gray-300 rounded w-full p-2" required></textarea>
|
||||
<label class="block mb-2" for="URL">URL</label>
|
||||
<input type="text" id="URL" x-model="newURL" placeholder="URL"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
|
||||
<label class="block mt-4 mb-2" for="editModule">Modulo</label>
|
||||
<select id="editModule" x-model="newModule" class="border border-gray-300 rounded w-full p-2" required>
|
||||
<option value="" disabled selected>Selecciona un modulo</option> <!-- Opción predeterminada -->
|
||||
<template x-for="module in modules" :key="module.ID">
|
||||
<option :value="module.ID" x-text="module.title"></option>
|
||||
<!-- Asegúrate de que 'name' y 'id' existen en tus roles -->
|
||||
</template>
|
||||
</select>
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar registro</button>
|
||||
<button type="button" class="bg-gray-600 text-white px-4 py-2 rounded"
|
||||
x-on:click="closeModal">Cancelar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Confirmar Eliminación -->
|
||||
<div x-cloak x-show="showConfirmModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-4">Confirmar Eliminación</h2>
|
||||
<p>¿Estás seguro de que deseas eliminar este registro?</p>
|
||||
<div class="mt-4 flex justify-end">
|
||||
<button @click="deleteModule()" class="bg-red-500 text-white px-4 py-2 rounded mr-2">Eliminar</button>
|
||||
<button @click="closeModal" class="bg-gray-600 text-white px-4 py-2 rounded">Cancelar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alpine.js Script -->
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('modals', () => ({
|
||||
addModal: false,
|
||||
editModal: false,
|
||||
viewModal: false,
|
||||
showConfirmModal: false,
|
||||
|
||||
newTitle: '',
|
||||
newDescription: '',
|
||||
newURL: '',
|
||||
newModule: '',
|
||||
|
||||
Title: '',
|
||||
Description: '',
|
||||
URL: '',
|
||||
ModuleTitle: '',
|
||||
|
||||
Id: null,
|
||||
deleteId: null,
|
||||
loading: false,
|
||||
totalRecords: 0, // Agregar esta línea
|
||||
isLoading: false,
|
||||
|
||||
modules: '',
|
||||
|
||||
|
||||
init() {
|
||||
this.loadModules();
|
||||
},
|
||||
//CARGAR MODULOS
|
||||
searchQuery: '', // Agrega esta línea dentro del objeto Alpine
|
||||
|
||||
// Modifica la función loadModules para incluir la búsqueda
|
||||
loadModules(page = 1) {
|
||||
this.isLoading = true;
|
||||
//this.loading = true;
|
||||
const search = this.searchQuery ? `&search=${this.searchQuery}` : '';
|
||||
fetch(`/app/loadsubmodules?page=${page}${search}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
this.totalRecords = data.total; // Establece el total de registros aquí
|
||||
this.modules = data.modules;
|
||||
this.submodules = data.submodules; // Asignar módulos
|
||||
this.totalPages = data.totalPages; // Asignar total de páginas
|
||||
this.createPagination(this.totalPages, page);
|
||||
const modulesList = document.getElementById('modulesList');
|
||||
modulesList.innerHTML = ''; // Limpiar la lista actual
|
||||
if (data.modules.length === 0) {
|
||||
modulesList.innerHTML = `<tr><td colspan="3" class="py-2 px-4 border-b text-center">No hay módulos disponibles.</td></tr>`;
|
||||
} else {
|
||||
data.submodules.forEach(submodule => {
|
||||
const row = document.createElement('tr');
|
||||
row.setAttribute('data-module-id', submodule.ID);
|
||||
row.classList.add('hover:bg-gray-100')
|
||||
row.innerHTML = `
|
||||
<td class="py-3 text-xs px-4 border-b ">${submodule.title}</td>
|
||||
<td class="py-3 text-xs px-4 border-b ">${submodule.description}</td>
|
||||
<td class="py-3 text-xs px-4 border-b ">${submodule.url}</td>
|
||||
<td class="py-3 text-xs px-4 border-b ">${submodule.module.title}</td>
|
||||
<td class="py-3 text-xs px-4 border-b flex justify-between space-x-1">
|
||||
<button x-on:click="viewModal = true; Title = '${submodule.title}'; Description = '${submodule.description}'; ModuleTitle = '${submodule.module.title}'; URL = '${submodule.url}';" title="Ver">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 text-[#8eb02f]">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
</svg>
|
||||
</button>
|
||||
<button x-on:click="editModal = true; Id = '${submodule.ID}'; Title = '${submodule.title}'; Description = '${submodule.description}'; ModuleTitle = '${submodule.module.ID}'; URL = '${submodule.url}';" title="Editar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10" />
|
||||
</svg>
|
||||
</button>
|
||||
<button x-on:click="showConfirmModal = true; deleteId = '${submodule.ID}';" title="Eliminar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 text-red-500">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
|
||||
</svg>
|
||||
</button>
|
||||
</td>
|
||||
|
||||
`;
|
||||
modulesList.appendChild(row);
|
||||
});
|
||||
|
||||
// Lógica de paginación
|
||||
const totalPages = Math.ceil(this.totalRecords / data.limit);
|
||||
this.createPagination(totalPages, page)
|
||||
}
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.isLoading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
},
|
||||
createPagination(totalPages, currentPage) {
|
||||
const paginationContainer = document.getElementById('pagination');
|
||||
paginationContainer.innerHTML = ''; // Limpiar la paginación actual
|
||||
|
||||
// Crear un contenedor para los botones de paginación
|
||||
const paginationButtonsContainer = document.createElement('div');
|
||||
paginationButtonsContainer.className = "md:flex mx-auto mb-2 md:justify-between items-center w-full"; // Alinear los botones
|
||||
|
||||
// Función para crear un botón
|
||||
const createButton = (text, isDisabled, onClick, additionalClasses = '') => {
|
||||
const button = document.createElement('button');
|
||||
button.textContent = text;
|
||||
button.disabled = isDisabled;
|
||||
button.className = `px-4 py-2 text-black bg-gray-200 ${additionalClasses} ${isDisabled ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-300'}`;
|
||||
if (!isDisabled) {
|
||||
button.onclick = onClick;
|
||||
}
|
||||
return button;
|
||||
};
|
||||
|
||||
// Botones de paginación
|
||||
const leftContainer = document.createElement('div');
|
||||
leftContainer.className = "md:flex text-center mb-2"; // Contenedor para los botones de paginación a la izquierda
|
||||
leftContainer.appendChild(createButton('Anterior', currentPage === 1, () => this.loadModules(currentPage - 1), 'rounded-l-md'));
|
||||
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
const pageButton = createButton(i, false, () => this.loadModules(i), `mx-1 ${i === currentPage ? 'bg-black text-gray-50' : 'bg-white text-black'} rounded-md`);
|
||||
leftContainer.appendChild(pageButton);
|
||||
}
|
||||
|
||||
leftContainer.appendChild(createButton('Siguiente', currentPage === totalPages, () => this.loadModules(currentPage + 1), 'rounded-r-md'));
|
||||
|
||||
paginationButtonsContainer.appendChild(leftContainer);
|
||||
|
||||
// Agregar el conteo de registros a la derecha
|
||||
const recordCountDiv = document.createElement('div');
|
||||
const startRecord = (currentPage - 1) * 10 + 1; // Primer registro de la página actual
|
||||
const endRecord = Math.min(currentPage * 10, this.totalRecords); // Último registro mostrado
|
||||
recordCountDiv.className = "text-sm text-gray-700 text-center md:ml-auto"; // Sin margen para alineación a la izquierda
|
||||
recordCountDiv.innerHTML = `Mostrando ${startRecord} a ${endRecord} de ${this.totalRecords} registros`;
|
||||
|
||||
paginationButtonsContainer.appendChild(recordCountDiv);
|
||||
|
||||
// Agregar los botones de paginación al contenedor principal
|
||||
paginationContainer.appendChild(paginationButtonsContainer);
|
||||
},
|
||||
|
||||
//CERRAR MODALES
|
||||
closeModal() {
|
||||
this.addModal = false;
|
||||
this.editModal = false;
|
||||
this.viewModal = false;
|
||||
this.showConfirmModal = false;
|
||||
},
|
||||
//CREAR
|
||||
submitAddModule() {
|
||||
this.loading = true;
|
||||
fetch('/app/submodules', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
title: this.newTitle,
|
||||
description: this.newDescription,
|
||||
url: this.newURL,
|
||||
module_id: parseInt(this.newModule)
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.newTitle = '';
|
||||
this.newDescription = '';
|
||||
this.newURL = '';
|
||||
this.newModule = '';
|
||||
this.closeModal();
|
||||
this.loadModules();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
},
|
||||
//ACTUALIZAR
|
||||
submitEditModule() {
|
||||
this.loading = true;
|
||||
fetch(`/app/submodules/${this.Id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
title: this.Title,
|
||||
description: this.Description,
|
||||
url: this.URL,
|
||||
module_id: parseInt(this.ModuleTitle),
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.newTitle = '';
|
||||
this.newDescription = '';
|
||||
this.newURL = '';
|
||||
this.newModule = '';
|
||||
this.closeModal();
|
||||
this.loadModules();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
},
|
||||
//ELIMINAR
|
||||
deleteModule() {
|
||||
this.loading = true;
|
||||
fetch(`/app/submodules/${this.deleteId}`, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
})
|
||||
.then(() => {
|
||||
this.closeModal();
|
||||
this.loadModules();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
}
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
@@ -0,0 +1,396 @@
|
||||
<!-- Container Principal -->
|
||||
<div x-data="modals" @keydown.escape="closeModal" class="bg-white rounded-lg shadow">
|
||||
<div class="container mx-auto p-6 w-full ">
|
||||
<h1 class="text-2xl font-bold mb-4">Lista de tarifas </h1>
|
||||
<div class="justify-between w-full md:flex">
|
||||
<p class="mb-4 text-sm">Gestión de tarifas.</p>
|
||||
<!-- Campo de Búsqueda -->
|
||||
<div class="mb-4 relative">
|
||||
<input type="text" x-model="searchQuery" placeholder="Buscar..."
|
||||
class="border border-gray-300 rounded w-full md:w-60 p-2 text-sm" @input="loadRegister()">
|
||||
|
||||
<!-- Contenedor para el botón o el ícono de carga -->
|
||||
<div x-show="isLoading" class="absolute right-2 top-2 flex items-center">
|
||||
<!-- SVG de cargando (puedes reemplazarlo con un botón si lo prefieres) -->
|
||||
<svg class="animate-spin h-5 w-5 text-gray-500" xmlns="http://www.w3.org/2000/svg" fill="none"
|
||||
viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4">
|
||||
</circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Botón Nuevo registro -->
|
||||
<div class="flex justify-end mb-4">
|
||||
<button class="bg-[#8eb02f] text-white px-4 py-2 rounded text-sm"
|
||||
x-on:click="addModal=true">Nuevo</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Agregar el GIF de carga -->
|
||||
<div x-show="loading" class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-50 justify-center items-center">
|
||||
<img src="../img/loading.gif" alt="Cargando..." class="w-16 h-16" />
|
||||
</div>
|
||||
<div class="overflow-x-auto max-w-full">
|
||||
<!-- Tabla de Registros -->
|
||||
<table class=" table-auto w-full">
|
||||
<thead class="text-sm text-left py-4 border-b border-gray-300">
|
||||
<tr class="text-left font-semibold border-collapse">
|
||||
<th class="py-2 px-4 border-b">Item</th>
|
||||
<th class="py-2 px-4 border-b">Descripción</th>
|
||||
<th class="py-2 px-4 border-b">Archivo</th>
|
||||
<th class="py-2 px-4 border-b"></th>
|
||||
<th class="py-2 px-4 border-b w-32"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-gray-500 select-none text-sm ">
|
||||
<!-- Mensaje de Carga Inicial -->
|
||||
<tr class="hover:bg-gray-100" x-show="isLoading">
|
||||
<td colspan="" class="py-2 px-4 border-b text-center w-full">
|
||||
<div class="text-center mx-auto justify-center flex space-x-2">
|
||||
<!-- SVG de cargando (puedes reemplazarlo con un botón si lo prefieres) -->
|
||||
<svg class="animate-spin h-5 w-5 mx-1 text-gray-500" xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor"
|
||||
stroke-width="4">
|
||||
</circle>
|
||||
<path class="opacity-75" fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z">
|
||||
</path>
|
||||
</svg>
|
||||
Cargando registros...
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Itera sobre los roles -->
|
||||
<template x-for="registro in registros" :key="registro.ID">
|
||||
<tr class="hover:bg-gray-100" :data-role-id="registro.ID">
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="registro.ID"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="registro.description"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="registro.ruta"></td>
|
||||
<td class="py-3 text-xs px-4 border-b">
|
||||
<button class="bg-[#8eb02f] text-white px-4 py-2 rounded"
|
||||
x-on:click="window.open(`${window.location.origin}/${registro.ruta}`, '_blank')">
|
||||
Ver archivo
|
||||
</button>
|
||||
</td>
|
||||
<td class="py-3 text-xs px-4 border-b">
|
||||
<div class="flex justify-between gap-2">
|
||||
|
||||
<button
|
||||
@click="viewModal = true; Description = registro.description; Ruta = registro.ruta;"
|
||||
title="Ver">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" class="w-5 text-[#8eb02f]">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
@click="editModal = true; Id = registro.ID; Description = registro.description; Ruta = registro.ruta;"
|
||||
title="Editar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" class="w-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10" />
|
||||
</svg>
|
||||
</button>
|
||||
<button @click="showConfirmModal = true; deleteId = registro.ID;" title="Eliminar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" class="w-5 text-red-500">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<tr x-show="sinregistro">
|
||||
<td colspan="3" class="py-2 px-4 border-b text-center">No hay registros disponibles.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<!-- Los botones de paginación se generarán aquí -->
|
||||
<div id="pagination" class="flex justify-left my-4 text-sm">
|
||||
</div>
|
||||
<!-- Mostrar conteo de registros -->
|
||||
<div id="recordCountDiv" class="text-sm text-gray-700 ml-4">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Ver -->
|
||||
<div x-cloak x-show="viewModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Ver registro</h2>
|
||||
<p class="font-semibold" x-text="Description"></p>
|
||||
<p class="mt-2" x-text="Ruta"></p>
|
||||
<button class="mt-4 bg-[#8eb02f] text-white px-4 py-2 rounded"
|
||||
x-on:click="viewModal = false">Cerrar</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Editar -->
|
||||
<div x-cloak x-show="editModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Editar registro</h2>
|
||||
<form @submit.prevent="submitEdit">
|
||||
<label class="block mt-4 mb-2" for="editDescription">Descripción</label>
|
||||
<textarea id="editDescription" x-model="Description" placeholder="Descripción"
|
||||
class="border border-gray-300 rounded w-full p-2" required></textarea>
|
||||
<label class="block mb-2" for="editRuta">Archivo</label>
|
||||
<input type="file" id="editFile" @change="handleUpdateFileChange"
|
||||
class="border border-gray-300 rounded w-full p-2" accept=".jpg,.png,.pdf,.doc,.docx">
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar Cambios</button>
|
||||
<button type="button" class="bg-gray-600 text-white px-4 py-2 rounded"
|
||||
x-on:click="editModal = false">Cancelar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Añadir -->
|
||||
<div x-cloak x-show="addModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Agregar registro</h2>
|
||||
<form @submit.prevent="submitAdd">
|
||||
<label class="block mt-4 mb-2" for="description">Descripción</label>
|
||||
<textarea id="description" x-model="newDescription" placeholder="Descripción"
|
||||
class="border border-gray-300 rounded w-full p-2" required></textarea>
|
||||
<label class="block mb-2" for="file">Archivo</label>
|
||||
<input type="file" id="file" @change="handleFileChange"
|
||||
class="border border-gray-300 rounded w-full p-2" accept=".jpg,.png,.pdf,.doc,.docx" required>
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar registro</button>
|
||||
<button type="button" class="bg-gray-600 text-white px-4 py-2 rounded"
|
||||
x-on:click="closeModal">Cancelar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Confirmar Eliminación -->
|
||||
<div x-cloak x-show="showConfirmModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-4">Confirmar Eliminación</h2>
|
||||
<p>¿Estás seguro de que deseas eliminar este registro?</p>
|
||||
<div class="mt-4 flex justify-end">
|
||||
<button class="bg-red-500 text-white px-4 py-2 rounded mr-2" @click="deleteItem()">Eliminar</button>
|
||||
<button @click="closeModal" class="bg-gray-600 text-white px-4 py-2 rounded">Cancelar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alpine.js Script -->
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('modals', () => ({
|
||||
addModal: false,
|
||||
editModal: false,
|
||||
viewModal: false,
|
||||
showConfirmModal: false,
|
||||
|
||||
newDescription: '',
|
||||
newRuta: '',
|
||||
newFile: null, // Archivo para la carga
|
||||
|
||||
Description: '',
|
||||
Ruta: '',
|
||||
updateFile: null, // Archivo para la actualización
|
||||
|
||||
sinregistro: '',
|
||||
Id: null,
|
||||
deleteId: null,
|
||||
loading: false,
|
||||
totalRecords: 0,
|
||||
isLoading: false,
|
||||
registros: '',
|
||||
|
||||
init() {
|
||||
this.loadRegister();
|
||||
},
|
||||
|
||||
searchQuery: '',
|
||||
|
||||
loadRegister(page = 1) {
|
||||
this.isLoading = true;
|
||||
const search = this.searchQuery ? `&search=${this.searchQuery}` : '';
|
||||
fetch(`/loadtarifas?page=${page}${search}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
this.totalRecords = data.total;
|
||||
this.registros = data.registros;
|
||||
this.totalPages = data.totalPages;
|
||||
this.createPagination(this.totalPages, page);
|
||||
this.sinregistro = data.registros.length === 0;
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.isLoading = false;
|
||||
});
|
||||
},
|
||||
|
||||
createPagination(totalPages, currentPage) {
|
||||
const paginationContainer = document.getElementById('pagination');
|
||||
paginationContainer.innerHTML = '';
|
||||
|
||||
const paginationButtonsContainer = document.createElement('div');
|
||||
paginationButtonsContainer.className = "md:flex mx-auto mb-2 md:justify-between items-center w-full";
|
||||
|
||||
const createButton = (text, isDisabled, onClick, additionalClasses = '') => {
|
||||
const button = document.createElement('button');
|
||||
button.textContent = text;
|
||||
button.disabled = isDisabled;
|
||||
button.className = `px-4 py-2 text-black bg-gray-200 ${additionalClasses} ${isDisabled ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-300'}`;
|
||||
if (!isDisabled) {
|
||||
button.onclick = onClick;
|
||||
}
|
||||
return button;
|
||||
};
|
||||
|
||||
const leftContainer = document.createElement('div');
|
||||
leftContainer.className = "md:flex text-center mb-2";
|
||||
leftContainer.appendChild(createButton('Anterior', currentPage === 1, () => this.loadRegister(currentPage - 1), 'rounded-l-md'));
|
||||
|
||||
// Rango de páginas para mostrar
|
||||
const maxVisibleButtons = 5; // Número máximo de botones a mostrar
|
||||
const halfRange = Math.floor(maxVisibleButtons / 2);
|
||||
let startPage = Math.max(1, currentPage - halfRange);
|
||||
let endPage = Math.min(totalPages, currentPage + halfRange);
|
||||
|
||||
// Ajustar si estamos al inicio o al final del rango de páginas
|
||||
if (currentPage <= halfRange) {
|
||||
endPage = Math.min(totalPages, maxVisibleButtons);
|
||||
}
|
||||
if (currentPage + halfRange > totalPages) {
|
||||
startPage = Math.max(1, totalPages - maxVisibleButtons + 1);
|
||||
}
|
||||
|
||||
// Crear botones de paginación
|
||||
for (let i = startPage; i <= endPage; i++) {
|
||||
const pageButton = createButton(
|
||||
i,
|
||||
false,
|
||||
() => this.loadRegister(i),
|
||||
`mx-1 ${i === currentPage ? 'bg-black text-gray-50' : 'bg-white text-black'} rounded-md`
|
||||
);
|
||||
leftContainer.appendChild(pageButton);
|
||||
}
|
||||
|
||||
leftContainer.appendChild(createButton('Siguiente', currentPage === totalPages, () => this.loadRegister(currentPage + 1), 'rounded-r-md'));
|
||||
paginationButtonsContainer.appendChild(leftContainer);
|
||||
|
||||
const recordCountDiv = document.createElement('div');
|
||||
const startRecord = (currentPage - 1) * 10 + 1;
|
||||
const endRecord = Math.min(currentPage * 10, this.totalRecords);
|
||||
recordCountDiv.className = "text-sm text-gray-700 text-center md:ml-auto";
|
||||
recordCountDiv.innerHTML = `Mostrando ${startRecord} a ${endRecord} de ${this.totalRecords} registros`;
|
||||
|
||||
paginationButtonsContainer.appendChild(recordCountDiv);
|
||||
paginationContainer.appendChild(paginationButtonsContainer);
|
||||
},
|
||||
|
||||
closeModal() {
|
||||
this.addModal = false;
|
||||
this.editModal = false;
|
||||
this.viewModal = false;
|
||||
this.showConfirmModal = false;
|
||||
this.newFile = null; // Reiniciar archivo
|
||||
this.updateFile = null; // Reiniciar archivo
|
||||
},
|
||||
|
||||
handleFileChange(event) {
|
||||
this.newFile = event.target.files[0]; // Manejar el archivo seleccionado
|
||||
},
|
||||
|
||||
handleUpdateFileChange(event) {
|
||||
this.updateFile = event.target.files[0]; // Manejar el archivo seleccionado para la actualización
|
||||
},
|
||||
|
||||
submitAdd() {
|
||||
this.loading = true;
|
||||
const formData = new FormData();
|
||||
formData.append('description', this.newDescription);
|
||||
if (this.newFile) formData.append('file', this.newFile); // Adjuntar el archivo si existe
|
||||
|
||||
fetch('/app/tarifas', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
this.newDescription = '';
|
||||
this.newRuta = data.ruta; // Guardar la ruta del archivo en la respuesta
|
||||
this.newFile = null; // Reinicia la variable de archivo
|
||||
// Limpia manualmente el input de archivo en el DOM
|
||||
document.getElementById('file').value = '';
|
||||
this.closeModal();
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
submitEdit() {
|
||||
this.loading = true;
|
||||
const formData = new FormData();
|
||||
formData.append('description', this.Description);
|
||||
if (this.updateFile) formData.append('file', this.updateFile); // Adjuntar el archivo si existe
|
||||
|
||||
fetch(`/app/tarifas/${this.Id}`, {
|
||||
method: 'PUT',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
this.Description = '';
|
||||
this.Ruta = data.ruta; // Actualizar la ruta del archivo en la respuesta
|
||||
this.updateFile = null; // Reinicia la variable de archivo
|
||||
// Limpia manualmente el input de archivo en el DOM
|
||||
document.getElementById('editFile').value = '';
|
||||
this.closeModal();
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
deleteItem() {
|
||||
this.loading = true;
|
||||
fetch(`/app/tarifas/${this.deleteId}`, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
})
|
||||
.then(() => {
|
||||
this.closeModal();
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,19 @@
|
||||
<!-- Container Principal -->
|
||||
<div class="bg-white rounded-lg shadow">
|
||||
<div class="container mx-auto p-6 w-full ">
|
||||
<h1 class="text-2xl font-bold mb-4">Token Vencido</h1>
|
||||
<div class="justify-between w-full md:flex">
|
||||
<p class="mb-4 text-sm">Tu token ha expirado. Por favor, intenta restablecer tu contraseña nuevamente.</p>
|
||||
<a href="/request-password-reset"><button type="submit"
|
||||
class="bg-[#8eb02f] text-white px-4 py-2 rounded flex space-x-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
||||
stroke="currentColor" class="w-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5 3 12m0 0 7.5-7.5M3 12h18" />
|
||||
</svg>
|
||||
<p> Intentar Restablecer Contraseña </p>
|
||||
</button>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,303 @@
|
||||
<!-- Container Principal -->
|
||||
<div x-data="tramitesForm" class="bg-white rounded-lg shadow">
|
||||
<div class="mx-auto py-8 px-4 sm:px-6 lg:px-8 max-w-5xl mb-8">
|
||||
<div x-show="loading" class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-50 justify-center items-center">
|
||||
<img src="../img/loading.gif" alt="Cargando..." class="w-16 h-16" />
|
||||
</div>
|
||||
<div class="section-title flex items-center mb-6">
|
||||
<span class="w-1 h-10 bg-blue-800 mr-4"></span>
|
||||
<h2 class="text-3xl font-bold ">
|
||||
Gestión de Trámites
|
||||
</h2>
|
||||
</div>
|
||||
<!-- Subtítulo -->
|
||||
<h3 class="font-semibold text-xl mt-4">
|
||||
PROCESO PARA ADQUIRIR EL SERVICIO DE GAS
|
||||
</h3>
|
||||
<p class="text-black mt-2">
|
||||
Si a un no cuenta con el servicio de instalación del gas natural de Gases del Oriente ahora es más fácil. El
|
||||
procedimiento a seguir es el siguiente:
|
||||
</p>
|
||||
<div class=" shadow-[0_5px_25px_rgba(0,0,0,0.1)] rounded-2xl p-6 mt-4">
|
||||
<label class="block mb-2" for="desc_adquirir">Descripción de adquirir</label>
|
||||
<textarea id="desc_adquirir" x-model="desc_adquirir" class="border border-gray-300 rounded w-full p-2 mb-4" required></textarea>
|
||||
</div>
|
||||
<!-- Section with 3 cards below the description -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mt-8">
|
||||
<!-- Card 1 -->
|
||||
<div class=" shadow-[0_5px_25px_rgba(0,0,0,0.1)] rounded-2xl p-4 flex items-center">
|
||||
<img src="/img/img38.webp" alt="Phone Icon" class="w-16 h-16 mr-4">
|
||||
<p class="text-black">
|
||||
<label class="block mb-2" for="paso_1">Paso 1</label>
|
||||
<textarea id="paso_1" x-model="paso_1" class="border border-gray-300 rounded w-full p-2 mb-4" required></textarea>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Card 2 -->
|
||||
<div class=" shadow-[0_5px_25px_rgba(0,0,0,0.1)] rounded-2xl p-4 flex items-center">
|
||||
<img src="/img/img37.webp" alt="Letter Icon" class="w-16 h-16 mr-4">
|
||||
<p class="text-black">
|
||||
<label class="block mb-2" for="paso_2">Paso 2</label>
|
||||
<textarea id="paso_2" x-model="paso_2" class="border border-gray-300 rounded w-full p-2 mb-4" required></textarea>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Card 3 -->
|
||||
<div class=" shadow-[0_5px_25px_rgba(0,0,0,0.1)] rounded-2xl p-4 flex items-center">
|
||||
<img src="/img/img36.webp" alt="Building Icon" class="w-16 h-16 mr-4">
|
||||
<p class="text-black">
|
||||
<label class="block mb-2" for="paso_3">Paso 3</label>
|
||||
<textarea id="paso_3" x-model="paso_3" class="border border-gray-300 rounded w-full p-2 mb-4" required></textarea>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-black mt-8">
|
||||
Cuando la solicitud de instalación es para servicio residencial, la empresa programará la visita al bien inmueble
|
||||
indicado, dentro de los ocho (8) días siguientes a la recepción de la solicitud, con el fin de verificar la
|
||||
disponibilidad de red, que la vivienda cumpla con las condiciones técnicas y físicas para la viabilidad del
|
||||
servicio. Si el inmueble cumple con dichas especificaciones, el asesor comercial procede a solicitar la
|
||||
documentación requerida para la suscripción del contrato:
|
||||
</p>
|
||||
|
||||
<div class="mt-8 mb-8 p-6 rounded-2xl shadow-[0_5px_25px_rgba(0,0,0,0.1)]">
|
||||
<label class="block mb-2" for="doc_res">Documento Residencial</label>
|
||||
<textarea id="doc_res" x-model="doc_res" class="border border-gray-300 rounded w-full p-2 mb-4" required></textarea>
|
||||
</div>
|
||||
|
||||
<p class="text-black mt-8">
|
||||
Si el servicio a instalar corresponde a un Usuario potencial No Residencial, se emitirá un presupuesto dentro de
|
||||
los ocho (8) días siguientes a la visita el cual contendrá el valor de la instalación, y posterior a la
|
||||
aceptación, se recibirá la documentación solicitada con el cual se suscribirá el contrato. Si usted cuenta con la
|
||||
instalación interna debidamente construida por una firma constructora y reparadora inscrita ante la
|
||||
Superintendencia de Industria y Comercio y ante nuestra empresa, será necesario que la solicitud del servicio sea
|
||||
realizada únicamente en el canal presencial de nuestras oficinas y dar cumplimiento a los requisitos especificados
|
||||
a continuación:
|
||||
</p>
|
||||
|
||||
<div class="mt-8 mb-8 p-6 rounded-2xl shadow-[0_5px_25px_rgba(0,0,0,0.1)]">
|
||||
<label class="block mb-2" for="doc_nores">Documento No Residencial</label>
|
||||
<textarea id="doc_nores" x-model="doc_nores" class="border border-gray-300 rounded w-full p-2 mb-4" required></textarea>
|
||||
</div>
|
||||
|
||||
<p class="text-black font-semibold">
|
||||
Nota: GASES DEL ORIENTE S.A. E.S.P. informa que ningún funcionario de la compañía está autorizado para recibir
|
||||
dinero o solicitar dádiva alguna para la instalación del servicio.
|
||||
</p>
|
||||
|
||||
<!-- Formulario de Archivos -->
|
||||
<div class="p-6 rounded-lg border w-full shadow mt-6 mb-4">
|
||||
<h2 class="text-xl font-bold mb-2">Archivos</h2>
|
||||
<label class="block mb-2" for="arc_venta_comp">Archivo de Venta Completa</label>
|
||||
<input type="file" id="arc_venta_comp" @change="handleFileChange($event, 'arc_venta_comp')" class="border border-gray-300 rounded w-full p-2 mb-2" accept=".jpg,.png,.pdf,.doc,.docx">
|
||||
<p x-show="arc_venta_comp_path" class="mt-2 text-sm text-gray-600">
|
||||
Archivo actual: <a :href="`${window.location.origin}/${arc_venta_comp_path}`" target="_blank" class="text-blue-500 underline" x-text="arc_venta_comp_path"></a>
|
||||
</p>
|
||||
|
||||
<label class="block mb-2" for="arc_derecho">Archivo de Derecho</label>
|
||||
<input type="file" id="arc_derecho" @change="handleFileChange($event, 'arc_derecho')" class="border border-gray-300 rounded w-full p-2 mb-2" accept=".jpg,.png,.pdf,.doc,.docx">
|
||||
<p x-show="arc_derecho_path" class="mt-2 text-sm text-gray-600">
|
||||
Archivo actual: <a :href="`${window.location.origin}/${arc_derecho_path}`" target="_blank" class="text-blue-500 underline" x-text="arc_derecho_path"></a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="section-title flex items-center mb-6">
|
||||
<span class="w-1 h-10 bg-blue-800 mr-4"></span>
|
||||
<h2 class="text-3xl font-bold ">
|
||||
Instructivo y carta para el diligenciamiento de la solicitud de disponibilidad de servicio.
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<!-- Subtitle Section -->
|
||||
<h2 class="font-semibold text-lg text-[#5082e6] mb-4">
|
||||
INSTRUCTIVO SOLICITUD DE DISPONIBILIDAD DE SERVICIO CARTA SOLICITUD DE DISPONIBILIDAD DE SERVICIO
|
||||
</h2>
|
||||
<label class="block mb-2" for="arc_instruct">Archivo de Instructivo</label>
|
||||
<input type="file" id="arc_instruct" @change="handleFileChange($event, 'arc_instruct')" class="border border-gray-300 rounded w-full p-2 mb-2" accept=".jpg,.png,.pdf,.doc,.docx">
|
||||
<p x-show="arc_instruct_path" class="mt-2 text-sm text-gray-600">
|
||||
Archivo actual: <a :href="`${window.location.origin}/${arc_instruct_path}`" target="_blank" class="text-blue-500 underline" x-text="arc_instruct_path"></a>
|
||||
</p>
|
||||
|
||||
<!-- Requirements Title -->
|
||||
<h3 class="font-semibold text-xl mt-4 mb-4">
|
||||
REQUISITOS PARA TERMINACIÓN Y ANULACIÓN DEL SERVICIO
|
||||
</h3>
|
||||
|
||||
<!-- Content Section -->
|
||||
<div class="flex flex-col lg:flex-row items-center lg:items-start lg:space-x-8 mb-8">
|
||||
<!-- Left Text Content -->
|
||||
<div class="lg:w-3/5 mb-6 lg:mb-0">
|
||||
<div class=" p-6 rounded-2xl shadow-[0_5px_25px_rgba(0,0,0,0.1)]">
|
||||
<label class="block mb-2" for="anul_servicio">Anulación de Servicio</label>
|
||||
<textarea id="anul_servicio" x-model="anul_servicio" class="border border-gray-300 rounded w-full p-2 mb-4" required></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Image Content -->
|
||||
<div class="lg:w-2/5">
|
||||
<img src="/img/img39.webp" alt="Person writing on paper" class="mx-auto lg:mx-0" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 class="font-semibold text-xl mt-4 mb-4">
|
||||
EN CASO DE ANULACIÓN DE SERVICIO
|
||||
</h3>
|
||||
<!-- Content Section -->
|
||||
<p class="text-black mt-4">
|
||||
Para <strong>GASES DEL ORIENTE S.A. E.S.P.</strong>, anular el contrato de prestación del servicio de gas natural
|
||||
del inmueble antes señalado, es necesario que el titular presente la solicitud por escrito acompañada de una
|
||||
fotocopia de la cédula de ciudadanía. En caso de presentar la anulación una persona diferente al suscriptor del
|
||||
servicio, se debe acreditar propiedad sobre el inmueble y presentar la siguiente información:
|
||||
</p>
|
||||
|
||||
<!-- Information Box -->
|
||||
<div class="mt-4 bg-white p-6 rounded-2xl shadow-[0_5px_25px_rgba(0,0,0,0.1)]">
|
||||
<label class="block mb-2" for="act_suscriptor">Actualizar Suscriptor</label>
|
||||
<textarea id="act_suscriptor" x-model="act_suscriptor" class="border border-gray-300 rounded w-full p-2 mb-4" required></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Title Section -->
|
||||
<h3 class="font-semibold text-xl mt-4 mb-4">
|
||||
ACTUALIZACIÓN DE SUSCRIPTOR, ESTRATO O DIRECCIÓN DEL SERVICIO
|
||||
</h3>
|
||||
<!-- Content Section -->
|
||||
<p class="text-black mt-4">
|
||||
Los usuarios interesados en realizar la actualización de suscriptor, estrato o dirección del servicio de gas
|
||||
combustible deberán presentarse en las oficinas de Gases del Oriente S.A. E.S.P. o enviar solicitud escrita
|
||||
firmada por el o los propietarios del inmueble y presentar los siguientes documentos:
|
||||
</p>
|
||||
|
||||
<!-- Documents List -->
|
||||
<h3 class="text-lg mt-4">Algunos de estos documentos:</h3>
|
||||
<div class="mt-4 p-6 rounded-2xl shadow-[0_5px_25px_rgba(0,0,0,0.1)]">
|
||||
<label class="block mb-2" for="act_est_res">Actualizar Estado Res</label>
|
||||
<textarea id="act_est_res" x-model="act_est_res" class="border border-gray-300 rounded w-full p-2 mb-4" required></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Title Section -->
|
||||
<h3 class="font-semibold text-xl mt-4 mb-4">
|
||||
DOCUMENTACIÓN REQUERIDA PARA ACTUALIZACIÓN DE ESTRATO
|
||||
</h3>
|
||||
|
||||
<div class="mt-4 p-6 rounded-2xl shadow-[0_5px_25px_rgba(0,0,0,0.1)]">
|
||||
<div class="flex items-start mb-4">
|
||||
<p class="font-semibold">Para usuarios residenciales</p>
|
||||
</div>
|
||||
<label class="block mb-2" for="act_est_nores">Actualizar Estado No Residencial</label>
|
||||
<textarea id="act_est_nores" x-model="act_est_nores" class="border border-gray-300 rounded w-full p-2 mb-4" required></textarea>
|
||||
<div class="flex items-start mb-4 mt-6">
|
||||
<p class="font-semibold">Para usuarios no residenciales</p>
|
||||
</div>
|
||||
<label class="block mb-2" for="act_direccion">Actualizar Dirección</label>
|
||||
<textarea id="act_direccion" x-model="act_direccion" class="border border-gray-300 rounded w-full p-2 mb-4" required></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Botón de Guardar -->
|
||||
<div class="mt-6 text-right">
|
||||
<button @click.prevent="submitUpdate" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar Cambios</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alpine.js Script -->
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('tramitesForm', () => ({
|
||||
desc_adquirir: '',
|
||||
paso_1: '',
|
||||
paso_2: '',
|
||||
paso_3: '',
|
||||
doc_res: '',
|
||||
doc_nores: '',
|
||||
anul_servicio: '',
|
||||
act_suscriptor: '',
|
||||
act_est_res: '',
|
||||
act_est_nores: '',
|
||||
act_direccion: '',
|
||||
arc_venta_comp: null,
|
||||
arc_venta_comp_path: '',
|
||||
arc_derecho: null,
|
||||
arc_derecho_path: '',
|
||||
arc_instruct: null,
|
||||
arc_instruct_path: '',
|
||||
loading: false,
|
||||
id_dato : 0,
|
||||
|
||||
init() {
|
||||
this.loadData();
|
||||
},
|
||||
|
||||
loadData() {
|
||||
this.loading = true;
|
||||
fetch('/loadtramites') // Llama al endpoint que devuelve el registro de trámites
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data) {
|
||||
this.id_dato = data.ID;
|
||||
this.desc_adquirir = data.desc_adquirir;
|
||||
this.paso_1 = data.paso_1;
|
||||
this.paso_2 = data.paso_2;
|
||||
this.paso_3 = data.paso_3;
|
||||
this.doc_res = data.doc_res;
|
||||
this.doc_nores = data.doc_nores;
|
||||
this.anul_servicio = data.anul_servicio;
|
||||
this.act_suscriptor = data.act_suscriptor;
|
||||
this.act_est_res = data.act_est_res;
|
||||
this.act_est_nores = data.act_est_nores;
|
||||
this.act_direccion = data.act_direccion;
|
||||
this.arc_venta_comp_path = data.arc_venta_comp;
|
||||
this.arc_derecho_path = data.arc_derecho;
|
||||
this.arc_instruct_path = data.arc_instruct;
|
||||
}
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
handleFileChange(event, field) {
|
||||
if (field === 'arc_venta_comp') {
|
||||
this.arc_venta_comp = event.target.files[0];
|
||||
} else if (field === 'arc_derecho') {
|
||||
this.arc_derecho = event.target.files[0];
|
||||
} else if (field === 'arc_instruct') {
|
||||
this.arc_instruct = event.target.files[0];
|
||||
}
|
||||
},
|
||||
|
||||
submitUpdate() {
|
||||
this.loading = true;
|
||||
const formData = new FormData();
|
||||
formData.append('desc_adquirir', this.desc_adquirir);
|
||||
formData.append('paso_1', this.paso_1);
|
||||
formData.append('paso_2', this.paso_2);
|
||||
formData.append('paso_3', this.paso_3);
|
||||
formData.append('doc_res', this.doc_res);
|
||||
formData.append('doc_nores', this.doc_nores);
|
||||
formData.append('anul_servicio', this.anul_servicio);
|
||||
formData.append('act_suscriptor', this.act_suscriptor);
|
||||
formData.append('act_est_res', this.act_est_res);
|
||||
formData.append('act_est_nores', this.act_est_nores);
|
||||
formData.append('act_direccion', this.act_direccion);
|
||||
|
||||
if (this.arc_venta_comp) formData.append('arc_venta_comp', this.arc_venta_comp);
|
||||
if (this.arc_derecho) formData.append('arc_derecho', this.arc_derecho);
|
||||
if (this.arc_instruct) formData.append('arc_instruct', this.arc_instruct);
|
||||
|
||||
fetch('/app/tramites/'+this.id_dato, {
|
||||
method: 'PUT',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.loadData();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
@@ -0,0 +1,561 @@
|
||||
<!-- Container Principal -->
|
||||
<div x-data="modals" @keydown.escape="closeModal" class="bg-white rounded-lg shadow">
|
||||
<div class="container mx-auto p-6 w-full ">
|
||||
<h1 class="text-2xl font-bold mb-4">Lista de Usuarios</h1>
|
||||
<div class="justify-between w-full md:flex">
|
||||
<p class="mb-4 text-sm">Gestión de usuarios.</p>
|
||||
<!-- Campo de Búsqueda -->
|
||||
<div class="mb-4 relative">
|
||||
<input type="text" x-model="searchQuery" placeholder="Buscar..."
|
||||
class="border border-gray-300 rounded w-full md:w-60 p-2 text-sm" @input="loadRegister()">
|
||||
|
||||
<!-- Contenedor para el botón o el ícono de carga -->
|
||||
<div x-show="isLoading" class="absolute right-2 top-2 flex items-center">
|
||||
<!-- SVG de cargando (puedes reemplazarlo con un botón si lo prefieres) -->
|
||||
<svg class="animate-spin h-5 w-5 text-gray-500" xmlns="http://www.w3.org/2000/svg" fill="none"
|
||||
viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4">
|
||||
</circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Botón Nuevo Módulo -->
|
||||
<div class="flex justify-end mb-4">
|
||||
<button class="bg-[#8eb02f] text-white px-4 py-2 rounded text-sm"
|
||||
x-on:click="addModal=true">Nuevo</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Agregar el GIF de carga -->
|
||||
<div x-show="loading" class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-50 justify-center items-center">
|
||||
<img src="../img/loading.gif" alt="Cargando..." class="w-16 h-16" />
|
||||
</div>
|
||||
<div class="overflow-x-auto max-w-full">
|
||||
<!-- Tabla de registros -->
|
||||
<table class=" table-auto w-full">
|
||||
<thead class="text-sm text-left py-4 border-b border-gray-300">
|
||||
<tr class="text-left font-semibold border-collapse">
|
||||
<th class="py-2 px-4 border-b w-52 " x-text=>Nombre</th>
|
||||
<th class="py-2 px-4 border-b w-52 ">Usuario</th>
|
||||
<th class="py-2 px-4 border-b">Estado</th>
|
||||
<th class="py-2 px-4 border-b">Email</th>
|
||||
<th class="py-2 px-4 border-b">Rol</th>
|
||||
<th class="py-2 px-4 border-b">Verificado</th>
|
||||
<th class="py-2 px-4 border-b w-32"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-gray-500 select-none text-sm ">
|
||||
<template x-for="user in users" :key="user.ID">
|
||||
<tr>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="user.name"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="user.nombre_usuario"></td>
|
||||
<td class="py-3 text-xs px-4 border-b">
|
||||
<button class="w-9 h-5 rounded-full transition-colors duration-200"
|
||||
:title="user.estado ? 'Activo' : 'Inactivo'"
|
||||
:class="user.estado ? 'bg-green-500' : 'bg-gray-300'"
|
||||
@click="toggleEstado(user.ID, user.estado)">
|
||||
<div class="w-5 h-5 bg-white rounded-full shadow-gray-400 shadow transform ring-0 transition-transform duration-300"
|
||||
:class="user.estado ? 'translate-x-full' : ''">
|
||||
</div>
|
||||
</button>
|
||||
</td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="user.email"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="user.Role.name"></td>
|
||||
<td class="py-3 text-xs px-4 border-b">
|
||||
<template x-if="user.email_verified == true">
|
||||
<div class="flex space-x-2">
|
||||
<div class="w-2 h-2 rounded-full mr-1 align-middle my-auto bg-green-500"></div>
|
||||
<span>Si</span>
|
||||
</div>
|
||||
<!-- Círculo verde -->
|
||||
|
||||
</template>
|
||||
<template x-if="!user.email_verified">
|
||||
<!-- Botón Enviar verificación -->
|
||||
<button @click="enviarVerificación(user.ID)" title="Reenviar validación">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" class="w-5 text-orange-400">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M6 12 3.269 3.125A59.769 59.769 0 0 1 21.485 12 59.768 59.768 0 0 1 3.27 20.875L5.999 12Zm0 0h7.5" />
|
||||
</svg>
|
||||
</button>
|
||||
</template>
|
||||
</td>
|
||||
<td class="py-3 text-xs px-4 border-b flex justify-between space-x-1">
|
||||
<!-- Botón de Ver -->
|
||||
<button @click="
|
||||
viewModal = true;
|
||||
Name = user.name;
|
||||
NombreUsuario = user.nombre_usuario;
|
||||
Estado = user.estado;
|
||||
Email = user.email;
|
||||
roleName = user.Role.name;
|
||||
" title="Ver">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" class="w-5 text-[#8eb02f]">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
<!-- Botón de Editar -->
|
||||
<button @click="
|
||||
editModal = true;
|
||||
Id = user.ID;
|
||||
Name = user.name;
|
||||
NombreUsuario = user.nombre_usuario;
|
||||
Estado = user.estado;
|
||||
Email = user.email;
|
||||
roleName = user.Role.ID;
|
||||
" title="Editar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" class="w-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10" />
|
||||
</svg>
|
||||
</button>
|
||||
<!-- Botón de Eliminar -->
|
||||
<button @click="showConfirmModal = true; deleteId = user.ID;" title="Eliminar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" class="w-5 text-red-500">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
|
||||
</svg>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<!-- Mensaje de Cargando -->
|
||||
<tr x-show="isLoading">
|
||||
<td colspan="6" class="py-2 px-4 border-b text-center">
|
||||
<div class="text-center flex justify-center">
|
||||
<svg class="animate-spin h-5 w-5 text-gray-500" xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor"
|
||||
stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z">
|
||||
</path>
|
||||
</svg>
|
||||
Cargando registros...
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<!-- Los botones de paginación se generarán aquí -->
|
||||
<div id="pagination" class="flex justify-left my-4 text-sm">
|
||||
</div>
|
||||
<!-- Mostrar conteo de registros -->
|
||||
<div id="recordCountDiv" class="text-sm text-gray-700 ml-4">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Ver -->
|
||||
<div x-cloak x-show="viewModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Ver registro</h2>
|
||||
<p class="font-semibold" x-text="Name"></p> <!-- Muestra el nombre -->
|
||||
<p class="mt-2" x-text="NombreUsuario"></p> <!-- Muestra el nombre de usuario -->
|
||||
<p class="mt-2 flex items-center">
|
||||
<!-- Punto de color basado en el estado -->
|
||||
<span :class="Estado ? 'bg-green-500' : 'bg-gray-400'"
|
||||
class="inline-block w-3 h-3 rounded-full mr-2"></span>
|
||||
<!-- Texto del estado (puedes personalizarlo) -->
|
||||
<span x-text="Estado ? 'Activo' : 'Inactivo'"></span>
|
||||
</p>
|
||||
<p class="mt-2" x-text="Email"></p> <!-- Muestra el correo -->
|
||||
<p class="mt-2" x-text="roleName"></p> <!-- Muestra el nombre del rol -->
|
||||
<button class="mt-4 bg-[#8eb02f] text-white px-4 py-2 rounded"
|
||||
x-on:click="viewModal = false">Cerrar</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Editar -->
|
||||
<div x-cloak x-show="editModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Editar registro</h2>
|
||||
<form @submit.prevent="submitEdit">
|
||||
<!-- Nombre -->
|
||||
<label class="block mb-2" for="editName">Nombre</label>
|
||||
<input type="text" id="editName" x-model="Name" placeholder="Nombre"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
|
||||
<!-- Nombre de usuario -->
|
||||
<label class="block mt-4 mb-2" for="editUsername">Nombre de usuario</label>
|
||||
<input id="editUsername" x-model="NombreUsuario" placeholder="Nombre de usuario"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
|
||||
<!-- Email -->
|
||||
<label class="block mt-4 mb-2" for="editEmail">Email</label>
|
||||
<input id="editEmail" x-model="Email" placeholder="Email"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
|
||||
<!-- Cambiar contraseña -->
|
||||
<div class="bg-[#8eb02f] text-white px-4 py-2 mt-2 rounded text-center cursor-pointer"
|
||||
x-on:click="showPasswordModal = true;" title="Cambiar contraseña">Cambiar contraseña</div>
|
||||
|
||||
|
||||
<!-- Rol -->
|
||||
<label class="block mt-4 mb-2" for="editRole">Rol</label>
|
||||
<select id="editRole" x-model="roleName" class="border border-gray-300 rounded w-full p-2" required>
|
||||
<option value="" disabled selected>Selecciona un rol</option> <!-- Opción predeterminada -->
|
||||
<template x-for="role in roles" :key="role.ID">
|
||||
<option :value="role.ID" x-text="role.name"></option>
|
||||
</template>
|
||||
</select>
|
||||
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar Cambios</button>
|
||||
<button type="button" class="bg-gray-600 text-white px-4 py-2 rounded"
|
||||
x-on:click="closeModal">Cancelar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Modal Añadir -->
|
||||
<div x-cloak x-show="addModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Agregar registro</h2>
|
||||
<form @submit.prevent="submitAdd">
|
||||
<label class="block mb-2" for="name">Nombre</label>
|
||||
<input type="text" id="name" x-model="newName" placeholder="Nombre"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
<label class="block mt-4 mb-2" for="nombre_usuario">Nombre de usuario</label>
|
||||
<input type="text" id="nombre_usuario" x-model="newNombreUsuario" placeholder="Nombre usuario"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
<label class="block mt-4 mb-2" for="editEmail">Email</label>
|
||||
<input id="editEmail" x-model="newEmail" placeholder="Email" type="email"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
|
||||
<label class="block mt-4 mb-2" for="editRole">Rol</label>
|
||||
<select id="editRole" x-model="newRole" class="border border-gray-300 rounded w-full p-2" required>
|
||||
<option value="" disabled selected>Selecciona un rol</option> <!-- Opción predeterminada -->
|
||||
<template x-for="role in roles" :key="role.ID">
|
||||
<option :value="role.ID" x-text="role.name"></option>
|
||||
</template>
|
||||
</select>
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar </button>
|
||||
<button type="button" class="bg-gray-600 text-white px-4 py-2 rounded"
|
||||
x-on:click="closeModal">Cancelar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Confirmar Eliminación -->
|
||||
<div x-cloak x-show="showConfirmModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-4">Confirmar Eliminación</h2>
|
||||
<p>¿Estás seguro de que deseas eliminar este registro?</p>
|
||||
<div class="mt-4 flex justify-end">
|
||||
<button class="bg-red-500 text-white px-4 py-2 rounded mr-2" @click="deleteItem()">Eliminar</button>
|
||||
<button @click="closeModal" class="bg-gray-600 text-white px-4 py-2 rounded">Cancelar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal cambiar contraseña -->
|
||||
<div x-cloak x-show="showPasswordModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<form @submit.prevent="changePass">
|
||||
<label class="block mb-2" for="password">Nueva contraseña</label>
|
||||
<input type="text" id="password" x-model="password" placeholder="Ingrese una contraseña"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar </button>
|
||||
<button type="button" class="bg-gray-600 text-white px-4 py-2 rounded"
|
||||
x-on:click="closeModalPassword">Cancelar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alpine.js Script -->
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('modals', () => ({
|
||||
addModal: false,
|
||||
editModal: false,
|
||||
viewModal: false,
|
||||
showConfirmModal: false,
|
||||
showPasswordModal: false,
|
||||
|
||||
newName: '',
|
||||
newEmail: '',
|
||||
newRole: '',
|
||||
newNombreUsuario: '',
|
||||
|
||||
Name: '',
|
||||
NombreUsuario: '',
|
||||
Estado: '',
|
||||
NewEstado: '',
|
||||
Email: '',
|
||||
roleName: '',
|
||||
|
||||
password: '',
|
||||
userId: '',
|
||||
|
||||
Id: null,
|
||||
deleteId: null,
|
||||
loading: false,
|
||||
totalRecords: 0, // Agregar esta línea
|
||||
isLoading: false,
|
||||
|
||||
roles: '',
|
||||
|
||||
init() {
|
||||
this.loadRegister();
|
||||
},
|
||||
//CARGAR registros
|
||||
searchQuery: '', // Agrega esta línea dentro del objeto Alpine
|
||||
|
||||
// Modifica la función loadRegister para incluir la búsqueda
|
||||
loadRegister(page = 1) {
|
||||
this.isLoading = true;
|
||||
//this.loading = true;
|
||||
const search = this.searchQuery ? `&search=${this.searchQuery}` : '';
|
||||
fetch(`/app/loadusers?page=${page}${search}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
this.totalRecords = data.total; // Establece el total de registros aquí
|
||||
this.users = data.Users; // Asignar
|
||||
this.roles = data.Roles;
|
||||
console.log(this.roles);
|
||||
|
||||
this.totalPages = data.totalPages; // Asignar total de páginas
|
||||
this.createPagination(this.totalPages, page);
|
||||
|
||||
if (data.Users.length != 0) {
|
||||
// Lógica de paginación
|
||||
const totalPages = Math.ceil(this.totalRecords / data.limit);
|
||||
this.createPagination(totalPages, page)
|
||||
}
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.isLoading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
},
|
||||
createPagination(totalPages, currentPage) {
|
||||
const paginationContainer = document.getElementById('pagination');
|
||||
paginationContainer.innerHTML = ''; // Limpiar la paginación actual
|
||||
|
||||
// Crear un contenedor para los botones de paginación
|
||||
const paginationButtonsContainer = document.createElement('div');
|
||||
paginationButtonsContainer.className = "md:flex mx-auto mb-2 md:justify-between items-center w-full"; // Alinear los botones
|
||||
|
||||
// Función para crear un botón
|
||||
const createButton = (text, isDisabled, onClick, additionalClasses = '') => {
|
||||
const button = document.createElement('button');
|
||||
button.textContent = text;
|
||||
button.disabled = isDisabled;
|
||||
button.className = `px-4 py-2 text-black bg-gray-200 ${additionalClasses} ${isDisabled ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-300'}`;
|
||||
if (!isDisabled) {
|
||||
button.onclick = onClick;
|
||||
}
|
||||
return button;
|
||||
};
|
||||
|
||||
// Botones de paginación
|
||||
const leftContainer = document.createElement('div');
|
||||
leftContainer.className = "md:flex text-center mb-2"; // Contenedor para los botones de paginación a la izquierda
|
||||
leftContainer.appendChild(createButton('Anterior', currentPage === 1, () => this.loadRegister(currentPage - 1), 'rounded-l-md'));
|
||||
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
const pageButton = createButton(i, false, () => this.loadRegister(i), `mx-1 ${i === currentPage ? 'bg-black text-gray-50' : 'bg-white text-black'} rounded-md`);
|
||||
leftContainer.appendChild(pageButton);
|
||||
}
|
||||
|
||||
leftContainer.appendChild(createButton('Siguiente', currentPage === totalPages, () => this.loadRegister(currentPage + 1), 'rounded-r-md'));
|
||||
|
||||
paginationButtonsContainer.appendChild(leftContainer);
|
||||
|
||||
// Agregar el conteo de registros a la derecha
|
||||
const recordCountDiv = document.createElement('div');
|
||||
const startRecord = (currentPage - 1) * 10 + 1; // Primer registro de la página actual
|
||||
const endRecord = Math.min(currentPage * 10, this.totalRecords); // Último registro mostrado
|
||||
recordCountDiv.className = "text-sm text-gray-700 text-center md:ml-auto"; // Sin margen para alineación a la izquierda
|
||||
recordCountDiv.innerHTML = `Mostrando ${startRecord} a ${endRecord} de ${this.totalRecords} registros`;
|
||||
|
||||
paginationButtonsContainer.appendChild(recordCountDiv);
|
||||
|
||||
// Agregar los botones de paginación al contenedor principal
|
||||
paginationContainer.appendChild(paginationButtonsContainer);
|
||||
},
|
||||
|
||||
//CERRAR MODALES
|
||||
closeModal() {
|
||||
this.addModal = false;
|
||||
this.editModal = false;
|
||||
this.viewModal = false;
|
||||
this.showConfirmModal = false;
|
||||
},
|
||||
|
||||
//CERRAR MODAL PASS
|
||||
closeModalPassword() {
|
||||
this.showPasswordModal = false;
|
||||
},
|
||||
//CREAR
|
||||
submitAdd() {
|
||||
this.loading = true;
|
||||
fetch('/app/users', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
name: this.newName,
|
||||
nombre_usuario: this.newNombreUsuario,
|
||||
email: this.newEmail,
|
||||
role_id: parseInt(this.newRole),
|
||||
estado: true,
|
||||
tipo: 'sistema'
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.newName = '';
|
||||
this.newNombreUsuario = '';
|
||||
this.newEmail = '';
|
||||
this.newRole = '';
|
||||
this.closeModal();
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
},
|
||||
//ACTUALIZAR
|
||||
submitEdit() {
|
||||
this.loading = true;
|
||||
fetch(`/app/users/${this.Id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
name: this.Name, // Usar 'Name' en lugar de 'First_name'
|
||||
nombre_usuario: this.NombreUsuario, // Usar 'Nombre_usuario' en lugar de 'Last_name'
|
||||
email: this.Email, // Usar 'Email'
|
||||
role_id: parseInt(this.roleName) // Usar 'roleName'
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
// Limpiar campos después de la actualización
|
||||
this.Name = '';
|
||||
this.NombreUsuario = '';
|
||||
this.Email = '';
|
||||
this.roleName = '';
|
||||
this.closeModal();
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
},
|
||||
|
||||
//ACTUALIZAR PASS
|
||||
changePass() {
|
||||
this.loading = true;
|
||||
fetch(`/app/password/${this.Id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
password: this.password,
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.password = '';
|
||||
this.closeModalPassword();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
},
|
||||
|
||||
//TOGGLE ESTADO
|
||||
toggleEstado($id, $estado) {
|
||||
this.Id = $id;
|
||||
this.NewEstado = $estado;
|
||||
this.loading = true;
|
||||
|
||||
if (this.NewEstado) {
|
||||
this.NewEstado = false;
|
||||
} else {
|
||||
this.NewEstado = true;
|
||||
}
|
||||
console.log(this.NewEstado);
|
||||
fetch(`/app/users/${this.Id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
estado: this.NewEstado
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
},
|
||||
|
||||
//ELIMINAR
|
||||
deleteItem() {
|
||||
this.loading = true;
|
||||
fetch(`/app/users/${this.deleteId}`, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
})
|
||||
.then(() => {
|
||||
this.closeModal();
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
},
|
||||
|
||||
enviarVerificación($id) {
|
||||
this.Id = $id;
|
||||
this.loading = true;
|
||||
fetch(`/app/verificacion/${this.Id}`, {
|
||||
method: 'GET',
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
})
|
||||
.then(() => {
|
||||
alert('Se ha enviado un correo de verificación');
|
||||
this.closeModal();
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
}
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
@@ -0,0 +1,615 @@
|
||||
<!-- Container Principal -->
|
||||
<div x-data="modals" @keydown.escape="closeModal" class="bg-white rounded-lg shadow">
|
||||
<div class="container mx-auto p-6 w-full ">
|
||||
<h1 class="text-2xl font-bold mb-4">Lista de Usuarios GAS</h1>
|
||||
<div class="justify-between w-full md:flex">
|
||||
<p class="mb-4 text-sm">Gestión de usuarios GAS.</p>
|
||||
<!-- Campo de Búsqueda -->
|
||||
<div class="mb-4 relative">
|
||||
<input type="text" x-model="searchQuery" placeholder="Buscar..."
|
||||
class="border border-gray-300 rounded w-full md:w-60 p-2 text-sm" @input="loadRegister()">
|
||||
|
||||
<!-- Contenedor para el botón o el ícono de carga -->
|
||||
<div x-show="isLoading" class="absolute right-2 top-2 flex items-center">
|
||||
<!-- SVG de cargando (puedes reemplazarlo con un botón si lo prefieres) -->
|
||||
<svg class="animate-spin h-5 w-5 text-gray-500" xmlns="http://www.w3.org/2000/svg" fill="none"
|
||||
viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4">
|
||||
</circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Botón Nuevo Módulo -->
|
||||
<div class="flex justify-end mb-4">
|
||||
<button class="bg-[#8eb02f] text-white px-4 py-2 rounded text-sm"
|
||||
x-on:click="addModal=true">Nuevo</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Agregar el GIF de carga -->
|
||||
<div x-show="loading" class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-50 justify-center items-center">
|
||||
<img src="../img/loading.gif" alt="Cargando..." class="w-16 h-16" />
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto max-w-full">
|
||||
<!-- Tabla de registros -->
|
||||
<table class=" table-auto w-full">
|
||||
<thead class="text-sm text-left py-4 border-b border-gray-300">
|
||||
<tr class="text-left font-semibold border-collapse">
|
||||
<th class="py-2 px-4 border-b w-52 ">Nombre</th>
|
||||
<th class="py-2 px-4 border-b">Codigo</th>
|
||||
<th class="py-2 px-4 border-b w-52">Medidor</th>
|
||||
<th class="py-2 px-4 border-b">Estado</th>
|
||||
<th class="py-2 px-4 border-b">Documento</th>
|
||||
<th class="py-2 px-4 border-b">Email</th>
|
||||
<th class="py-2 px-4 border-b">Celular</th>
|
||||
<th class="py-2 px-4 border-b">Acepto</th>
|
||||
<th class="py-2 px-4 border-b">Verificado</th>
|
||||
<th class="py-2 px-4 border-b w-32"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-gray-500 select-none text-sm ">
|
||||
<template x-for="user in users" :key="user.ID">
|
||||
<tr>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="user.name"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="user.nombre_usuario"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="user.numero_medidor || 'N/A'"></td>
|
||||
<td class="py-3 text-xs px-4 border-b">
|
||||
<button class="w-9 h-5 rounded-full transition-colors duration-200"
|
||||
:title="user.estado ? 'Activo' : 'Inactivo'"
|
||||
:class="user.estado ? 'bg-green-500' : 'bg-gray-300'"
|
||||
@click="toggleEstado(user.ID, user.estado)">
|
||||
<div class="w-5 h-5 bg-white rounded-full shadow-gray-400 shadow transform ring-0 transition-transform duration-300"
|
||||
:class="user.estado ? 'translate-x-full' : ''">
|
||||
</div>
|
||||
</button>
|
||||
</td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="user.documento"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="user.email"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="user.celular"></td>
|
||||
<td class="py-3 text-xs px-4 border-b ">
|
||||
<div class="flex j space-x-2 ">
|
||||
<!-- Punto de color basado en acepto_info -->
|
||||
<span :class="user.acepto_info ? 'bg-green-500' : 'bg-gray-400'"
|
||||
class=" w-2 h-2 rounded-full mr-1 align-middle my-auto"></span>
|
||||
<!-- Texto del estado -->
|
||||
<span x-text="user.acepto_info ? 'Si' : 'No'"></span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-3 text-xs px-4 border-b">
|
||||
<template x-if="user.email_verified == true">
|
||||
<div class="flex space-x-2">
|
||||
<div
|
||||
class="w-2 h-2 rounded-full mr-1 align-middle my-auto bg-green-500"></div ><span>Si</span>
|
||||
</div>
|
||||
<!-- Círculo verde -->
|
||||
|
||||
</template>
|
||||
<template x-if="!user.email_verified">
|
||||
<!-- Botón Enviar verificación -->
|
||||
<button @click="enviarVerificación(user.ID)" title="Reenviar validación">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" class="w-5 text-orange-400">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M6 12 3.269 3.125A59.769 59.769 0 0 1 21.485 12 59.768 59.768 0 0 1 3.27 20.875L5.999 12Zm0 0h7.5" />
|
||||
</svg>
|
||||
</button>
|
||||
</template>
|
||||
</td>
|
||||
<td class="py-3 text-xs px-4 border-b flex justify-between space-x-1">
|
||||
<!-- Botón de Ver -->
|
||||
<button @click="
|
||||
viewModal = true;
|
||||
Name = user.name;
|
||||
NombreUsuario = user.nombre_usuario;
|
||||
NumeroMedidor = user.numero_medidor;
|
||||
Estado = user.estado;
|
||||
Email = user.email;
|
||||
Celular = user.celular;
|
||||
" title="Ver">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" class="w-5 text-[#8eb02f]">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
<!-- Botón de Editar -->
|
||||
<button @click="
|
||||
editModal = true;
|
||||
Id = user.ID;
|
||||
Name = user.name;
|
||||
NombreUsuario = user.nombre_usuario;
|
||||
NumeroMedidor = user.numero_medidor;
|
||||
Estado = user.estado;
|
||||
Email = user.email;
|
||||
Celular = user.celular;
|
||||
" title="Editar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" class="w-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10" />
|
||||
</svg>
|
||||
</button>
|
||||
<!-- Botón de Eliminar -->
|
||||
<button @click="showConfirmModal = true; deleteId = user.ID;" title="Eliminar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" class="w-5 text-red-500">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
|
||||
</svg>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<!-- Mensaje de Cargando -->
|
||||
<tr x-show="isLoading">
|
||||
<td colspan="6" class="py-2 px-4 border-b text-center">
|
||||
<div class="text-center flex justify-center">
|
||||
<svg class="animate-spin h-5 w-5 text-gray-500" xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor"
|
||||
stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z">
|
||||
</path>
|
||||
</svg>
|
||||
Cargando registros...
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<!-- Los botones de paginación se generarán aquí -->
|
||||
<div id="pagination" class="flex justify-left my-4 text-sm">
|
||||
</div>
|
||||
<!-- Mostrar conteo de registros -->
|
||||
<div id="recordCountDiv" class="text-sm text-gray-700 ml-4">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Ver -->
|
||||
<div x-cloak x-show="viewModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Ver registro</h2>
|
||||
<p class="font-semibold" x-text="Name"></p> <!-- Muestra el nombre -->
|
||||
<p class="mt-2" x-text="NombreUsuario"></p> <!-- Muestra el nombre de usuario -->
|
||||
<p class="mt-2 flex items-center">
|
||||
<!-- Punto de color basado en el estado -->
|
||||
<span :class="Estado ? 'bg-green-500' : 'bg-gray-400'"
|
||||
class="inline-block w-3 h-3 rounded-full mr-2"></span>
|
||||
<!-- Texto del estado (puedes personalizarlo) -->
|
||||
<span x-text="Estado ? 'Activo' : 'Inactivo'"></span>
|
||||
</p>
|
||||
<p class="mt-2" x-text="Email"></p> <!-- Muestra el correo -->
|
||||
<p class="mt-2" x-text="Celular"></p> <!-- Muestra el nombre del rol -->
|
||||
<button class="mt-4 bg-[#8eb02f] text-white px-4 py-2 rounded"
|
||||
x-on:click="viewModal = false">Cerrar</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Editar -->
|
||||
<div x-cloak x-show="editModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Editar registro</h2>
|
||||
<form @submit.prevent="submitEdit">
|
||||
<!-- Nombre -->
|
||||
<label class="block mb-2" for="editName">Nombre</label>
|
||||
<input type="text" id="editName" x-model="Name" placeholder="Nombre"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
|
||||
<!-- Nombre de usuario -->
|
||||
<label class="block mt-4 mb-2" for="editUsername">Codigo</label>
|
||||
<input id="editUsername" x-model="NombreUsuario" placeholder="Codigo"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
|
||||
|
||||
<label class="block mt-4 mb-2" for="editNumeroMedidor">Medidor</label>
|
||||
<input id="editNumeroMedidor" x-model="NumeroMedidor" placeholder="Medidor"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
|
||||
|
||||
<!-- Email -->
|
||||
<label class="block mt-4 mb-2" for="editEmail">Email</label>
|
||||
<input id="editEmail" x-model="Email" placeholder="Email"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
|
||||
<!-- Cambiar contraseña -->
|
||||
<div class="bg-[#8eb02f] text-white px-4 py-2 mt-2 rounded text-center cursor-pointer"
|
||||
x-on:click="showPasswordModal = true;" title="Cambiar contraseña">Cambiar contraseña</div>
|
||||
|
||||
|
||||
<!-- Celular -->
|
||||
<label class="block mt-4 mb-2" for="editCelular">Celular</label>
|
||||
<input id="editCelular" x-model="Celular" placeholder="tel"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar Cambios</button>
|
||||
<button type="button" class="bg-gray-600 text-white px-4 py-2 rounded"
|
||||
x-on:click="closeModal">Cancelar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Modal Añadir -->
|
||||
<div x-cloak x-show="addModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-2">Agregar registro</h2>
|
||||
<form @submit.prevent="submitAdd">
|
||||
<label class="block mb-2" for="name">Nombre</label>
|
||||
<input type="text" id="name" x-model="newName" placeholder="Nombre"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
<label class="block mt-4 mb-2" for="nombre_usuario">Codigo</label>
|
||||
<input type="text" id="nombre_usuario" x-model="newNombreUsuario" placeholder="Codigo"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
<label class="block mt-4 mb-2" for="numero_medidor">Medidor</label>
|
||||
<input type="text" id="numero_medidor" x-model="newNumeroMedidor" placeholder="Medidor"
|
||||
class="border border-gray-300 rounded w-full p-2">
|
||||
<label class="block mt-4 mb-2" for="documento">Documento</label>
|
||||
<input type="text" id="documento" x-model="newDocumento" placeholder="Documento"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
<label class="block mt-4 mb-2" for="editEmail">Email</label>
|
||||
<input id="editEmail" x-model="newEmail" placeholder="Email" type="email"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
<label class="block mt-4 mb-2" for="editCelular">Celular</label>
|
||||
<input id="editCelular" x-model="newCelular" placeholder="Celular" type="tel"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar </button>
|
||||
<button type="button" class="bg-gray-600 text-white px-4 py-2 rounded"
|
||||
x-on:click="closeModal">Cancelar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Confirmar Eliminación -->
|
||||
<div x-cloak x-show="showConfirmModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<h2 class="text-xl font-bold mb-4">Confirmar Eliminación</h2>
|
||||
<p>¿Estás seguro de que deseas eliminar este registro?</p>
|
||||
<div class="mt-4 flex justify-end">
|
||||
<button class="bg-red-500 text-white px-4 py-2 rounded mr-2" @click="deleteItem()">Eliminar</button>
|
||||
<button @click="closeModal" class="bg-gray-600 text-white px-4 py-2 rounded">Cancelar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal cambiar contraseña -->
|
||||
<div x-cloak x-show="showPasswordModal" x-transition
|
||||
class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-40 justify-center items-center text-sm">
|
||||
<div class="bg-white p-6 rounded shadow-lg max-w-sm w-full overflow-y-auto max-h-full">
|
||||
<form @submit.prevent="changePass">
|
||||
<label class="block mb-2" for="password">Nueva contraseña</label>
|
||||
<input type="text" id="password" x-model="password" placeholder="Ingrese una contraseña"
|
||||
class="border border-gray-300 rounded w-full p-2" required>
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar </button>
|
||||
<button type="button" class="bg-gray-600 text-white px-4 py-2 rounded"
|
||||
x-on:click="closeModalPassword">Cancelar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alpine.js Script -->
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('modals', () => ({
|
||||
addModal: false,
|
||||
editModal: false,
|
||||
viewModal: false,
|
||||
showConfirmModal: false,
|
||||
showPasswordModal: false,
|
||||
|
||||
users : [],
|
||||
|
||||
newName: '',
|
||||
newEmail: '',
|
||||
newNombreUsuario: '',
|
||||
newCelular: '',
|
||||
|
||||
Name: '',
|
||||
NombreUsuario: '',
|
||||
NumeroMedidor: '',
|
||||
Estado: '',
|
||||
NewEstado: '',
|
||||
Email: '',
|
||||
Celular: '',
|
||||
|
||||
newDocumento: '',
|
||||
newNumeroMedidor: '',
|
||||
newCelular: '',
|
||||
|
||||
password: '',
|
||||
userId: '',
|
||||
|
||||
Id: null,
|
||||
deleteId: null,
|
||||
loading: false,
|
||||
totalRecords: 0, // Agregar esta línea
|
||||
isLoading: false,
|
||||
|
||||
roles: '',
|
||||
|
||||
init() {
|
||||
this.loadRegister();
|
||||
},
|
||||
//CARGAR registros
|
||||
searchQuery: '', // Agrega esta línea dentro del objeto Alpine
|
||||
|
||||
// Modifica la función loadRegister para incluir la búsqueda
|
||||
loadRegister(page = 1) {
|
||||
this.isLoading = true;
|
||||
//this.loading = true;
|
||||
const search = this.searchQuery ? `&search=${this.searchQuery}` : '';
|
||||
fetch(`/app/loadusers_gas?page=${page}${search}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log(data);
|
||||
|
||||
this.totalRecords = data.total; // Establece el total de registros aquí
|
||||
this.users = data.Users; // Asignar
|
||||
this.roles = data.Roles;
|
||||
|
||||
this.totalPages = data.totalPages; // Asignar total de páginas
|
||||
this.createPagination(this.totalPages, page);
|
||||
|
||||
if (data.Users.length != 0) {
|
||||
// Lógica de paginación
|
||||
const totalPages = Math.ceil(this.totalRecords / data.limit);
|
||||
this.createPagination(totalPages, page)
|
||||
}
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.isLoading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
},
|
||||
createPagination(totalPages, currentPage) {
|
||||
const paginationContainer = document.getElementById('pagination');
|
||||
paginationContainer.innerHTML = ''; // Limpiar la paginación actual
|
||||
|
||||
// Crear un contenedor para los botones de paginación
|
||||
const paginationButtonsContainer = document.createElement('div');
|
||||
paginationButtonsContainer.className = "md:flex mx-auto mb-2 md:justify-between items-center w-full"; // Alinear los botones
|
||||
|
||||
// Función para crear un botón
|
||||
const createButton = (text, isDisabled, onClick, additionalClasses = '') => {
|
||||
const button = document.createElement('button');
|
||||
button.textContent = text;
|
||||
button.disabled = isDisabled;
|
||||
button.className = `px-4 py-2 text-black bg-gray-200 ${additionalClasses} ${isDisabled ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-300'}`;
|
||||
if (!isDisabled) {
|
||||
button.onclick = onClick;
|
||||
}
|
||||
return button;
|
||||
};
|
||||
|
||||
// Botones de paginación
|
||||
const leftContainer = document.createElement('div');
|
||||
leftContainer.className = "md:flex text-center mb-2"; // Contenedor para los botones de paginación a la izquierda
|
||||
leftContainer.appendChild(createButton('Anterior', currentPage === 1, () => this.loadRegister(currentPage - 1), 'rounded-l-md'));
|
||||
|
||||
// Rango de páginas para mostrar
|
||||
const maxVisibleButtons = 5; // Número máximo de botones a mostrar
|
||||
const halfRange = Math.floor(maxVisibleButtons / 2);
|
||||
let startPage = Math.max(1, currentPage - halfRange);
|
||||
let endPage = Math.min(totalPages, currentPage + halfRange);
|
||||
|
||||
// Ajustar si estamos al inicio o al final del rango de páginas
|
||||
if (currentPage <= halfRange) {
|
||||
endPage = Math.min(totalPages, maxVisibleButtons);
|
||||
}
|
||||
if (currentPage + halfRange > totalPages) {
|
||||
startPage = Math.max(1, totalPages - maxVisibleButtons + 1);
|
||||
}
|
||||
|
||||
// Crear botones de paginación
|
||||
for (let i = startPage; i <= endPage; i++) {
|
||||
const pageButton = createButton(
|
||||
i,
|
||||
false,
|
||||
() => this.loadRegister(i),
|
||||
`mx-1 ${i === currentPage ? 'bg-black text-gray-50' : 'bg-white text-black'} rounded-md`
|
||||
);
|
||||
leftContainer.appendChild(pageButton);
|
||||
}
|
||||
|
||||
leftContainer.appendChild(createButton('Siguiente', currentPage === totalPages, () => this.loadRegister(currentPage + 1), 'rounded-r-md'));
|
||||
|
||||
paginationButtonsContainer.appendChild(leftContainer);
|
||||
|
||||
// Agregar el conteo de registros a la derecha
|
||||
const recordCountDiv = document.createElement('div');
|
||||
const startRecord = (currentPage - 1) * 10 + 1; // Primer registro de la página actual
|
||||
const endRecord = Math.min(currentPage * 10, this.totalRecords); // Último registro mostrado
|
||||
recordCountDiv.className = "text-sm text-gray-700 text-center md:ml-auto"; // Sin margen para alineación a la izquierda
|
||||
recordCountDiv.innerHTML = `Mostrando ${startRecord} a ${endRecord} de ${this.totalRecords} registros`;
|
||||
|
||||
paginationButtonsContainer.appendChild(recordCountDiv);
|
||||
|
||||
// Agregar los botones de paginación al contenedor principal
|
||||
paginationContainer.appendChild(paginationButtonsContainer);
|
||||
},
|
||||
|
||||
//CERRAR MODALES
|
||||
closeModal() {
|
||||
this.addModal = false;
|
||||
this.editModal = false;
|
||||
this.viewModal = false;
|
||||
this.showConfirmModal = false;
|
||||
},
|
||||
|
||||
//CERRAR MODAL PASS
|
||||
closeModalPassword() {
|
||||
this.showPasswordModal = false;
|
||||
},
|
||||
//CREAR
|
||||
submitAdd() {
|
||||
this.loading = true;
|
||||
fetch('/users_gas', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
nombre_usuario: this.newNombreUsuario,
|
||||
numero_medidor: this.newNumeroMedidor,
|
||||
documento: this.newDocumento,
|
||||
name: this.newName,
|
||||
email: this.newEmail,
|
||||
celular: this.newCelular,
|
||||
estado: true,
|
||||
tipo: 'gas'
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.newName = '';
|
||||
this.newDocumento = '';
|
||||
this.newNombreUsuario = '';
|
||||
this.newNumeroMedidor = '';
|
||||
this.newEmail = '';
|
||||
this.newCelular = '';
|
||||
this.closeModal();
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
},
|
||||
//ACTUALIZAR
|
||||
submitEdit() {
|
||||
this.loading = true;
|
||||
fetch(`/app/users_gas/${this.Id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
name: this.Name,
|
||||
nombre_usuario: this.NombreUsuario,
|
||||
numero_medidor: this.NumeroMedidor,
|
||||
email: this.Email,
|
||||
celular: this.Celular
|
||||
})
|
||||
})
|
||||
// .then(response => response.json())
|
||||
.then(() => {
|
||||
// Limpiar campos después de la actualización
|
||||
this.Name = '';
|
||||
this.NombreUsuario = '';
|
||||
this.NumeroMedidor = '';
|
||||
this.Email = '';
|
||||
this.Celular = '';
|
||||
this.closeModal();
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
},
|
||||
|
||||
//ACTUALIZAR PASS
|
||||
changePass() {
|
||||
this.loading = true;
|
||||
fetch(`/app/password/${this.Id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
password: this.password,
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.password = '';
|
||||
this.closeModalPassword();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
},
|
||||
|
||||
//TOGGLE ESTADO
|
||||
toggleEstado($id, $estado) {
|
||||
this.Id = $id;
|
||||
this.NewEstado = $estado;
|
||||
this.loading = true;
|
||||
|
||||
if (this.NewEstado) {
|
||||
this.NewEstado = false;
|
||||
} else {
|
||||
this.NewEstado = true;
|
||||
}
|
||||
console.log(this.NewEstado);
|
||||
fetch(`/app/users/${this.Id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
estado: this.NewEstado
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
},
|
||||
|
||||
//ELIMINAR
|
||||
deleteItem() {
|
||||
this.loading = true;
|
||||
fetch(`/app/users/${this.deleteId}`, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
})
|
||||
.then(() => {
|
||||
this.closeModal();
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
},
|
||||
|
||||
enviarVerificación($id) {
|
||||
this.Id = $id;
|
||||
this.loading = true;
|
||||
fetch(`/app/verificacion/${this.Id}`, {
|
||||
method: 'GET',
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
})
|
||||
.then(() => {
|
||||
alert('Se ha enviado un correo de verificación');
|
||||
this.closeModal();
|
||||
this.loadRegister();
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false; // Ocultar el GIF de carga
|
||||
});
|
||||
}
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
@@ -0,0 +1,123 @@
|
||||
<!-- Contenedor Principal -->
|
||||
<div x-data="videoinstitucionalForm" class="bg-white mx-3 my-3 rounded-lg p-6">
|
||||
<h1 class="text-2xl font-bold mb-4">Gestión de Video Institucional</h1>
|
||||
<p class="mb-4 text-sm">Actualiza el archivo del video institucional.</p>
|
||||
|
||||
<div x-show="loading" class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-50 justify-center items-center">
|
||||
<img src="../img/loading.gif" alt="Cargando..." class="w-16 h-16" />
|
||||
</div>
|
||||
|
||||
<!-- Contenedor del Formulario -->
|
||||
<div class="bg-white p-6 rounded-lg border shadow max-w-2xl mx-auto">
|
||||
<!-- Alerta -->
|
||||
<div x-show="showAlert" class="mb-4 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" role="alert">
|
||||
<span x-text="alertMessage"></span>
|
||||
</div>
|
||||
<form @submit.prevent="submitUpdate">
|
||||
<!-- Campo para el archivo Video Institucional -->
|
||||
<div class="mb-6">
|
||||
<label class="block mb-2" for="video_institucional">Archivo Video Institucional</label>
|
||||
<input type="file" id="video_institucional" @change="handleFileChange($event, 'video_institucional')" class="border border-gray-300 rounded w-full p-2" accept=".mp4" />
|
||||
<p x-show="video_institucional_path" class="mt-2 text-sm text-gray-600">
|
||||
Archivo actual: <a :href="`${window.location.origin}/${video_institucional_path}`" target="_blank" class="text-blue-500 underline" x-text="video_institucional_path"></a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Botón de Guardar -->
|
||||
<div class="mt-6 text-right">
|
||||
<button type="submit" class="bg-[#8eb02f] text-white px-4 py-2 rounded">Guardar Cambios</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Alpine.js Script -->
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('videoinstitucionalForm', () => ({
|
||||
// Campos relacionados con el archivo
|
||||
video_institucional: null,
|
||||
video_institucional_path: '',
|
||||
loading: false,
|
||||
id_dato : 0,
|
||||
showAlert: false,
|
||||
alertMessage: '',
|
||||
|
||||
init() {
|
||||
this.loadData();
|
||||
},
|
||||
|
||||
loadData() {
|
||||
this.loading = true;
|
||||
fetch('/loadvideoinstitucional') // Cambia esta URL al endpoint correspondiente
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data && data.video_institucional) {
|
||||
this.id_dato = data.ID;
|
||||
this.video_institucional_path = data.video_institucional; // Ruta del archivo actual
|
||||
}
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
handleFileChange(event) {
|
||||
const file = event.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
// Validar que sea MP4
|
||||
const allowedTypes = ['video/mp4'];
|
||||
if(!allowedTypes.includes(file.type)) {
|
||||
this.showAlert = true;
|
||||
this.alertMessage = 'El archivo debe ser un video MP4.';
|
||||
this.video_institucional = null;
|
||||
event.target.value = ''; // Reset input
|
||||
return;
|
||||
}
|
||||
|
||||
// Validar tamaño del archivo (ej: máx 50MB)
|
||||
const maxSize = 50 * 1024 * 1024; // 50MB
|
||||
if(file.size > maxSize) {
|
||||
this.showAlert = true;
|
||||
this.alertMessage = 'El archivo no debe exceder los 50MB.';
|
||||
this.video_institucional = null;
|
||||
event.target.value = ''; // Reset input
|
||||
return;
|
||||
}
|
||||
|
||||
// Si pasa las validaciones, asignar el archivo y cerrar alerta
|
||||
this.showAlert = false;
|
||||
this.alertMessage = '';
|
||||
this.video_institucional = file;
|
||||
},
|
||||
|
||||
submitUpdate() {
|
||||
this.loading = true;
|
||||
const formData = new FormData();
|
||||
// Validar si hay un archivo nuevo
|
||||
if (this.video_institucional) {
|
||||
formData.append('video_institucional', this.video_institucional);
|
||||
} else if (this.video_institucional_path) {
|
||||
// Si no hay archivo nuevo, enviar el valor actual
|
||||
formData.append('video_institucional', this.video_institucional_path);
|
||||
}
|
||||
|
||||
fetch('/app/videoinstitucional/'+this.id_dato, { // Cambia esta URL al endpoint correspondiente
|
||||
method: 'PUT',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.loadData(); // Recargar datos después de la actualización
|
||||
})
|
||||
.catch(error => console.error('Error:', error))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
Reference in New Issue
Block a user