let aside = document.querySelector(".aside");
let content = document.querySelector(".main__main-content");
let registration = document.querySelector(".header__registration");
let signIn = document.querySelector(".header__sign-in");
let cart = document.querySelector(".imaginary-shopping-cart--content");
let cartButton = document.querySelector(".header__cart");
let dasboard = document.querySelector(".header__dashboard");
registration.addEventListener("click", function() {
location.href = "#/register";
});
signIn.addEventListener("click", function() {
location.href = "#/login";
});
cartButton.addEventListener("click", function() {
location.href = "#/cart";
});
dasboard.addEventListener("click", function() {
location.href = "#/dasboard";
});
let createStore = function(reducer) {
let state = reducer(undefined, {});
let cbs = [];
let getState = () => state;
let subscribe = function(cb) {
cbs.push(cb);
return () => cbs = cbs.filter(c => c !== cb);
};
let dispatch = function(action) {
if(typeof(action) == "function") {
return action(dispatch, getState);
};
let newState = reducer(state, action);
if (newState !== state){
state = newState;
for (let cb of cbs) {
cb();
};
};
};
return {
getState,
subscribe,
dispatch
};
};
const promiseReducer = function(state={}, {type, name, status, payload, error}) {
if (type == 'PROMISE'){
return {
...state,
[name]:{status, payload, error}
}
}
return state;
};
const actionPending = name => ({type: "PROMISE", name, status: 'PENDING'});
const actionFulfilled = (name,payload) => ({type: "PROMISE", name, status: 'FULFILLED', payload});
const actionRejected = (name,error) => ({type: "PROMISE", name, status: 'REJECTED', error});
const actionPromise = function(name, promise) {
return async dispatch => {
dispatch(actionPending(name));
try {
let payload = await promise
dispatch(actionFulfilled(name, payload))
return payload
}
catch(error){
dispatch(actionRejected(name, error))
};
};
};
let jwtDecode = function(token) {
let payloadInBase64;
let payloadInJson;
let payload;
try {
payloadInBase64 = token.split(".")[1];
payloadInJson = atob(payloadInBase64);
payload = JSON.parse(payloadInJson);
return payload;
}
catch(err) {
}
};
const authReducer = function(state, {type, token}) {
let payload;
if (state == undefined) {
if(localStorage.authToken) {
type = "AUTH_LOGIN";
token = localStorage.authToken;
} else {
type = "AUTH_LOGOUT";
};
};
if (type == "AUTH_LOGIN") {
payload = jwtDecode(token);
if(payload) {
localStorage.authToken = token;
return {
token: token,
payload: payload
}
}
};
if (type == "AUTH_LOGOUT") {
localStorage.removeItem("authToken");
return {};
};
return state || {};
};
const actionAuthLogin = token => ({type: "AUTH_LOGIN", token});
const actionAuthLogout = () => ({type: "AUTH_LOGOUT"});
let cartReducer = function(state={}, {type, good, count=1}) {
if(type == "CART_ADD") {
let newState = {...state};
if(good["_id"] in state) {
newState[good._id].count = newState[good._id].count + count;
}
else {
newState = {
...state,
[good._id]: {count, good}
};
};
return newState;
};
if(type == "CART_CHANGE") {
let newState = {...state,
[good._id]: {count, good}
};
return newState;
};
if(type == "CART_DELETE") {
let newState = {...state};
delete newState[good._id];
return newState;
};
if(type == "CART_CLEAR") {
return {};
};
return state;
};
const actionCartAdd = (good, count=1) => ({type: 'CART_ADD', good, count})
const actionCartChange = (good, count=1) => ({type: 'CART_CHANGE', good, count})
const actionCartDelete = (good) => ({type: 'CART_DELETE', good})
const actionCartClear = () => ({type: 'CART_CLEAR'})
const combineReducers = function(reducers) {
return function (state={}, action) {
const newState = {};
for(let [reducerName, reducer] of Object.entries(reducers)) {
let checkState = reducer(state[reducerName], action);
if(state[reducerName] != checkState) {
newState[reducerName] = checkState;
};
};
if(Object.keys(newState).length == 0) {
return state;
};
return {...Object.assign(state, newState)};
};
};
const store = createStore(combineReducers({promise: promiseReducer, auth: authReducer, cart: cartReducer}));
store.subscribe(() => console.log(store.getState()));
const getGQL = function(url) {
return async function(query, variables) {
const res = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
...(localStorage.authToken ? { "Authorization": "Bearer " + localStorage.authToken } : {})
},
body: JSON.stringify({ query, variables })
});
const data = await res.json();
if (data.data) {
return Object.values(data.data)[0];
}
else {
throw new Error(JSON.stringify(data.errors));
};
};
};
const backendURL = 'http://shop-roles.asmer.fs.a-level.com.ua';
const gql = getGQL(backendURL + '/graphql');
let actionRootCats = function() {
return actionPromise("rootCats", gql(`query {
CategoryFind(query: "[{\\"parent\\":null}]"){
_id name
}
}`));
};
store.dispatch(actionRootCats());
let actionCatById = function(_id) {
return actionPromise("catById", gql(`query catById($q: String){
CategoryFindOne(query: $q){
_id name goods {
_id name price images {
url
}
}
}
}`,
{q: JSON.stringify([{_id}])}
));
};
let actionGoodById = function(_id) {
return actionPromise("goodById", gql(`query findGood($goodQuery: String) {
GoodFindOne(query:$goodQuery) {
_id name price images {
url
}
}
}`,
{goodQuery: JSON.stringify([{"_id": _id}])}
));
};
let actionFullLogin = async function(login, password) {
let token = await gql("query userLogin($login: String, $password: String) {login(login: $login, password: $password)}", {"login": login, "password": password});
store.dispatch(actionAuthLogin(token));
};
let actionFullRegister = function(login, password, nick) {
return actionPromise("userRegister", gql(`mutation userRegister($login:String, $password:String, $nick:String) {
UserUpsert(user: {login:$login, password:$password, nick:$nick}) {
_id login nick
}
}`,
{
"login": login,
"password": password,
"nick": nick
}))
};
let actionOrders = async function() {
let order = await gql(`mutation makeOrder($order:OrderInput){
OrderUpsert(order: $order){
_id
}
}`, {
"order": {
orderGoods: Object.entries(store.getState().cart).map(([_id, count]) =>({"count": count.count, "good": {_id}}))
}
});
store.dispatch(actionCartClear());
}
let createCart = function() {
const [,route, _id] = location.hash.split('/');
if(route == "cart") {
let str = "
Корзина Сделать заказ ";
content.innerHTML = str;
table.addEventListener("click", function(evt) {
if(evt.target.tagName == "BUTTON") {
store.dispatch(actionCartDelete(store.getState().cart[evt.path[2].firstElementChild.textContent]?.good))
};
});
order.addEventListener("click", function() {
actionOrders();
});
}
};
let createDashbord = async function() {
const [,route, _id] = location.hash.split('/');
if(route == "dasboard") {
let orders = await gql(`query ordersFind($query:String) {
OrderFind(query: $query) {
createdAt orderGoods {
count good {
name price images {
url
}
}
}
}
}`,
{
"query": JSON.stringify([{}])
});
let str = "История заказов ";
for(let order of orders) {
str += "";
str += `${(new Date(+order.createdAt)).toLocaleString()} `;
str += ""
for(let orderGood of order.orderGoods) {
str += `
${orderGood.good.name}
Цена: ${orderGood.good.price}
`;
}
str += " "
str += " ";
};
str += "
";
content.innerHTML = str;
}
};
window.onhashchange = () => {
const [, route, _id] = location.hash.split('/');
const routes = {
category(){
store.dispatch(actionCatById(_id));
},
good(){
store.dispatch(actionGoodById(_id));
},
login(){
content.innerHTML = `Вход на сайт
Войти `;
sign_in.addEventListener("click", function() {
actionFullLogin(login.value, password.value);
// store.dispatch(actionFullLogin(login.value, password.value));
});
},
register(){
content.innerHTML = `Регистрация
Зарегистрироваться `;
registr.addEventListener("click", function() {
store.dispatch(actionFullRegister(login.value, password.value, nick.value));
});
},
cart() {
createCart();
},
dasboard() {
createDashbord();
}
};
if (route in routes) {
routes[route]();
};
};
window.onhashchange();
store.subscribe(() => {
const {rootCats} = store.getState().promise;
if (rootCats?.payload){
let ul = document.createElement("ul");
aside.innerHTML = '';
for (const {_id, name} of rootCats?.payload){
let li = document.createElement("li");
let link = document.createElement('a');
link.href = `#/category/${_id}`;
link.innerText = name;
li.append(link);
ul.append(li);
}
aside.append(ul);
};
});
store.subscribe(() => {
const {catById} = store.getState().promise;
const [,route, _id] = location.hash.split('/')
if (catById?.payload && route === 'category'){
const {name} = catById.payload
content.innerHTML = `${name} ТУТ ДОЛЖНЫ БЫТЬ ПОДКАТЕГОРИИ`
for (const {_id, name, price, images} of catById.payload.goods){
const card = document.createElement('div')
card.innerHTML = `${name}
${price}
ССЫЛКА НА СТРАНИЦУ ТОВАРА `
content.append(card);
}
}
});
store.subscribe(() => {
const {goodById} = store.getState().promise;
const [,route, _id] = location.hash.split('/');
if (goodById?.payload && route == "good") {
const {name} = goodById.payload;
content.innerHTML = `${name} `;
const card = document.createElement('div');
card.innerHTML = `${goodById.payload.name}
${goodById.payload.price}
Добавить в корзину `;
content.append(card);
goodAdd.addEventListener("click", function() {
store.dispatch(actionCartAdd(goodById.payload));
});
};
});
store.subscribe(createCart);