mirror of
https://github.com/sergeyyarkov/digital-store.git
synced 2026-10-12 10:49:07 +03:00
deleted src
This commit is contained in:
parent
01b66f81f0
commit
b7b67214ab
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +0,0 @@
|
|||||||
node_modules
|
|
||||||
package-lock.json
|
|
||||||
.env
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
import { Component } from '../core/component';
|
|
||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
|
|
||||||
export class AdministratorComponent extends Component {
|
|
||||||
constructor(id) {
|
|
||||||
super(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
setElems() {
|
|
||||||
this.$el.querySelector('form').addEventListener('submit', this.request.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
async request(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
try {
|
|
||||||
const data = {
|
|
||||||
id: e.target.elements.id.value,
|
|
||||||
name: e.target.elements.name.value,
|
|
||||||
email: e.target.elements.email.value,
|
|
||||||
oldPass: e.target.elements.oldPass.value,
|
|
||||||
newPass: e.target.elements.newPass.value
|
|
||||||
}
|
|
||||||
const response = await axios.post('/control-panel/administrators/update', data);
|
|
||||||
alert(response.data);
|
|
||||||
document.location.reload(true);
|
|
||||||
} catch (error) {
|
|
||||||
alert('Невозможно выполнить запрос.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
import { Component } from "../core/component";
|
|
||||||
import { apiService } from "../services/api.service";
|
|
||||||
import { renderCategories } from "../templates/categories.template";
|
|
||||||
import { renderIcons } from "../templates/icons.template";
|
|
||||||
|
|
||||||
export class CategoriesComponent extends Component {
|
|
||||||
constructor(id) {
|
|
||||||
super(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
setElems() {
|
|
||||||
// селекты в которых рендерится контент
|
|
||||||
this.$editSelect = this.$el.querySelector('#editCategory_select'); // редактирование категории
|
|
||||||
this.$dellSelect = this.$el.querySelector('#deleteCategory_select'); // удаление категории
|
|
||||||
this.$iconsSelect = this.$el.querySelector('#icons_select'); // выбор иконки
|
|
||||||
|
|
||||||
// обработка форм
|
|
||||||
this.$addForm = this.$el.querySelector('#addCategory');
|
|
||||||
this.$dellForm = this.$el.querySelector('#deleteCategory');
|
|
||||||
|
|
||||||
// добавим ивенты на наши формы
|
|
||||||
this.$addForm.addEventListener('submit', this.addCategory.bind(this));
|
|
||||||
this.$dellForm.addEventListener('submit', this.deleteCategory.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
async init() {
|
|
||||||
const categories = await apiService.getCategories(),
|
|
||||||
icons = await apiService.getIcons();
|
|
||||||
|
|
||||||
this.$editSelect.insertAdjacentHTML('beforeend', renderCategories(categories));
|
|
||||||
this.$dellSelect.insertAdjacentHTML('beforeend', renderCategories(categories));
|
|
||||||
this.$iconsSelect.insertAdjacentHTML('beforeend', renderIcons(icons));
|
|
||||||
M.FormSelect.init(document.querySelectorAll('select'));
|
|
||||||
}
|
|
||||||
|
|
||||||
async addCategory(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
const categories = await apiService.getCategories(),
|
|
||||||
title = this.$addForm.elements[0].value.toLowerCase().trim(),
|
|
||||||
index = categories.map((category) => {return category.title}).indexOf(title);
|
|
||||||
|
|
||||||
index != -1 ? alert('Такая категория уже существует, придумайте другое название.') : this.$addForm.submit();
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteCategory(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
const categories = await apiService.getCategories(),
|
|
||||||
title = this.$dellForm.elements[0].value.toLowerCase().trim(),
|
|
||||||
index = categories.map((category) => {return category.title}).indexOf(title);
|
|
||||||
|
|
||||||
index != -1 ? this.$dellForm.submit() : alert('Выберите категорию для удаления.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
import { Component } from '../core/component';
|
|
||||||
|
|
||||||
export class ContentComponent extends Component {
|
|
||||||
constructor(id) {
|
|
||||||
super(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
setElems() {
|
|
||||||
this.$info = this.$el.querySelector('#info');
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
M.textareaAutoResize(this.$info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
import { Component } from "../core/component";
|
|
||||||
import { apiService } from "../services/api.service";
|
|
||||||
import { renderBuyers } from "../templates/buyers.template";
|
|
||||||
|
|
||||||
export class DashboardComponent extends Component {
|
|
||||||
constructor(id, {pagination}, {search}) {
|
|
||||||
super(id);
|
|
||||||
this.pagination = pagination;
|
|
||||||
this.search = search;
|
|
||||||
}
|
|
||||||
|
|
||||||
async init() {
|
|
||||||
const buyers = await apiService.getBuyers();
|
|
||||||
this.$table = this.$el.querySelector('table tbody');
|
|
||||||
this.search.initialize(this.$table, this.getBuyersByBillId);
|
|
||||||
this.pagination.initialize(buyers.length, this.$table, this.getBuyersByPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBuyersByBillId(bill_id) {
|
|
||||||
const buyer = await apiService.getBillId(bill_id);
|
|
||||||
return renderBuyers(buyer);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBuyersByPage(page) {
|
|
||||||
const buyers = await apiService.getBuyersOffset(page);
|
|
||||||
return renderBuyers(buyers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
import { Component } from "../core/component";
|
|
||||||
import { apiService } from "../services/api.service";
|
|
||||||
import { renderIcons } from "../templates/icons.template";
|
|
||||||
|
|
||||||
export class IconsComponent extends Component {
|
|
||||||
constructor(id) {
|
|
||||||
super(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
setElems() {
|
|
||||||
this.$icons = this.$el.querySelector('#selectIcons');
|
|
||||||
this.$delete = this.$el.querySelector('#dellIcon');
|
|
||||||
this.$delete.addEventListener('submit', this.dellIcon.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
async init() {
|
|
||||||
const icons = await apiService.getIcons();
|
|
||||||
this.$icons.insertAdjacentHTML('beforeend', renderIcons(icons));
|
|
||||||
M.FormSelect.init(this.$icons);
|
|
||||||
}
|
|
||||||
|
|
||||||
async dellIcon(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
const icons = await apiService.getIcons(),
|
|
||||||
currIcon = e.target.elements[0].value,
|
|
||||||
index = icons.indexOf(currIcon);
|
|
||||||
|
|
||||||
index != -1 ? e.target.submit() : alert('Выберите иконку для удаления.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
import { Component } from "../core/component";
|
|
||||||
import { apiService } from "../services/api.service";
|
|
||||||
import { renderItems } from "../templates/items.template";
|
|
||||||
import { renderCategories } from "../templates/categories.template";
|
|
||||||
|
|
||||||
export class ItemsComponent extends Component {
|
|
||||||
constructor(id, {pagination}, {search}) {
|
|
||||||
super(id);
|
|
||||||
this.pagination = pagination;
|
|
||||||
this.search = search;
|
|
||||||
}
|
|
||||||
|
|
||||||
setElems() {
|
|
||||||
this.$categories = this.$el.querySelector('#selectCategories');
|
|
||||||
}
|
|
||||||
|
|
||||||
async init() {
|
|
||||||
const items = await apiService.getItems(),
|
|
||||||
categories = await apiService.getCategories();
|
|
||||||
|
|
||||||
this.$table = this.$el.querySelector('table tbody');
|
|
||||||
this.search.initialize(this.$table, this.getItemsByText);
|
|
||||||
this.pagination.initialize(items.length, this.$table, this.getItemsByPage);
|
|
||||||
this.$categories.insertAdjacentHTML('beforeend', renderCategories(categories));
|
|
||||||
M.FormSelect.init(this.$categories);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getItemsByText(text) {
|
|
||||||
const items = await apiService.getItemsQuery(text),
|
|
||||||
categories = await apiService.getCategories(),
|
|
||||||
data = await apiService.getItemsData();
|
|
||||||
return renderItems(items, categories, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getItemsByPage(page) {
|
|
||||||
const items = await apiService.getItemsOffset(page),
|
|
||||||
categories = await apiService.getCategories(),
|
|
||||||
data = await apiService.getItemsData();
|
|
||||||
return renderItems(items, categories, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
import { Component } from "../core/component";
|
|
||||||
|
|
||||||
export class LoaderComponent extends Component {
|
|
||||||
constructor(id) {
|
|
||||||
super(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,92 +0,0 @@
|
|||||||
import { Component } from "../core/component";
|
|
||||||
|
|
||||||
export class PaginationComponent extends Component {
|
|
||||||
constructor(id, {loader}) {
|
|
||||||
super(id);
|
|
||||||
this.loader = loader;
|
|
||||||
}
|
|
||||||
|
|
||||||
// вставляем кнопки со страницами и назначаем ивент
|
|
||||||
initialize(pages, insertTo, request) {
|
|
||||||
this.insertButtons(pages);
|
|
||||||
this.$pages = Array.from(this.$el.querySelectorAll('li'));
|
|
||||||
this.$el.onclick = (e) => this.buttonHandler(e, insertTo, request);
|
|
||||||
this.moveTo(1, insertTo, request); // показываем первую страницу
|
|
||||||
this.$el.querySelector('li').nextElementSibling.classList.add('active');
|
|
||||||
}
|
|
||||||
|
|
||||||
removeActive() {
|
|
||||||
this.$pages.forEach(li => li.classList.remove('active'));
|
|
||||||
}
|
|
||||||
|
|
||||||
setActive(li, value) {
|
|
||||||
li.forEach(li => {const page = parseInt(li.querySelector('a').dataset.move);page === value ? li.classList.add('active') : false;});
|
|
||||||
}
|
|
||||||
|
|
||||||
buttonHandler(e, insertTo, request) {
|
|
||||||
e.preventDefault();
|
|
||||||
if (e.target.dataset.move) {
|
|
||||||
const page = parseInt(e.target.dataset.move),
|
|
||||||
target = e.target.parentNode;
|
|
||||||
|
|
||||||
this.removeActive();
|
|
||||||
target.classList.add('active');
|
|
||||||
this.moveTo(page, insertTo, request);
|
|
||||||
} else if (e.target.tagName.toLowerCase() === 'i') {
|
|
||||||
const moveType = e.target.parentNode.dataset.type,
|
|
||||||
page = parseInt(this.$el.dataset.page);
|
|
||||||
|
|
||||||
moveType === 'prev' ? this.movePrev(page, this.$pages, insertTo, request) : this.moveNext(page, this.$pages, insertTo, request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
movePrev(page, li, insertTo, request) {
|
|
||||||
if (page === 1) return 0; else {
|
|
||||||
--page;
|
|
||||||
this.removeActive();
|
|
||||||
this.setActive(li, page);
|
|
||||||
this.moveTo(page, insertTo, request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// выполняем запрос на сервер и выводим на данные
|
|
||||||
async moveTo(page, insertTo, request) {
|
|
||||||
this.loader.show();
|
|
||||||
insertTo.innerHTML = '';
|
|
||||||
const response = await request(page);
|
|
||||||
if (response != '') {
|
|
||||||
this.$el.setAttribute('data-page', page);
|
|
||||||
insertTo.insertAdjacentHTML('afterbegin', response);
|
|
||||||
} else {
|
|
||||||
insertTo.innerHTML = 'Данных нету.';
|
|
||||||
}
|
|
||||||
this.loader.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
moveNext(page, li, insertTo, request) {
|
|
||||||
const length = this.$pages.length - 2;
|
|
||||||
if (page === length) return 0; else {
|
|
||||||
++page;
|
|
||||||
this.removeActive();
|
|
||||||
this.setActive(li, page);
|
|
||||||
this.moveTo(page, insertTo, request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
insertButtons(pages) {
|
|
||||||
const count = Math.ceil(pages / 5);
|
|
||||||
let html = '';
|
|
||||||
|
|
||||||
// назад
|
|
||||||
html += '<li><a class="disabled" href="#" data-type="prev"><i class="material-icons">chevron_left</i></a></li>';
|
|
||||||
|
|
||||||
// все страницы
|
|
||||||
for (let i = 1; i <= count; i++) {
|
|
||||||
html += `<li><a href="#" data-move="${i}">${i}</a></li>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// вперед
|
|
||||||
html += '<li><a class="disabled" href="#" data-type="next"><i class="material-icons">chevron_right</i></a></li>';
|
|
||||||
this.$el.insertAdjacentHTML('afterbegin', html);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
import { Component } from "../core/component";
|
|
||||||
|
|
||||||
export class SearchComponent extends Component {
|
|
||||||
constructor(id, {loader}) {
|
|
||||||
super(id);
|
|
||||||
this.loader = loader;
|
|
||||||
}
|
|
||||||
|
|
||||||
initialize(insertTo, request) {
|
|
||||||
this.$el.onchange = (e) => {
|
|
||||||
this.search(e, insertTo, request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async search(e, insertTo, request) {
|
|
||||||
try {
|
|
||||||
insertTo.innerHTML = '';
|
|
||||||
this.loader.show();
|
|
||||||
const query = e.target.value.trim(),
|
|
||||||
items = await request(query);
|
|
||||||
|
|
||||||
items != '' ? insertTo.insertAdjacentHTML('afterbegin', items) : insertTo.innerHTML = `По запросу "${query}" ничего не найдено...`;
|
|
||||||
e.target.value = '';
|
|
||||||
this.loader.hide();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Произошла ошибка.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
const M = require('../frameworks/materialize.min');
|
|
||||||
export class MaterializeConfig {
|
|
||||||
constructor() {
|
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
|
||||||
// Closest полифилл для ie11
|
|
||||||
(function() {
|
|
||||||
if (!Element.prototype.closest) {
|
|
||||||
Element.prototype.closest = function(css) {
|
|
||||||
var node = this;
|
|
||||||
|
|
||||||
while (node) {
|
|
||||||
if (node.matches(css)) return node;
|
|
||||||
else node = node.parentElement;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
// Matches полифилл для ie11
|
|
||||||
(function() {
|
|
||||||
if (!Element.prototype.matches) {
|
|
||||||
Element.prototype.matches = Element.prototype.matchesSelector ||
|
|
||||||
Element.prototype.webkitMatchesSelector ||
|
|
||||||
Element.prototype.mozMatchesSelector ||
|
|
||||||
Element.prototype.msMatchesSelector;
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
|
|
||||||
M.Sidenav.init(document.querySelectorAll('.sidenav'));
|
|
||||||
M.Collapsible.init(document.querySelectorAll('.collapsible'));
|
|
||||||
M.Modal.init(document.querySelectorAll('.modal'));
|
|
||||||
document.querySelector('#type') ? M.textareaAutoResize(document.querySelector('#type')) : false
|
|
||||||
M.updateTextFields();
|
|
||||||
|
|
||||||
// окраска li по нажатию
|
|
||||||
if (document.querySelector('#currentPage')) {
|
|
||||||
const currentPage = document.querySelector('#currentPage').dataset.current;
|
|
||||||
const pages = Array.from(document.querySelectorAll('.collapsible li'));
|
|
||||||
pages.forEach(function (page) {
|
|
||||||
if (page.dataset.page) {
|
|
||||||
if (currentPage === page.dataset.page) {
|
|
||||||
document.querySelector('#home').classList.remove('active');
|
|
||||||
page.classList.add('active');
|
|
||||||
const collapse = M.Collapsible.getInstance(page.closest('.collapsible'));
|
|
||||||
collapse.open();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
export class Component {
|
|
||||||
constructor(id) {
|
|
||||||
this.$el = document.getElementById(id);
|
|
||||||
this.$el ? this.setElems() : false;
|
|
||||||
this.$el ? this.init() : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {}
|
|
||||||
|
|
||||||
setElems() {}
|
|
||||||
|
|
||||||
onShow() {}
|
|
||||||
|
|
||||||
onHide() {}
|
|
||||||
|
|
||||||
hide() {
|
|
||||||
this.$el ? this.$el.classList.add('hide') : false;
|
|
||||||
this.onHide();
|
|
||||||
}
|
|
||||||
|
|
||||||
show() {
|
|
||||||
this.$el ? this.$el.classList.remove('hide') : false;
|
|
||||||
this.onShow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
export class Modal {
|
|
||||||
constructor(id, open, close) {
|
|
||||||
this.$el = document.getElementById(id);
|
|
||||||
this.open = document.getElementById(open);
|
|
||||||
this.close = document.getElementById(close);
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
if (this.open) {
|
|
||||||
this.setElems();
|
|
||||||
this.open.addEventListener('click', this.show.bind(this));
|
|
||||||
this.close.addEventListener('click', this.hide.bind(this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
show(e) {
|
|
||||||
this.$el.classList.remove('hide');
|
|
||||||
document.body.style.overflowY = 'hidden';
|
|
||||||
this.openHandler(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
hide() {
|
|
||||||
this.$el.classList.add('hide');
|
|
||||||
document.body.style.overflowY = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
openHandler() {}
|
|
||||||
|
|
||||||
setElems() {}
|
|
||||||
}
|
|
||||||
6
src/admin/frameworks/materialize.min.js
vendored
6
src/admin/frameworks/materialize.min.js
vendored
File diff suppressed because one or more lines are too long
@ -1,32 +0,0 @@
|
|||||||
import { MaterializeConfig } from "./config/materialize.config.js";
|
|
||||||
import { CategoriesComponent } from "./components/categories.component.js";
|
|
||||||
import { ItemsComponent } from "./components/items.component.js";
|
|
||||||
import { LoaderComponent } from "./components/loader.component.js";
|
|
||||||
import { PaginationComponent } from "./components/pagination.component.js";
|
|
||||||
import { SearchComponent } from "./components/search.component.js";
|
|
||||||
import { IconsComponent } from "./components/icons.component.js";
|
|
||||||
import { ItemEditModal } from "./modals/item-edit.modal.js";
|
|
||||||
import { ItemDeleteModal } from "./modals/item-delete.modal.js";
|
|
||||||
import { CategoryEditModal } from "./modals/category-edit.modal";
|
|
||||||
import { ContentComponent } from "./components/content.component.js";
|
|
||||||
import { AdministratorComponent } from "./components/administrator.component.js";
|
|
||||||
import { DashboardComponent } from "./components/dashboard.component.js";
|
|
||||||
|
|
||||||
// Components
|
|
||||||
const loader = new LoaderComponent('loader');
|
|
||||||
const pagination = new PaginationComponent('pagination', {loader});
|
|
||||||
const search = new SearchComponent('search', {loader});
|
|
||||||
const categories = new CategoriesComponent('categories');
|
|
||||||
const icons = new IconsComponent('icons');
|
|
||||||
const items = new ItemsComponent('items', {pagination}, {search});
|
|
||||||
const dashboards = new DashboardComponent('dashboard', {pagination}, {search});
|
|
||||||
const content = new ContentComponent('content');
|
|
||||||
const administrator = new AdministratorComponent('administrator');
|
|
||||||
|
|
||||||
// Modals
|
|
||||||
const itemEdit = new ItemEditModal('editItemModal', 'edit', 'editItemClose');
|
|
||||||
const itemDelete = new ItemDeleteModal('deleteItemModal', 'edit', 'deleteItemClose');
|
|
||||||
const categoryEdit = new CategoryEditModal('editCategoryModal', 'editCategory_select', 'editCategoryClose');
|
|
||||||
|
|
||||||
const materialize = new MaterializeConfig();
|
|
||||||
console.log('Control-Panel v1.0.0');
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
import { Modal } from "../core/modal";
|
|
||||||
import { apiService } from "../services/api.service";
|
|
||||||
import { renderIcons } from "../templates/icons.template";
|
|
||||||
|
|
||||||
export class CategoryEditModal extends Modal {
|
|
||||||
constructor(id, open, close) {
|
|
||||||
super(id, open, close);
|
|
||||||
}
|
|
||||||
|
|
||||||
// перепишем метод для перевода ивента open в событие onchange
|
|
||||||
init() {
|
|
||||||
if (this.open) {
|
|
||||||
this.setElems();
|
|
||||||
this.open.addEventListener('change', this.show.bind(this));
|
|
||||||
this.close.addEventListener('click', this.hide.bind(this));
|
|
||||||
this.$el.querySelector('form').addEventListener('submit', this.updateCategory.bind(this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setElems() {
|
|
||||||
this.$id = this.$el.querySelector('.id');
|
|
||||||
this.$originalTitle = this.$el.querySelector('.originalTitle');
|
|
||||||
this.$title = this.$el.querySelector('.title');
|
|
||||||
this.$type = this.$el.querySelector('.type');
|
|
||||||
this.$format = this.$el.querySelector('.format');
|
|
||||||
this.$img = this.$el.querySelector('.img');
|
|
||||||
}
|
|
||||||
|
|
||||||
async openHandler(e) {
|
|
||||||
const data = JSON.parse(e.target.value),
|
|
||||||
icons = await apiService.getIcons();
|
|
||||||
|
|
||||||
this.$img.innerHTML = `<option value='${data.img}' selected>Оставить прежнюю</option>`;
|
|
||||||
this.$id.value = data.id;
|
|
||||||
this.$originalTitle.value = data.title[0].toUpperCase() + data.title.slice(1);
|
|
||||||
this.$title.value = data.title[0].toUpperCase() + data.title.slice(1);
|
|
||||||
this.$type.value = data.type;
|
|
||||||
this.$format.value = data.format;
|
|
||||||
this.$img.insertAdjacentHTML('beforeend', renderIcons(icons));
|
|
||||||
M.FormSelect.init(this.$img);
|
|
||||||
M.textareaAutoResize(this.$type);
|
|
||||||
M.updateTextFields();
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateCategory(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
const form = this.$el.querySelector('form');
|
|
||||||
const categories = await apiService.getCategories();
|
|
||||||
const id = form.elements[0].value.toLowerCase().trim();
|
|
||||||
const index = categories.map((category) => {return category._id}).indexOf(id);
|
|
||||||
index != -1 ? form.submit() : alert('Категории с таким ID не существует.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
import { Modal } from "../core/modal";
|
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
export class ItemDeleteModal extends Modal {
|
|
||||||
constructor(id, open, close) {
|
|
||||||
super(id, open, close);
|
|
||||||
}
|
|
||||||
|
|
||||||
show(e) {
|
|
||||||
if (e.target.id === 'deleteItem') {
|
|
||||||
this.$el.classList.remove('hide');
|
|
||||||
document.body.style.overflowY = 'hidden';
|
|
||||||
this.openHandler(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setElems() {
|
|
||||||
this.$content = this.$el.querySelector('.modal-content__form p');
|
|
||||||
this.$button = this.$el.querySelector('.delete-item');
|
|
||||||
}
|
|
||||||
|
|
||||||
openHandler(e) {
|
|
||||||
const data = JSON.parse(e.target.parentNode.parentNode.dataset.info);
|
|
||||||
this.$content.innerHTML = `Вы действительно хотите удалить товар "${data.title}"? Находящиеся в нем аккаунты будут удалены.`;
|
|
||||||
this.$button.onclick = this.deleteHandler.bind(this, data.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteHandler(id) {
|
|
||||||
try {
|
|
||||||
this.$button.classList.add('hide');
|
|
||||||
this.$content.innerHTML = '<div class="progress"><div class="indeterminate"></div></div>'
|
|
||||||
await axios.post('/control-panel/items/delete', {id});
|
|
||||||
alert('Товар был успешно удален.');
|
|
||||||
document.location.reload(true);
|
|
||||||
} catch (error) {
|
|
||||||
alert('Невозможно выполнить запрос.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
import { Modal } from "../core/modal";
|
|
||||||
import { apiService } from "../services/api.service";
|
|
||||||
import { renderCategories } from "../templates/categories.template";
|
|
||||||
|
|
||||||
export class ItemEditModal extends Modal {
|
|
||||||
constructor(id, open, close) {
|
|
||||||
super(id, open, close);
|
|
||||||
}
|
|
||||||
|
|
||||||
show(e) {
|
|
||||||
if (e.target.id === 'editItem') {
|
|
||||||
this.$el.classList.remove('hide');
|
|
||||||
document.body.style.overflowY = 'hidden';
|
|
||||||
this.openHandler(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setElems() {
|
|
||||||
this.$id = this.$el.querySelector('.id');
|
|
||||||
this.$title = this.$el.querySelector('.title');
|
|
||||||
this.$price = this.$el.querySelector('.price');
|
|
||||||
this.$description = this.$el.querySelector('.description');
|
|
||||||
this.$category = this.$el.querySelector('.category');
|
|
||||||
this.$data = this.$el.querySelector('.data');
|
|
||||||
}
|
|
||||||
|
|
||||||
async openHandler(e) {
|
|
||||||
const data = JSON.parse(e.target.parentNode.parentNode.dataset.info),
|
|
||||||
categories = await apiService.getCategories();
|
|
||||||
|
|
||||||
this.$category.innerHTML = `<option value='{"title": "${data.category}"}' selected>Оставить прежнюю</option>`;
|
|
||||||
this.$id.value = data.id;
|
|
||||||
this.$title.value = data.title;
|
|
||||||
this.$price.value = data.price;
|
|
||||||
this.$description.value = data.description;
|
|
||||||
this.$category.insertAdjacentHTML('beforeend', renderCategories(categories));
|
|
||||||
this.$data.value = data.data;
|
|
||||||
M.FormSelect.init(this.$category);
|
|
||||||
M.textareaAutoResize(this.$description);
|
|
||||||
M.textareaAutoResize(this.$data);
|
|
||||||
M.updateTextFields();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,124 +0,0 @@
|
|||||||
import axios from "axios";
|
|
||||||
|
|
||||||
class ApiService {
|
|
||||||
constructor(baseUrl) {
|
|
||||||
this.url = baseUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getCategory(category) {
|
|
||||||
try {
|
|
||||||
const request = `${this.url}/api/category/${encodeURIComponent(category)}`;
|
|
||||||
return useRequest(request);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getCategories() {
|
|
||||||
try {
|
|
||||||
const request = `${this.url}/api/categories`;
|
|
||||||
return useRequest(request);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getItems(sorting) {
|
|
||||||
try {
|
|
||||||
if (sorting) {
|
|
||||||
const request = `${this.url}/api/items?sorting=${sorting}`;
|
|
||||||
return useRequest(request);
|
|
||||||
} else {
|
|
||||||
const request = `${this.url}/api/items`;
|
|
||||||
return useRequest(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getItemsOffset(page) {
|
|
||||||
try {
|
|
||||||
const request = `${this.url}/api/items/page/${page}`;
|
|
||||||
return useRequest(request);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getItemsQuery(text) {
|
|
||||||
try {
|
|
||||||
const request = `${this.url}/api/items?q=${text}`;
|
|
||||||
return useRequest(request);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getItemsOne(category, sorting) {
|
|
||||||
try {
|
|
||||||
if (sorting) {
|
|
||||||
const request = `${this.url}/api/items/${encodeURIComponent(category.toLowerCase())}?sorting=${sorting}`;
|
|
||||||
return useRequest(request);
|
|
||||||
} else {
|
|
||||||
const request = `${this.url}/api/items/${encodeURIComponent(category.toLowerCase())}`;
|
|
||||||
return useRequest(request);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getItemsData() {
|
|
||||||
try {
|
|
||||||
const request = `${this.url}/api/items/data`;
|
|
||||||
return useRequest(request);
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBuyers() {
|
|
||||||
try {
|
|
||||||
const request = `${this.url}/api/buyers`;
|
|
||||||
return useRequest(request);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBuyersOffset(page) {
|
|
||||||
try {
|
|
||||||
const request = `${this.url}/api/buyers/page/${page}`;
|
|
||||||
return useRequest(request);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBillId(bill_id) {
|
|
||||||
try {
|
|
||||||
const request = `${this.url}/api/buyers/${bill_id}`;
|
|
||||||
return useRequest(request);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getIcons() {
|
|
||||||
try {
|
|
||||||
const request = `${this.url}/api/icons`;
|
|
||||||
return useRequest(request);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function useRequest(request) {
|
|
||||||
const response = await axios.get(request);
|
|
||||||
return await JSON.parse(response.request.response);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const apiService = new ApiService('http://localhost:3000');
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
export function renderBuyers(buyers) {
|
|
||||||
let html = '';
|
|
||||||
buyers.forEach(buyer => {
|
|
||||||
html += `<tr><td>${buyer.email}</td><td>${buyer.method[0].toUpperCase() + buyer.method.slice(1)}</td><td>${new Date(buyer.date).toLocaleDateString()}</td><td>${buyer.amount} ₽</td></tr>`;
|
|
||||||
});
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
export function renderCategories(categories) {
|
|
||||||
let html = '';
|
|
||||||
categories.forEach(category => {
|
|
||||||
html += `<option value='{"id": "${category._id}", "title": "${category.title}", "img": "${category.img}", "type": "${category.type}", "format": "${category.format}"}' data-icon="../img/service-icons/${category.img}">${category.title[0].toUpperCase() + category.title.slice(1)}</option>`;
|
|
||||||
});
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
export function renderIcons(icons) {
|
|
||||||
let html = '';
|
|
||||||
icons.forEach(icon => {
|
|
||||||
html += `<option value='${icon}' data-icon="../img/service-icons/${icon}">${icon}</option>`;
|
|
||||||
});
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
export function renderItems(items, categories, info) {
|
|
||||||
let html = '';
|
|
||||||
|
|
||||||
if (!items.error) {
|
|
||||||
categories.forEach(category => {
|
|
||||||
items.forEach((item, i) => {
|
|
||||||
if (item.category.toLowerCase() === category.title.toLowerCase()) html += `<tr data-info='{"id": "${item._id}", "title": "${item.title}", "category": "${item.category}", "price": "${item.price}", "description": "${item.description}", "data": "${info[i].data}"}'><td><img src="../img/service-icons/${category.img}" alt="alt"></td><td>${item.title}</td><td>${item.category[0].toUpperCase() + item.category.slice(1)}</td><td>${new Date(item.date).toLocaleDateString()}</td><td>${item.count}</td><td>${item.price} ₽</td><td><button id="deleteItem" class="btn red">Удалить</button><button id="editItem" class="btn orange">Изменить</button></td></tr>`
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else html += 'Данных нету.';
|
|
||||||
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
import { Component } from "../core/component";
|
|
||||||
|
|
||||||
export class BreadcrumbComponent extends Component {
|
|
||||||
constructor(id) {
|
|
||||||
super(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
if(this.$el) {
|
|
||||||
const btn = this.$el.querySelector('#breadcrumbBtn');
|
|
||||||
btn.addEventListener('click', buttonHandler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function buttonHandler(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
if (e.target.dataset.category) {
|
|
||||||
localStorage.setItem('category', e.target.dataset.category.toLowerCase());
|
|
||||||
window.location.href = '/';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
import { Component } from "../core/component";
|
|
||||||
import { apiService } from "../services/api.service";
|
|
||||||
import { renderItems } from "../templates/items.template";
|
|
||||||
|
|
||||||
export class CategoryComponent extends Component {
|
|
||||||
constructor(id, {items}, {filter}) {
|
|
||||||
super(id);
|
|
||||||
this.items = items;
|
|
||||||
this.filter = filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
if (this.$el) {
|
|
||||||
this.$el.addEventListener('click', buttonHandler.bind(this));
|
|
||||||
|
|
||||||
if (localStorage.getItem('category')) {
|
|
||||||
localStorage.removeItem('sortByAll', 'true'); // установка значения для компонента Filter
|
|
||||||
|
|
||||||
const category = localStorage.getItem('category');
|
|
||||||
breadcrumbActiveLink.call(this, category); // окрашиваем категорию по нажатию на breadcrumb
|
|
||||||
showItems.call(this, category); // отображем айтемсы если был нажат breadcrumb
|
|
||||||
localStorage.removeItem('category'); // очищаем ключ category чтобы данные не показывались всегда
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function showItems(category) {
|
|
||||||
const targetCategory = await apiService.getCategory(category);
|
|
||||||
const fData = await apiService.getItemsOne(category),
|
|
||||||
html = renderItems(targetCategory, fData);
|
|
||||||
|
|
||||||
this.items.onHide();
|
|
||||||
this.items.insertItems(html);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function buttonHandler(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
if (e.target.dataset.category && e.target.dataset.category != 'all') { // Выполняем логику если нажали на кнопки кроме "Все товары"
|
|
||||||
localStorage.removeItem('sortByAll'); // установка значения для компонента Filter
|
|
||||||
|
|
||||||
this.filter.clearChecked();
|
|
||||||
this.items.onShow();
|
|
||||||
btnActiveLink(e);
|
|
||||||
|
|
||||||
const category = await apiService.getCategory(e.target.dataset.category),
|
|
||||||
fData = await apiService.getItemsOne(e.target.dataset.category),
|
|
||||||
html = renderItems(category, fData);
|
|
||||||
|
|
||||||
this.items.onHide();
|
|
||||||
this.items.insertItems(html);
|
|
||||||
} else if (e.target.dataset.category === 'all') { // Выполняем логику если нажали на кнопку "Все товары"
|
|
||||||
localStorage.setItem('sortByAll', 'true'); // установка значения для компонента Filter
|
|
||||||
|
|
||||||
this.filter.clearChecked();
|
|
||||||
this.items.onShow();
|
|
||||||
btnActiveLink(e);
|
|
||||||
|
|
||||||
const fData = await apiService.getItems();
|
|
||||||
const categories = await apiService.getCategories();
|
|
||||||
const html = renderItems(categories, fData);
|
|
||||||
|
|
||||||
this.items.onHide();
|
|
||||||
this.items.insertItems(html);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Окраска li по нажатию
|
|
||||||
function btnActiveLink(e) {
|
|
||||||
Array.from(e.target.parentNode.parentNode.querySelectorAll('#catLi')).forEach(li => li.classList.remove('active'));
|
|
||||||
e.target.classList.add('active');
|
|
||||||
localStorage.setItem('currentCategory', e.target.dataset.category);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Окраска li по нажатию на breadcrumb
|
|
||||||
function breadcrumbActiveLink(category) {
|
|
||||||
const links = this.$el.querySelectorAll('#catLi');
|
|
||||||
Array.from(links).forEach(li => li.classList.remove('active'));
|
|
||||||
Array.from(links).forEach(li => li.dataset.category === category ? li.classList.add('active') : false);
|
|
||||||
Array.from(links).forEach(li => li.dataset.category === category ? localStorage.setItem('currentCategory', li.dataset.category) : false);
|
|
||||||
}
|
|
||||||
@ -1,56 +0,0 @@
|
|||||||
import { Component } from "../core/component";
|
|
||||||
import { apiService } from "../services/api.service";
|
|
||||||
import { renderItems } from "../templates/items.template";
|
|
||||||
|
|
||||||
export class FilterComponent extends Component {
|
|
||||||
constructor(id, {items}) {
|
|
||||||
super(id);
|
|
||||||
this.items = items;
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
if (this.$el) {
|
|
||||||
this.$el.addEventListener('click', sortByAllHandler.bind(this));
|
|
||||||
this.$el.addEventListener('click', sortByOneHandler.bind(this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clearChecked() {
|
|
||||||
if (this.$el) {
|
|
||||||
const options = this.$el.querySelectorAll('.filter-options form input');
|
|
||||||
Array.from(options).forEach(option => option.checked = false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function sortByAllHandler(e) {
|
|
||||||
if (localStorage.getItem('sortByAll')) {
|
|
||||||
if (e.target.id) {
|
|
||||||
const sorting = e.target.id;
|
|
||||||
|
|
||||||
this.items.onShow();
|
|
||||||
const fData = await apiService.getItems(sorting);
|
|
||||||
const categories = await apiService.getCategories();
|
|
||||||
const html = renderItems(categories, fData);
|
|
||||||
|
|
||||||
this.items.onHide();
|
|
||||||
this.items.insertItems(html);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function sortByOneHandler(e) {
|
|
||||||
if (!localStorage.getItem('sortByAll')) {
|
|
||||||
if (e.target.id) {
|
|
||||||
const sorting = e.target.id;
|
|
||||||
this.items.onShow();
|
|
||||||
|
|
||||||
const category = await apiService.getCategory(localStorage.getItem('currentCategory')),
|
|
||||||
fData = await apiService.getItemsOne(localStorage.getItem('currentCategory'), sorting),
|
|
||||||
html = renderItems(category, fData);
|
|
||||||
|
|
||||||
this.items.onHide();
|
|
||||||
this.items.insertItems(html);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
import { Component } from "../core/component";
|
|
||||||
import { insertCount } from "../other/counter";
|
|
||||||
|
|
||||||
export class HeaderComponent extends Component {
|
|
||||||
constructor(id) {
|
|
||||||
super(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
if (this.$el) {
|
|
||||||
const currentPage = this.$el.querySelector('#desktop-nav');
|
|
||||||
const pages = Array.from(this.$el.querySelectorAll('#page'));
|
|
||||||
pages.forEach(li => li.dataset.page === currentPage.dataset.current ? li.classList.add('active') : false);
|
|
||||||
// ф-я счетика товаров
|
|
||||||
localStorage.getItem('cart') ? insertCount('counter', JSON.parse(localStorage.getItem('cart'))) : false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
import { Component } from "../core/component";
|
|
||||||
|
|
||||||
export class InformationComponent extends Component {
|
|
||||||
constructor(id) {
|
|
||||||
super(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
if (this.$el) {
|
|
||||||
if (!localStorage.getItem('visited')) {
|
|
||||||
this.show();
|
|
||||||
}
|
|
||||||
const btn = this.$el.querySelector('#information-close');
|
|
||||||
btn.addEventListener('click', buttonHandler.bind(this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function buttonHandler() {
|
|
||||||
localStorage.setItem('visited', JSON.stringify(true));
|
|
||||||
this.hide();
|
|
||||||
}
|
|
||||||
@ -1,120 +0,0 @@
|
|||||||
import { Component } from "../core/component";
|
|
||||||
import { apiService } from "../services/api.service";
|
|
||||||
import { insertCount } from "../other/counter";
|
|
||||||
import { renderItems } from "../templates/items.template";
|
|
||||||
|
|
||||||
export class ItemsComponent extends Component {
|
|
||||||
constructor(id, {loader}, {notification}) {
|
|
||||||
super(id);
|
|
||||||
this.loader = loader;
|
|
||||||
this.notification = notification;
|
|
||||||
this.$el ? this.roster = this.$el.querySelector('#roster') : false;
|
|
||||||
if (localStorage.getItem('cart')) {
|
|
||||||
this.cart = JSON.parse(localStorage.getItem('cart'));
|
|
||||||
} else {
|
|
||||||
this.cart = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async init() {
|
|
||||||
if (this.$el) {
|
|
||||||
localStorage.setItem('sortByAll', 'true'); // установка значения для компонента Filter
|
|
||||||
this.$el.addEventListener('click', addItem.bind(this));
|
|
||||||
if (!localStorage.getItem('category')) { // Получаем все товары и выводим их если нету ключа category в ls
|
|
||||||
const fData = await apiService.getItems();
|
|
||||||
const categories = await apiService.getCategories();
|
|
||||||
const html = renderItems(categories, fData);
|
|
||||||
this.insertItems(html);
|
|
||||||
this.btnColor();
|
|
||||||
this.loader.hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onHide() {
|
|
||||||
this.$el.querySelector('#roster').innerHTML = '';
|
|
||||||
this.loader.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
onShow() {
|
|
||||||
this.$el.querySelector('#roster').innerHTML = '';
|
|
||||||
this.loader.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
btnColor() {
|
|
||||||
if (localStorage.getItem('cart')) {
|
|
||||||
// Окраска кнопок айтемов которые находятся в корзине
|
|
||||||
const obj = JSON.parse(localStorage.getItem('cart'));
|
|
||||||
|
|
||||||
obj.forEach(item => {
|
|
||||||
if (this.$el.querySelector(`#rosterButtons[data-id="${item.id}"] #addItem`)) {
|
|
||||||
this.$el.querySelector(`#rosterButtons[data-id="${item.id}"] #addItem`).classList.add('orange');
|
|
||||||
this.$el.querySelector(`#rosterButtons[data-id="${item.id}"] #addItem i`).innerHTML = 'close';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
insertItems(html) {
|
|
||||||
this.roster.insertAdjacentHTML('afterbegin', html);
|
|
||||||
this.btnColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function addItem(e) {
|
|
||||||
|
|
||||||
if (e.target.localName === 'button' && e.target.id === 'addItem') {
|
|
||||||
const target = e.target;
|
|
||||||
const item = {
|
|
||||||
id: e.target.parentNode.dataset.id,
|
|
||||||
title: e.target.parentNode.dataset.title,
|
|
||||||
count: e.target.parentNode.dataset.count,
|
|
||||||
price: e.target.parentNode.dataset.price
|
|
||||||
}
|
|
||||||
renderObj(item, this, target);
|
|
||||||
} else if (e.target.localName === 'i') {
|
|
||||||
const target = e.target.parentNode;
|
|
||||||
const item = {
|
|
||||||
id: e.target.parentNode.parentNode.dataset.id,
|
|
||||||
title: e.target.parentNode.parentNode.dataset.title,
|
|
||||||
count: e.target.parentNode.parentNode.dataset.count,
|
|
||||||
price: e.target.parentNode.parentNode.dataset.price
|
|
||||||
}
|
|
||||||
renderObj(item, this, target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderObj(obj, context, target) {
|
|
||||||
if (context.cart.length > 0) {
|
|
||||||
let insterted = false;
|
|
||||||
let index;
|
|
||||||
// Проверка на существующий айтем в корзине
|
|
||||||
context.cart.forEach((item, i) => {
|
|
||||||
if (item.id === obj.id) {
|
|
||||||
insterted = true;
|
|
||||||
index = i;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (insterted === false) {
|
|
||||||
context.cart.push(obj)
|
|
||||||
localStorage.setItem('cart', JSON.stringify(context.cart));
|
|
||||||
target.classList.add('orange');
|
|
||||||
target.querySelector('i').innerHTML = 'close';
|
|
||||||
insertCount('counter', context.cart);
|
|
||||||
context.notification.notificate('Товар был успешно добавлен в корзину.', '#26A69A');
|
|
||||||
} else {
|
|
||||||
context.cart.splice(index, 1);
|
|
||||||
localStorage.setItem('cart', JSON.stringify(context.cart));
|
|
||||||
target.classList.remove('orange');
|
|
||||||
target.querySelector('i').innerHTML = 'shopping_cart';
|
|
||||||
insertCount('counter', context.cart);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
context.cart.push(obj);
|
|
||||||
localStorage.setItem('cart', JSON.stringify(context.cart));
|
|
||||||
target.classList.add('orange');
|
|
||||||
target.querySelector('i').innerHTML = 'close';
|
|
||||||
insertCount('counter', context.cart);
|
|
||||||
context.notification.notificate('Товар был успешно добавлен в корзину.', '#26A69A');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
import { Component } from "../core/component";
|
|
||||||
|
|
||||||
export class LoaderComponent extends Component {
|
|
||||||
constructor(id) {
|
|
||||||
super(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,50 +0,0 @@
|
|||||||
import { Component } from "../core/component";
|
|
||||||
|
|
||||||
export class NotificationComponent extends Component {
|
|
||||||
constructor(id) {
|
|
||||||
super(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
notificate(text, color) {
|
|
||||||
const card = document.createElement('div');
|
|
||||||
card.classList.add('card-panel');
|
|
||||||
card.style.backgroundColor = color;
|
|
||||||
card.innerHTML = `<span class="white-text">${text}</span>`;
|
|
||||||
this.$el.innerHTML += card.outerHTML;
|
|
||||||
this.removeNotificate();
|
|
||||||
}
|
|
||||||
|
|
||||||
removeNotificate() {
|
|
||||||
// Полифилл для IE ^9
|
|
||||||
(function() {
|
|
||||||
var arr = [window.Element, window.CharacterData, window.DocumentType];
|
|
||||||
var args = [];
|
|
||||||
|
|
||||||
arr.forEach(function (item) {
|
|
||||||
if (item) {
|
|
||||||
args.push(item.prototype);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
(function (arr) {
|
|
||||||
arr.forEach(function (item) {
|
|
||||||
if (item.hasOwnProperty('remove')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Object.defineProperty(item, 'remove', {
|
|
||||||
configurable: true,
|
|
||||||
enumerable: true,
|
|
||||||
writable: true,
|
|
||||||
value: function remove() {
|
|
||||||
this.parentNode.removeChild(this);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})(args);
|
|
||||||
})();
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
this.$el.querySelector('.card-panel').remove();
|
|
||||||
}, 2000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
const M = require('../frameworks/materialize.min');
|
|
||||||
export class MaterializeConfig {
|
|
||||||
constructor() {
|
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
|
||||||
M.Sidenav.init(document.querySelectorAll('.sidenav'))
|
|
||||||
M.FormSelect.init(document.querySelectorAll('select'))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
export class Component {
|
|
||||||
constructor(id) {
|
|
||||||
this.$el = document.getElementById(id);
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {}
|
|
||||||
|
|
||||||
onShow() {}
|
|
||||||
|
|
||||||
onHide() {}
|
|
||||||
|
|
||||||
hide() {
|
|
||||||
this.$el ? this.$el.classList.add('hide') : false
|
|
||||||
}
|
|
||||||
|
|
||||||
show() {
|
|
||||||
this.$el ? this.$el.classList.remove('hide') : false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
export class Modal {
|
|
||||||
constructor(id, open, close) {
|
|
||||||
this.$el = document.getElementById(id);
|
|
||||||
this.open = document.getElementById(open);
|
|
||||||
this.close = document.getElementById(close);
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
if (this.open != null) {
|
|
||||||
this.open.addEventListener('click', openHandler.bind(this));
|
|
||||||
this.close.addEventListener('click', closeHandler.bind(this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
show() {
|
|
||||||
this.$el.classList.remove('hide');
|
|
||||||
document.body.style.overflowY = 'hidden';
|
|
||||||
}
|
|
||||||
|
|
||||||
hide() {
|
|
||||||
this.$el.classList.add('hide');
|
|
||||||
document.body.style.overflowY = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function openHandler() {
|
|
||||||
this.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeHandler() {
|
|
||||||
this.hide();
|
|
||||||
}
|
|
||||||
6
src/main/frameworks/materialize.min.js
vendored
6
src/main/frameworks/materialize.min.js
vendored
File diff suppressed because one or more lines are too long
@ -1,28 +0,0 @@
|
|||||||
import { HeaderComponent } from "./components/header.component.js";
|
|
||||||
import { InformationComponent } from "./components/information.component.js";
|
|
||||||
import { LoaderComponent } from "./components/loader.component.js";
|
|
||||||
import { ItemsComponent } from "./components/items.component.js";
|
|
||||||
import { CategoryComponent } from "./components/category.component.js";
|
|
||||||
import { BreadcrumbComponent } from "./components/breadcrumb.component.js";
|
|
||||||
import { FilterComponent } from "./components/filter.component.js";
|
|
||||||
import { CartModal } from "./modals/cart.modal.js";
|
|
||||||
import { PayModal } from "./modals/pay.modal.js";
|
|
||||||
import { NotificationComponent } from "./components/notification.component.js";
|
|
||||||
import { MaterializeConfig } from "./config/materialize.config.js";
|
|
||||||
|
|
||||||
// Components
|
|
||||||
const header = new HeaderComponent('header');
|
|
||||||
const loader = new LoaderComponent('loader');
|
|
||||||
const information = new InformationComponent('information');
|
|
||||||
const notification = new NotificationComponent('notification');
|
|
||||||
const items = new ItemsComponent('items', {loader}, {notification});
|
|
||||||
const filter = new FilterComponent('filter', {items});
|
|
||||||
const category = new CategoryComponent('category', {items}, {filter});
|
|
||||||
const breadcumb = new BreadcrumbComponent('breadcrumb');
|
|
||||||
|
|
||||||
// Modals
|
|
||||||
const cart = new CartModal('cart', 'cartOpen', 'cartClose', {items});
|
|
||||||
const pay = new PayModal('pay', 'pay-js', 'payClose');
|
|
||||||
|
|
||||||
const materialize = new MaterializeConfig();
|
|
||||||
console.log('Main Page');
|
|
||||||
@ -1,96 +0,0 @@
|
|||||||
import { Modal } from "../core/modal";
|
|
||||||
import { insertCount } from "../other/counter";
|
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
export class CartModal extends Modal {
|
|
||||||
constructor(id, open, close, {items}) {
|
|
||||||
super(id, open, close);
|
|
||||||
this.items = items;
|
|
||||||
if (this.$el) {
|
|
||||||
this.open.addEventListener('click', this.openHandler.bind(this));
|
|
||||||
this.close.addEventListener('click', this.closeHandler.bind(this));
|
|
||||||
this.list = this.$el.querySelector('#modalList');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closeHandler() {
|
|
||||||
this.removeItem = null;
|
|
||||||
this.makePay = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
openHandler() {
|
|
||||||
this.removeItem != null ? this.list.addEventListener('click', this.removeItem.bind(this)) : false
|
|
||||||
this.makePay != null ? this.$el.querySelector('form').addEventListener('submit', this.makePay.bind(this)) : false;
|
|
||||||
this.list.innerHTML = '';
|
|
||||||
this.insertItems(this.list);
|
|
||||||
}
|
|
||||||
|
|
||||||
insertItems(list) {
|
|
||||||
if (localStorage.getItem('cart')) {
|
|
||||||
const items = JSON.parse(localStorage.getItem('cart'));
|
|
||||||
|
|
||||||
if (items.length == 0) {
|
|
||||||
list.innerHTML = '<p style="text-align:center;padding:15px;">Вы не добавили ни один товар</p>';
|
|
||||||
this.$el.querySelector('form').classList.add('hide');
|
|
||||||
} else {
|
|
||||||
this.$el.querySelector('form').classList.remove('hide');
|
|
||||||
}
|
|
||||||
|
|
||||||
items.forEach(item => this.list.innerHTML += `<div data-id="${item.id}" data-title="${item.title}" data-price="${item.price}" data-count="1" class="modal-content__item"><div class="modal-content__title"><a href="/product/${item.id}"><b>${item.title}</b></a><br><span class="in-stock">В наличии: ${item.count} (шт)</span></div><div class="modal-content__right"><span id="price">${parseFloat(item.price).toFixed(2)}₽</span></div><div class="modal-content__remove"><span><i data-id="${item.id}" class="material-icons" id="removeItem">close</i></span></div></div>`);
|
|
||||||
insertCount('modalCounter', this.items.cart);
|
|
||||||
insertCount('counter', this.items.cart);
|
|
||||||
this.insertTotalPrice('totalPrice', this.items.cart);
|
|
||||||
} else {
|
|
||||||
list.innerHTML = '<p style="text-align:center;padding:15px;">Вы не добавили ни один товар</p>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
removeItem(e) {
|
|
||||||
if (e.target.id === 'removeItem') {
|
|
||||||
const id = e.target.dataset.id;
|
|
||||||
let index;
|
|
||||||
|
|
||||||
this.items.cart.forEach((item, i) => item.id === id ? index = i : false);
|
|
||||||
this.items.cart.splice(index, 1);
|
|
||||||
localStorage.setItem('cart', JSON.stringify(this.items.cart));
|
|
||||||
|
|
||||||
this.list.innerHTML = '';
|
|
||||||
this.insertItems(this.list);
|
|
||||||
this.defaultBtnColor(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
insertTotalPrice(id, array) {
|
|
||||||
let totalPrice = 0;
|
|
||||||
array.forEach(item => totalPrice += parseFloat(item.price));
|
|
||||||
this.$el.querySelector(`#${id}`).innerHTML = `${totalPrice.toFixed(2)}₽`;
|
|
||||||
}
|
|
||||||
|
|
||||||
async makePay(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
const payInfo = {items: this.items.cart.map(item => {
|
|
||||||
return {
|
|
||||||
id: item.id,
|
|
||||||
title: item.title,
|
|
||||||
price: parseFloat(item.price)
|
|
||||||
}
|
|
||||||
})};
|
|
||||||
let totalPrice = 0;
|
|
||||||
payInfo.items.forEach(item => totalPrice += parseFloat(item.price));
|
|
||||||
payInfo.totalPrice = Math.round(totalPrice * 100) / 100;
|
|
||||||
payInfo.payMethod = this.$el.querySelector('.payment-field input').value;
|
|
||||||
payInfo.email = this.$el.querySelector('.email-field input').value;
|
|
||||||
|
|
||||||
const response = await axios.put('/payment', payInfo);
|
|
||||||
response.data.payUrl ? document.location.href = response.data.payUrl : alert(response.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultBtnColor(id) {
|
|
||||||
if (this.items.roster) {
|
|
||||||
if (this.items.roster.querySelector(`#rosterButtons[data-id="${id}"] #addItem`)) {
|
|
||||||
this.items.roster.querySelector(`#rosterButtons[data-id="${id}"] #addItem`).classList.remove('orange');
|
|
||||||
this.items.roster.querySelector(`#rosterButtons[data-id="${id}"] #addItem i`).innerHTML = 'shopping_cart';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
import { Modal } from "../core/modal";
|
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
export class PayModal extends Modal {
|
|
||||||
constructor (id, open, close) {
|
|
||||||
super(id, open, close);
|
|
||||||
if (this.open != null) {
|
|
||||||
this.open.addEventListener('click', this.openHandler.bind(this));
|
|
||||||
this.close.addEventListener('click', this.closeHandler.bind(this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closeHandler() {
|
|
||||||
this.$el.querySelector('form').onsubmit = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
openHandler(e) {
|
|
||||||
if (e.target.id === 'payOpen') {
|
|
||||||
const targetInfo = e.target.parentNode.dataset;
|
|
||||||
this.$el.querySelector('.title-field input').value = targetInfo.title;
|
|
||||||
|
|
||||||
this.show();
|
|
||||||
this.$el.querySelector('form').onsubmit = (e) => {
|
|
||||||
this.makePay(e, targetInfo);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async makePay(e, info) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
const payInfo = {
|
|
||||||
items: [{
|
|
||||||
id: info.id,
|
|
||||||
title: info.title
|
|
||||||
}],
|
|
||||||
totalPrice: parseFloat(info.price)
|
|
||||||
}
|
|
||||||
payInfo.payMethod = this.$el.querySelector('.payment-field input').value;
|
|
||||||
payInfo.email = this.$el.querySelector('.email-field input').value;
|
|
||||||
|
|
||||||
const response = await axios.put('/payment', payInfo);
|
|
||||||
response.data.payUrl ? document.location.href = response.data.payUrl : alert(response.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
export function insertCount(id, array) {
|
|
||||||
const counter = document.getElementById(id);
|
|
||||||
counter.innerHTML = array.length;
|
|
||||||
}
|
|
||||||
@ -1,61 +0,0 @@
|
|||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
class ApiService {
|
|
||||||
constructor(baseUrl) {
|
|
||||||
this.url = baseUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getCategory(category) {
|
|
||||||
try {
|
|
||||||
const request = `${this.url}/api/category/${encodeURIComponent(category)}`;
|
|
||||||
return useRequest(request);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getCategories() {
|
|
||||||
try {
|
|
||||||
const request = `${this.url}/api/categories`;
|
|
||||||
return useRequest(request);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getItems(sorting) {
|
|
||||||
try {
|
|
||||||
if (sorting) {
|
|
||||||
const request = `${this.url}/api/items?sorting=${sorting}`;
|
|
||||||
return useRequest(request);
|
|
||||||
} else {
|
|
||||||
const request = `${this.url}/api/items`;
|
|
||||||
return useRequest(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getItemsOne(category, sorting) {
|
|
||||||
try {
|
|
||||||
if (sorting) {
|
|
||||||
const request = `${this.url}/api/items/${encodeURIComponent(category.toLowerCase())}?sorting=${sorting}`;
|
|
||||||
return useRequest(request);
|
|
||||||
} else {
|
|
||||||
const request = `${this.url}/api/items/${encodeURIComponent(category.toLowerCase())}`;
|
|
||||||
return useRequest(request);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function useRequest(request) {
|
|
||||||
const response = await axios.get(request);
|
|
||||||
return await JSON.parse(response.request.response);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const apiService = new ApiService('http://localhost:3000');
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
export function renderItems(categories, items) {
|
|
||||||
let html = '';
|
|
||||||
try {
|
|
||||||
categories.forEach(category => {
|
|
||||||
html += `<div class="items-category">
|
|
||||||
<h2 class="small-title">${category.title}</h2>
|
|
||||||
</div>`;
|
|
||||||
category.itemsInCategory = 0; // счетчит для отслеживания категорий где нету айтемов
|
|
||||||
try {
|
|
||||||
items.forEach(item => {
|
|
||||||
if (item.category.toLowerCase() === category.title.toLowerCase()) {
|
|
||||||
category.itemsInCategory += 1;
|
|
||||||
html += `
|
|
||||||
<div class="items-list">
|
|
||||||
<div class="items-list__name">
|
|
||||||
<div class="list-icon">
|
|
||||||
<img src="./img/service-icons/${category.img}" alt="#">
|
|
||||||
</div>
|
|
||||||
<div class="list-title">
|
|
||||||
<a href="/product/${item._id}">${item.title}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="items-list__info">
|
|
||||||
<div class="list-date">
|
|
||||||
<small>${diffDates(new Date(), new Date(item.date))}</small>
|
|
||||||
</div>
|
|
||||||
<div class="list-count">
|
|
||||||
<span>${item.count} шт.</span>
|
|
||||||
</div>
|
|
||||||
<div class="list-one">
|
|
||||||
<span>Цена за 1 шт.</span>
|
|
||||||
</div>
|
|
||||||
<div class="list-price">
|
|
||||||
<span>${item.price.toFixed(2)}₽</span>
|
|
||||||
</div>
|
|
||||||
<div id="rosterButtons" data-id="${item._id}" data-title="${item.title}" data-count="${item.count}" data-price="${item.price} class="list-buttons">
|
|
||||||
<button id="payOpen" class="btn-small waves-effect waves-light">Купить</button>
|
|
||||||
<button id="addItem" class="btn-small waves-effect waves-light"><i
|
|
||||||
class="material-icons">shopping_cart</i></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
category.itemsInCategory === 0
|
|
||||||
? html += '<div class="items-list"><span>В этой категории товаров пока что нету.</span></div>'
|
|
||||||
: false;
|
|
||||||
} catch {
|
|
||||||
html += '<div class="items-list"><span>В этой категории товаров пока что нету.</span></div>';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch {
|
|
||||||
html += '<div class="items-list"><span>Добавьте хотя бы одну категорию.</span></div>';
|
|
||||||
}
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
|
|
||||||
function diffDates(firstDate, secondDate) {
|
|
||||||
let diff = Math.floor((firstDate - secondDate) / (60 * 60 * 24 * 1000));
|
|
||||||
if (diff <= 0) {
|
|
||||||
return 'добавлено сегодня';
|
|
||||||
}
|
|
||||||
return diff + ' дней назад';
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user