Kaynağa Gözat

Make it better

Агаев Даниэл Сейранович 3 yıl önce
işleme
9e067e354a
10 değiştirilmiş dosya ile 681 ekleme ve 0 silme
  1. 15 0
      .htaccess
  2. 8 0
      .idea/.gitignore
  3. 221 0
      css/main.css
  4. 33 0
      index.html
  5. 105 0
      js/components/LoginForm.js
  6. 77 0
      js/components/User.js
  7. 82 0
      js/components/Users.js
  8. 24 0
      js/helper.js
  9. 78 0
      js/libs/router.js
  10. 38 0
      js/main.js

+ 15 - 0
.htaccess

@@ -0,0 +1,15 @@
+RewriteEngine On
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteCond %{REQUEST_FILENAME} !-d
+#RewriteCond %{REQUEST_URI} !^/js/
+#RewriteCond %{REQUEST_URI} !^/css/
+RewriteRule ^(.*)$ index/index.html
+
+#401 Авторизация не выполнена
+ErrorDocument 401 http://localhost/
+#403 Доступ запрещен
+ErrorDocument 403 http://localhost/
+#404 Страница не найдена
+ErrorDocument 404 http://localhost/
+#500 Внутренняя ошибка сервера
+ErrorDocument 500 http://localhost/

+ 8 - 0
.idea/.gitignore

@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/

+ 221 - 0
css/main.css

