123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473 |
- 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 = "<h2>Корзина</h2><table id='table'>";
- for(let goodId of Object.entries(store.getState().cart)) {
- str += `<tr>
- <td class="visually-hidden">${goodId[0]}</td>
- <td>${goodId[1].good.name}</td>
- <td><img src="${backendURL}/${goodId[1].good.images[0].url}"/></td>
- <td>Цена: <span id="price">${goodId[1].good.price}</span></td>
- <td>Кол-во: <input id="count" type="number" value="${goodId[1].count}"></td>
- <td><button id="clear">Удалить товар</button></td>
- </tr>`;
- };
- str += "</table><button id='order'>Сделать заказ</button>";
- 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 = "<h2>История заказов</h2><table>";
-
- for(let order of orders) {
- str += "<tr>";
- str += `<td>${(new Date(+order.createdAt)).toLocaleString()}</td>`;
- str += "<td>"
- for(let orderGood of order.orderGoods) {
- str += `<ul>
- <li>${orderGood.good.name}</li>
- <li><img src="${backendURL}/${orderGood.good.images[0].url}"/></li>
- <li>Цена: ${orderGood.good.price}</li>
- </ul>`;
- }
- str += "</td>"
- str += "</tr>";
- };
- str += "</table>";
- 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 = `<h2>Вход на сайт</h2>
- <input id="login" type="text" name="login" placeholder="Введите ваш логин">
- <input id="password" type="password" name="password" placeholder="Введите ваш пароль">
- <button id="sign_in">Войти</button>`;
- sign_in.addEventListener("click", function() {
- actionFullLogin(login.value, password.value);
- // store.dispatch(actionFullLogin(login.value, password.value));
- });
- },
- register(){
- content.innerHTML = `<h2>Регистрация</h2>
- <input id="login" type="text" name="reg-login" placeholder="Введите ваш будущий логин">
- <input id="password" type="text" name="reg-password" placeholder="Введите ваш будущий пароль">
- <input id="nick" type="text" name="reg-nick" placeholder="Введите ваш nick">
- <button id="registr">Зарегистрироваться</button>`;
- 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 = `<h1>${name}</h1> ТУТ ДОЛЖНЫ БЫТЬ ПОДКАТЕГОРИИ`
- for (const {_id, name, price, images} of catById.payload.goods){
- const card = document.createElement('div')
- card.innerHTML = `<h2>${name}</h2>
- <img src="${backendURL}/${images[0].url}" />
- <strong>${price}</strong>
- <a href="#/good/${_id}">ССЫЛКА НА СТРАНИЦУ ТОВАРА</a>`
- 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 = `<h1>${name}</h1>`;
- const card = document.createElement('div');
- card.innerHTML = `<h2>${goodById.payload.name}</h2>
- <img src="${backendURL}/${goodById.payload.images[0].url}" />
- <strong>${goodById.payload.price}</strong>
- <button id="goodAdd">Добавить в корзину</button>`;
- content.append(card);
- goodAdd.addEventListener("click", function() {
- store.dispatch(actionCartAdd(goodById.payload));
- });
- };
- });
- store.subscribe(createCart);
|