@@ -0,0 +1,221 @@
+main {
+    display: flex;
+    width: 100%;
+    gap: 1rem;
+}
+
+#app {
+    display: flex;
+    flex: 90%;
+    flex-direction: column;
+    gap: 1rem;
+    overflow: hidden;
+    padding: 10vh;
+}
+
+.category-name {
+    font-family: sans-serif;
+
+    text-align: center;
+    font-size: 40px;
+}
+
+.card-category-2 ul, .card-category-3 ul, .card-category-4 ul, .card-category-5 ul .card-category-6 ul {
+    padding: 0;
+}
+
+.card-category-2 ul li, .card-category-3 ul li, .card-category-4 ul li, .card-category-5 ul li, .card-category-6 ul li {
+    list-style-type: none;
+    display: inline-block;
+    vertical-align: top;
+}
+
+.card-category-2 ul li, .card-category-3 ul li {
+    margin: 10px 5px;
+}
+
+.card-category-1, .card-category-2, .card-category-3, .card-category-4, .card-category-5, .card-category-6 {
+    font-family: sans-serif;
+    margin-bottom: 45px;
+    text-align: center;
+}
+
+.card-category-1 div, .card-category-2 div {
+    display: inline-block;
+}
+
+.card-category-1 > div, .card-category-2 > div:not(:last-child) {
+    margin: 10px 5px;
+    text-align: left;
+}
+
+/* Basic Card */
+.basic-card {
+    width: 100vw;
+    position: relative;
+    overflow: hidden;
+    padding: 1vh;
+}
+
+.basic-card .card-content {
+    padding: 10px;
+}
+
+.basic-card .card-title {
+    font-size: 15px;
+    font-family: 'Open Sans', sans-serif;
+}
+
+.basic-card .card-text {
+    line-height: 1.6;
+}
+
+.basic-card .card-link {
+    padding: 15px;
+    width: -webkit-fill-available;
+}
+
+.basic-card .card-link a {
+    text-decoration: none;
+    position: relative;
+    padding: 10px 0px;
+}
+
+.basic-card .card-link a:after {
+    top: 30px;
+    content: "";
+    display: block;
+    height: 2px;
+    left: 50%;
+    position: absolute;
+    width: 0;
+
+
+}
+
+.basic-card .card-link a:hover:after {
+    width: 100%;
+    left: 0;
+}
+
+.basic-card-aqua {
+    position: relative;
+    overflow: hidden;
+}
+
+.basic-card-aqua::before {
+    background-image: linear-gradient(to bottom right, #0080ff, #0080ff);
+    content: "";
+    position: absolute;
+    width: 90vh;
+    height: 90vh;
+
+    z-index: -1;
+}
+
+.basic-card-aqua .card-content, .basic-card .card-link a {
+    color: #fff;
+}
+
+.basic-card-aqua .card-link {
+    border-top: 1px solid #82c1bb;
+}
+
+.basic-card-aqua .card-link a:after {
+    background: #fff;
+}
+
+.basic-card-lips {
+    background-image: linear-gradient(to bottom right, #ec407b, #ff7d94);
+}
+
+.basic-card-lips .card-content {
+    color: #fff;
+}
+
+.basic-card-lips .card-link {
+    border-top: 1px solid #ff97ba;
+}
+
+.basic-card-lips .card-link a:after {
+    background: #fff;
+}
+
+.basic-card-light {
+    border: 1px solid #eee;
+}
+
+.basic-card-light .card-title, .basic-card-light .card-link a {
+    color: #636363;
+}
+
+.basic-card-light .card-text {
+    color: #7b7b7b;
+}
+
+.basic-card-light .card-link {
+    border-top: 1px solid #eee;
+}
+
+.basic-card-light .card-link a:after {
+    background: #636363;
+}
+
+.basic-card-dark {
+    background-image: linear-gradient(to bottom right, #252525, #4a4a4a);
+}
+
+.basic-card-dark .card-title, .basic-card-dark .card-link a {
+    color: #eee;
+}
+
+.basic-card-dark .card-text {
+    color: #dcdcdcdd;
+}
+
+.basic-card-dark .card-link {
+    border-top: 1px solid #636363;
+}
+
+.basic-card-dark .card-link a:after {
+    background: #eee;
+}
+
+shop-admin-users {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 1vh
+}
+
+.buttons {
+    position: relative;
+
+}
+
+router-link {
+    cursor: pointer;
+    font-family: Bahnschrift, sans-serif;
+    color: #252525;
+    padding: 1vh;
+    width: 100px;
+    transition: .2s;
+    text-align: center;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+
+router-link:hover {
+    background: #0080ff;
+    color: #eeeeee;
+}
+
+#header {
+    display: flex;
+}
+
+.message {
+    padding: 1vh;
+    color: white;
+    margin-bottom: 2vh;
+}

+ 33 - 0
index.html

@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>qwe</title>
+    <link rel="stylesheet" href="css/main.css">
+</head>
+<body>
+
+<script defer src="js/libs/router.js" type="module"></script>
+<script defer src="js/main.js" type="module"></script>
+
+<main>
+
+    <div id="app">
+
+        <div id="header">
+            <router-link to="/login">Вход</router-link>
+            <router-link to="/users">Сотрудники</router-link>
+            <router-link to="/sheets">Смены</router-link>
+        </div>
+        <hr>
+
+        <router-view></router-view>
+
+
+    </div>
+
+
+</main>
+
+</body>
+</html>

+ 105 - 0
js/components/LoginForm.js

@@ -0,0 +1,105 @@
+import {f} from "../helper.js";
+import {dEvent} from "../main.js";
+
+export default class LoginForm extends HTMLElement {
+    constructor() {
+        super();
+        this.user = null;
+        this.data = {
+            login: "",
+            password: "",
+        }
+        this.bindEvents();
+    }
+
+    connectedCallback() {
+        if (!this.user) {
+            this.render(this.getTemplateLogin())
+        }
+    }
+
+    render(template) {
+        this.innerHTML = template;
+        this.attachModel();
+    }
+
+    getTemplateLogin() {
+        return `
+        <h3>Вход</h3>
+        <div class="message"></div>
+        <label>Логин: <input type="text" data-model="login"></label>
+        <label>Пароль: <input type="text" data-model="password"></label>
+        <button data-click="login">Войти</button>
+        `
+    }
+    getTemplateOut() {
+        return `
+        <h3>Вы вошли как ${this.user.login}</h3>
+        <div class="message"></div>
+        <button data-click="logout">Выход</button>
+        `
+    }
+
+    bindEvents() {
+
+        console.log("BIND EVENT - " + this.constructor.name)
+
+        document.addEventListener("user-login",(e) => {
+            this.user = e.detail;
+            this.render(this.getTemplateOut())
+        })
+
+        document.addEventListener("user-logout", (e)=>{
+            this.render(this.getTemplateLogin())
+        })
+    }
+
+    attachModel() {
+        this.querySelectorAll("input")
+            .forEach(el=>el.addEventListener("input",e =>this.inputText(e)))
+        this.querySelector('button')
+            .addEventListener('click', e => this.clickButton(e));
+    }
+
+    inputText(e) {
+        if (this.data[e.target.dataset.model] !== undefined) {
+            this.data[e.target.dataset.model] = e.target.value;
+            console.log(this.data);
+        }
+    }
+
+    clickButton(e) {
+        this[e.target.dataset.click]();
+    }
+
+    async login() {
+        if (!this.data.login || !this.data.password) return;
+        let res = await f('login', 'post', null, this.data);
+
+        console.log(res);
+        localStorage.setItem("user", JSON.stringify(res));
+
+        if (res.error) {
+            this.querySelector('.message').innerHTML = 'Не правильный логин или пароль';
+            this.querySelector('.message').innerHTML+=`<style>.message {background:crimson}</style>`
+            return;
+        }
+
+        dEvent('user-login', {login: this.data.login, api_token: res.data.user_token, role: "admin"});
+    }
+
+    async logout() {
+
+        console.log(this.user)
+
+        let res = await f('logout', 'get', this.user.api_token, this.data);
+        console.log(res)
+
+        if (!res.message) {
+            dEvent('user-logout');
+        }
+
+    }
+
+
+}

+ 77 - 0
js/components/User.js

@@ -0,0 +1,77 @@
+import {f, dEvent} from "../main.js";
+
+export default class User extends HTMLElement {
+    constructor() {
+        super();
+        this.users = [];
+        this.data = {
+            name: "",
+            login: "",
+            status: "",
+            group: "",
+            id: ""
+        }
+        this.user = null;
+        this.bindEvents();
+    }
+
+    connectedCallback() {
+        this.id = this.dataset.id;
+        this.name = this.dataset.name;
+        this.status = this.dataset.status;
+        this.group = this.dataset.group;
+        this.render(this.getTemplateUser());
+        this.attachModel();
+    }
+
+    render(template) {
+        this.innerHTML = template;
+    }
+
+    bindEvents() {
+        console.log("BIND EVENT - " + this.constructor.name)
+        document.addEventListener('user-login', (e) => {
+            this.user = e.detail;
+            this.render(this.getTemplateUser());
+        });
+        document.addEventListener('user-out', () => {
+            this.render(null);
+        });
+    }
+
+
+    attachModel() {
+        this.querySelector('button')
+            .addEventListener('click', e => this.clickButton(e));
+    }
+
+    getTemplateUser() {
+        return `
+           
+           <div class="basic-card basic-card-aqua">
+                <div class="card-content">
+                    <span class="card-title"><h3>ID:${this.id}</h3></span>
+                    <p class="card-text">
+                       Name: ${this.name}, Status: ${this.status}, Group: ${this.group}
+                       
+                       <div class="buttons">
+                       <button data-click="see">Просмотр</button>   
+                       <button  style="background: firebrick; color: white">Уволить</button>     
+                        </div>
+
+                    </p>
+                </div>
+            
+                </div>
+            `;
+    }
+
+    clickButton(e) {
+        this[e.target.dataset.click]();
+    }
+
+    see(id) {
+        console.log(id)
+    }
+
+}

+ 82 - 0
js/components/Users.js

@@ -0,0 +1,82 @@
+import {f, dEvent} from "../main.js";
+
+export default class Users extends HTMLElement {
+
+    constructor() {
+        super();
+        this.users = [];
+        this.data = {};
+        this.user = null;
+        this.renderer = false;
+        this.bindEvents();
+    }
+
+    connectedCallback() {
+        if (!this.renderer) {
+            this.render(this.getTemplateUsers());
+        }
+    }
+
+    render(template) {
+        this.renderer = true;
+        this.innerHTML = template;
+        this.users.forEach(e => {
+            this.append(e);
+        })
+    }
+
+    getTemplateUsers() {
+        return `
+         <h3>Пользователи</h3>
+            <div class="message"></div> 
+        `
+    }
+
+   bindEvents() {
+
+       console.log("BIND EVENT - " + this.constructor.name)
+
+        document.addEventListener('user-login', (e) => {
+            this.user = e.detail;
+            this.loadUsers();
+            this.render(this.getTemplateUsers());
+        });
+
+        document.addEventListener('user-out', () => {
+            this.render(null);
+        });
+    }
+
+    clear() {
+        this.users = [];
+        this.innerHTML = '';
+    }
+
+    addUser(user) {
+        this.users.push(this.createUser(user));
+    }
+
+    createUser(data) {
+
+        let user = document.createElement('shop-admin-user');
+        user.dataset.id = data.id;
+        user.dataset.name = data.name;
+        user.dataset.status = data.status;
+        user.dataset.group = data.group;
+
+        return user;
+    }
+
+    async loadUsers() {
+        let list = (await f('user', 'get', this.user.api_token)).data;
+        // console.log(list)
+
+        list.forEach(el => this.addUser(el));
+
+        this.users.forEach(e => {
+            this.append(e);
+        })
+
+    }
+
+}

+ 24 - 0
js/helper.js

@@ -0,0 +1,24 @@
+
+let host = "https://jurapro.bhuser.ru/api-cafe";
+
+let f = async (url, method="get",token=false, data=[]) => {
+    let options = {
+        method: method.toUpperCase(),
+        headers: {
+            "Content-type": "application/json"
+        }
+    }
+
+    if (token) {
+        options.headers["Authorization"] = `Bearer ${token}`
+    }
+
+    if (["post", "patch"].includes(method)) {
+
+        options.body = JSON.stringify(data);
+    }
+
+    return await fetch(`${host}/${url}`, options).then(res=>res.json())
+}
+
+export {f, host};

+ 78 - 0
js/libs/router.js

@@ -0,0 +1,78 @@
+
+export default class Router {
+
+    constructor(settings) {
+        this.routes = settings.routes;
+
+        for (let i =0;i<this.routes.length;i++) {
+            if (!this.routes[i].element) {
+                const elementName = 'template-' + this.routes[i].component.name.toLocaleLowerCase();
+                if (!customElements.get(elementName)) customElements.define(elementName, this.routes[i].component);
+                this.routes[i].element = document.createElement(elementName);
+
+            }
+        }
+
+        this.link = settings.link || "router-link";
+        this.view = settings.view || "router-view";
+        this.home = window.location.toString();
+        customElements.define(this.link, RouterLink);
+        customElements.define(this.view, RouterView);
+        this.bindEvents();
+    }
+
+    bindEvents() {
+        document.addEventListener("router-click",(e)=> {
+            let route = this.routes.find(route=> route.path === e.detail);
+            if (!route) return;
+
+            window.history.pushState({page: 2},String(e.path), this.home+String(e.detail));
+
+            // if (!route.element) {
+            //     const elementName = 'template-' + route.component.name.toLocaleLowerCase();
+            //     if (!customElements.get(elementName)) customElements.define(elementName, route.component);
+            //
+            //
+            //     route.element = document.createElement(elementName);
+            //
+            // }
+            document.querySelector(this.view).dispatchEvent(new CustomEvent(
+                'router-view', {
+                    detail: route.element
+                }
+            ));
+        })
+    }
+}
+
+class RouterView extends HTMLElement {
+    connectedCallback() {
+        this.bindEvents();
+    }
+
+    bindEvents() {
+        this.addEventListener('router-view', (e) => {
+            this.innerHTML = '';
+            this.append(e.detail);
+        });
+    }
+}
+
+class RouterLink extends HTMLElement {
+
+    constructor() {
+        super();
+        this.bindEvents();
+    }
+
+    bindEvents() {
+        this.addEventListener('click', () => {
+            document.dispatchEvent(new CustomEvent(
+                'router-click', {
+                    detail: this.getAttribute('to')
+                }
+            ));
+        });
+    }
+
+}

+ 38 - 0
js/main.js

@@ -0,0 +1,38 @@
+import {f} from "./helper.js";
+import LoginForm from "./components/LoginForm.js";
+import Router from "./libs/router.js";
+import Users from "./components/Users.js";
+import User from "./components/User.js";
+
+const dEvent = (event, detail) => {
+    document.dispatchEvent(new CustomEvent(
+        event, {
+            detail: detail
+        }
+    ))
+}
+
+class App {
+    constructor() {
+        this.defineElements();
+    }
+
+    defineElements() {
+        customElements.define("shop-admin-user", User);
+    }
+
+}
+
+const routes = [
+    {path: "/login", component: LoginForm, name: 'Вход'},
+    {path: "/users", component: Users, name: 'Работники'},
+]
+
+
+
+const router = new Router(
+    {routes})
+
+new App();
+
+export {f, dEvent};