123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727 |
- // функция createStore
- function createStore(reducer) {
- let state = reducer(undefined, {})
- let cbs = []
- function dispatch(action) {
- if (typeof action === 'function') {
- return action(dispatch)
- }
- const newState = reducer(state, action)
- if (newState !== state) {
- state = newState
- for (let cb of cbs)
- cb()
- }
- }
-
- return {
- dispatch,
- getState() {
- return state
- },
- subscribe(cb) {
- cbs.push(cb)
- return () => cbs = cbs.filter(c => c !== cb)
- }
- }
- }
- // функция promiseReducer
- function promiseReducer(state = {}, { type, status, payload, error, name }) {
-
- if (type === 'PROMISE') {
- return {
- ...state,
- [name]: { status, payload, error }
- }
- }
- return state
- }
- // функция cartReducer
- function cartReducer(state = {}, { type, count = 1, _id, name }) {
- if (type === "CART_ADD") {
- return {
- ...state,
- [_id]: {
- name: name,
- count: state[_id] ? state[_id].count + count : count
- }
- }
- }
- if (type === "CART_CHANGE") {
- return {
- ...state,
- [_id]: {
- name: name,
- count: count
- }
- }
- }
- if (type === 'CART_REMOVE') {
- let { [_id]: count, ...copyWithout } = state
- return copyWithout
- }
- if (type === 'CART_CLEAR') {
- return {}
- }
- return state
- }
- let signatureToken = (token) => JSON.parse(atob(token.split(".")[1]))
- function authReducer(state, { type, token }) {
- if (state === undefined) {
- if (localStorage.authToken) {
- type = "LOGIN"
- token = localStorage.authToken
- } else {
- return {}
- }
- }
- if (type === "LOGIN") {
- console.log('LOGIN')
- localStorage.authToken = token
- return {token, payload: signatureToken(token)}
- }
- if (type === "LOGOUT") {
- console.log('LOGOUT')
- localStorage.removeItem("authToken")
- return {}
- }
- return state
- }
- // reducers
- let reducers = {
- promise: promiseReducer,
- cart: cartReducer,
- auth: authReducer
- }
- // функция combineReducers
- function combineReducers(reducers) {
- function commonReducer(state = {}, action) {
- let newState = {}
- for (let key in reducers) {
- let innerState = reducers[key](state[key], action)
- innerState === state[key] ? newState[key] = state[key] : newState[key] = innerState
- }
- return newState
- }
- return commonReducer
- }
- const store = createStore(combineReducers(reducers))
- // запросы
- const getGQL = url =>
- (query, variables = {}) => fetch(url, {
- method: 'POST',
- headers: {
- "content-type": "application/json",
- ...(localStorage.authToken ? { Authorization: "Bearer " + localStorage.authToken } : {})
- },
- body: JSON.stringify({ query, variables })
- }).then(res => res.json())
- let shopGQL = getGQL("http://shop-roles.asmer.fs.a-level.com.ua/graphql")
- let categoryById = async (id) => {
- let query = `query fndcategory($id: String) {
- CategoryFind(query: $id){
- name goods{
- _id name price images {
- url
- }
- }
- }
- }`
- let variables = {
- "id": JSON.stringify([{ "_id": id }])
- }
- let res = await shopGQL(query, variables)
- console.log(res)
- return res
- }
- let goodById = async (id) => {
- let query = `query fndgood($id: String) {
- GoodFind(query: $id){
- name description price images {
- url
- }
- }
- }`
- let variables = {
- "id": JSON.stringify([{ "_id": id }])
- }
- let res = await shopGQL(query, variables)
- return res
- }
- const actionRootCategories = () =>
- actionPromise('rootCategories', shopGQL(`query cats($query:String) {
- CategoryFind(query:$query) {
- _id name
- }
- }`, {query: JSON.stringify([{parent:null}])}))
- //регистрация
- let reg = async(login, password) => {
- let query = `mutation reg($login:String, $password:String) {
- UserUpsert(user:{
- login: $login,
- password: $password
- }){
- _id
- }
- }`
- let variables = {"login":login, "password":password}
- let res = await shopGQL(query, variables)
- return res
- }
- //логин
- let log = async(login, password) => {
- let query = `query login($login:String, $password:String) {
- login(login: $login, password: $password)
- }`
- let variables = {"login":login, "password":password}
- let token = await shopGQL(query, variables)
- return token.data.login
- }
- //отправка заказа
- let newOrder = async(obj) => {
- let option = Object.entries(obj)
- let orderGoods = []
-
- for (let key of option) {
- let i = {
- "count": key[1],
- "good": {"_id": key[0]}
- }
- orderGoods.push(i)
- }
-
- let query = `mutation newOrder($order:OrderInput) {
- OrderUpsert(order:$order) {
- _id
- }
- }`
-
- let variables = {
- "order": {"orderGoods": orderGoods}
- }
-
- let res = await shopGQL(query, variables)
- console.log(res)
- return res
- }
- // actions
- const actionPending = name => ({ type: 'PROMISE', status: 'PENDING', name })
- const actionResolved = (name, payload) => ({ type: 'PROMISE', status: 'RESOLVED', name, payload })
- const actionRejected = (name, error) => ({ type: 'PROMISE', status: 'REJECTED', name, error })
- const actionPromise = (name, promise) =>
- async dispatch => {
- dispatch(actionPending(name))
- try {
- let payload = await promise
- dispatch(actionResolved(name, payload))
- return payload
- }
- catch (error) {
- dispatch(actionRejected(name, error))
- }
- }
- const actionCategoryById = id => actionPromise('catById', categoryById(id))
- const actionGoodById = id => actionPromise('goodById', goodById(id))
- const actionBuyGood = (obj) => actionPromise('newOrder', newOrder(obj))
- const actionCartAdd = (n, id, name) => ({ type: "CART_ADD", count: n, _id: id, name })
- const actionCartChange = (n, id, name) => ({ type: "CART_CHANGE", count: n, _id: id, name })
- const actionCartRemove = id => ({ type: "CART_REMOVE", _id: id })
- const actionCartClear = () => ({ type: "CART_CLEAR" })
- const actionAuthLogin = token => ({type: 'LOGIN', token})
- const actionAuthLogout = () => ({type: 'LOGOUT'})
- const actionLogin = (login, password) => actionPromise("log", log(login, password))
- const actionReg = (login, password) => actionPromise("reg", reg(login, password))
- const actionFullLogin = (login, password) => async(dispatch) => {
- let result = await dispatch(actionLogin(login, password))
- if (result !== null){
- dispatch(actionAuthLogin(result))
- } else {
- alert ('Такой пользователь не существует!')
- }
- }
- const actionFullRegister = (login, password) => async(dispatch) => {
- let result = await dispatch(actionReg(login, password))
- if(result.data.UserUpsert !==null) {
- dispatch(actionFullLogin(login, password))
- } else {
- alert('Такой пользователь уже существует!')
- }
- }
- store.dispatch(actionRootCategories())
- window.onhashchange = () => {
- let { 1: route, 2: id } = location.hash.split('/')
- if (route === 'categories') {
- store.dispatch(actionCategoryById(id))
- }
- if (route === 'good') {
- store.dispatch(actionGoodById(id))
- }
- if (route === 'cart') {
- cartDraw(store.getState().cart, main)
- }
- if (route === "login") {
- drawLog(main)
- }
- if (route === "registration") {
- drawReg(main)
- }
- }
- function drawMainMenu() {
- let cats = store.getState().promise.rootCategories.payload
- if (cats) {
- aside.innerText = ''
- for (let { _id, name } of cats.data.CategoryFind) {
- let catA = document.createElement('a')
- catA.href = `#/categories/${_id}`
- catA.innerText = name
- aside.append(catA)
- }
- }
- }
- let goodDraw = (obj, parent, _id) => {
- let box = document.createElement("div")
- let goodName = document.createElement("h3")
- let goodImg = document.createElement("img")
- let description = document.createElement("p")
- let price = document.createElement("p")
- let count = document.createElement("input")
- let goodBtnBox = document.createElement("p")
- let btn1 = document.createElement("button")
- let btn2 = document.createElement("button")
- price.textContent = "Цена: " + obj.price + "грн"
- goodImg.src = "http://shop-roles.asmer.fs.a-level.com.ua/" + obj.images[0].url
- goodName.textContent = obj.name
- description.textContent = "Описание: " + obj.description
- count.type = "number"
- count.min = 1
- count.value = 1
- btn1.textContent = "Купить"
- btn2.textContent = "В корзину"
- goodBtnBox.append(count, btn2, btn1)
- let order = {
- [_id]: +count.value
- }
- count.oninput = () => order[_id] = +count.value
- btn1.onclick = () => {
- store.dispatch(actionBuyGood(order))
- }
- btn2.onclick = () => {
- store.dispatch(actionCartAdd(+count.value, _id, obj.name))
- }
- box.append(goodImg, goodName, description, price, goodBtnBox)
- parent.append(box)
- }
- let cardDraw = (obj, parent) => {
- let box = document.createElement("div")
- let img = document.createElement("img")
- img.style.width ='400px'
- img.src = "http://shop-roles.asmer.fs.a-level.com.ua/" + obj.images[0].url
- let price = document.createElement("p")
- let nameGood = document.createElement("h5")
- nameGood.textContent = obj.name
- price.innerText = "Цена:" + obj.price + "грн"
- box.append(img, nameGood, price,)
- let a = document.createElement("a")
- a.href = "#/good/" + obj._id
- a.append(box)
- parent.append(a)
- }
- let cartDraw = (obj, parent) => {
- while (parent.lastChild) {
- parent.lastChild.remove()
- }
- let cartName = document.createElement("h3")
- cartName.textContent = "Ваши заказы:"
- parent.append(cartName)
- let order = {}
- for (let key in obj) {
- order[key] = obj[key].count
- let cartItem = document.createElement("p")
- let name = document.createElement("p")
- let count = document.createElement("input")
- let btnDelItem = document.createElement("button")
- btnDelItem .textContent="Удалить"
- let btnPlus = document.createElement("button")
- btnPlus.textContent="+"
- let btnMinus = document.createElement("button")
- btnMinus.textContent="-"
- count.min = 1
- count.value = obj[key].count
- name.textContent = obj[key].name
- cartItem.append(btnMinus, count, btnPlus, name, btnDelItem)
- parent.append(cartItem)
- if (+count.value === 1) {
- btnMinus.disabled = "true"
- }
- count.oninput = () => {
- if (+count.value >= 1) {
- store.dispatch(actionCartChange(+count.value, key, obj[key].name))
- }
- }
- btnPlus.onclick = () => {
- store.dispatch(actionCartChange(+count.value + 1, key, obj[key].name))
- }
- btnMinus.onclick = () => {
- store.dispatch(actionCartChange(+count.value - 1, key, obj[key].name))
- }
- btnDelItem.onclick = () => {
- store.dispatch(actionCartRemove(key))
- }
- }
- let btnBox = document.createElement("p")
- let btnOrder = document.createElement("button")
- let btnClear = document.createElement("button")
- btnClear.textContent = "ОЧИСТИТЬ КОРЗИНУ"
- btnOrder.textContent = "КУПИТЬ"
- btnOrder.onclick = () => {
- store.dispatch(actionBuyGood(order))
- store.dispatch(actionCartClear())
- }
- btnClear.onclick = () => {
- store.dispatch(actionCartClear())
- }
- btnBox.append(btnOrder, btnClear)
- parent.append(btnBox)
- }
- let statusCart = () => {
- if (cart.children.length === 1) {
- let span = document.createElement("span")
- cart.append(span)
- }
- let sum = 0
- let cartState = store.getState().cart
- for (let key in cartState) {
- sum += cartState[key].count
- }
- cart.lastChild.textContent = sum
- }
- let checkUser = (parent = thecart) => {
- if (parent.children.length > 1) {
- parent.lastChild.remove()
- }
- let status = store.getState().auth
- let box = document.createElement("div")
- let userName = document.createElement("p")
- box.append(userName)
- parent.append(box)
- if (status.payload) {
- let btn = document.createElement("button")
- userName.textContent = status.payload.sub.login
- btn.textContent = "Выход"
- btn.style.cursor="pointer"
- btn.style.color="rgb(86, 93, 189)"
- btn.onclick = () => {
- store.dispatch(actionAuthLogout())
- }
- box.append(btn)
- } else {
- let btn = document.createElement("a")
- let btnREG = document.createElement("a")
- btn.textContent = "Вход"
- btnREG.textContent = "Регистрация"
- btn.href = "#/login"
- btnREG.href = "#/registration"
- box.append(btn, btnREG)
- }
- }
- function Reg(parent, type, open) {
- let h3 = document.createElement("h3")
- let loginInput = document.createElement("input")
- let passwordInput = document.createElement("input")
- let checkbox = document.createElement("input")
- let btn = document.createElement("button")
- btn.style.marginRight="10px"
- let form = document.createElement("span")
- let box = document.createElement("p")
- box.append(passwordInput, checkbox)
- loginInput.id = "login"
- loginInput.placeholder = "логин"
- loginInput.style.textAlign="center"
- passwordInput.id = "password"
- passwordInput.placeholder = "пароль"
- passwordInput.style.textAlign="center"
- btn.id = "btn"
- checkbox.type = "checkbox"
- btn.disabled = true;
- if (type === "reg") {
- h3.textContent = "РЕГИСТРАЦИЯ"
- btn.textContent = "Зарегистрироваться"
- } else {
- h3.textContent = "ВХОД"
- btn.textContent = "Войти"
- }
- form.append(h3, loginInput, box, btn)
- form.className = "form"
- parent.append(form)
- let btnOpen = () => {
- if (type === "reg" && checkbox.checked === false) {
- passwordInput.value !== "" && password.value === passwordVerify.value ? btn.disabled = false : btn.disabled = true
- } else {
- (loginInput.value != "" && passwordInput.value != "") ? btn.disabled = false : btn.disabled = true
- }
- }
- let checker = (check) => {
- if (check) {
- passwordInput.type = "text"
- checkbox.checked = true
- if (type === "reg" && passwordVerify) {
- passwordVerify.remove()
- }
- } else {
- passwordInput.type = "password"
- checkbox.checked = false
- if (type === "reg") {
- let passwordInput2 = document.createElement("input")
- passwordInput2.placeholder = "повторите пароль"
- passwordInput2.style.textAlign="center"
- passwordInput2.id = "passwordVerify"
- passwordInput2.type = "password"
- passwordInput2.oninput = () => {
- btnOpen();
- }
- form.append(passwordInput2)
- }
- }
- }
- checker(open)
- loginInput.oninput = () => {
- btnOpen();
- if (typeof this.onChange === "function") {
- this.onChange([loginInput.value, passwordInput.value])
- }
- }
- passwordInput.oninput = () => {
- btnOpen();
- if (typeof this.onChange === "function") {
- this.onChange([loginInput.value, passwordInput.value])
- }
- }
- checkbox.onchange = () => {
- checker(checkbox.checked)
- btnOpen()
- if (typeof this.onOpenChange === "function") {
- this.onOpenChange(checkbox.checked)
- }
- }
- this.getValue = () => [loginInput.value, passwordInput.value]
- this.setValue = (valueLogin, valuePassword) => {
- loginInput.value = valueLogin;
- passwordInput.value = valuePassword
- btnOpen()
- }
- this.getOpen = () => checkbox.checked
- this.setOpen = (open) => {
- checker(open)
- }
- }
- let drawLog = (parent) => {
- while (parent.lastChild) {
- parent.lastChild.remove()
- }
- if (store.getState().auth.payload) {
- let h2 = document.createElement("h2")
- h2.textContent = "Вход выполнен успешно!"
- h2.style.color = "rgb(86, 93, 189)"
- parent.append(h2)
- } else {
- new Reg(parent)
- btn.onclick = () => {
- store.dispatch(actionFullLogin(login.value, password.value))
- }
- }
- }
- let drawReg = (parent) => {
- while (parent.lastChild) {
- parent.lastChild.remove()
- }
- if (store.getState().auth.payload) {
- let h2 = document.createElement("h2")
- h2.textContent = "Регистрация прошла успешно!"
- h2.style.color = "rgb(86, 93, 189)"
- parent.append(h2)
- } else {
- new Reg(parent, "reg")
- btn.onclick = () => {
- store.dispatch(actionFullRegister(login.value, password.value))
- }
- }
- }
- //subscribers
- store.subscribe(drawMainMenu)
- store.subscribe(() => console.log(store.getState()))
- store.subscribe(statusCart)
- store.subscribe(checkUser)
- store.subscribe(() => {
- const { 1: route, 2: id } = location.hash.split('/')
- if (route === 'categories') {
- const catById = store.getState().promise.catById?.payload
- if (catById) {
- while (main.lastChild) {
- main.lastChild.remove()
- }
- aside.innerText = ''
- let cats = document.createElement('p')
- cats.innerText = "Вы в категории ==>" + " " + catById.data.CategoryFind[0].name
- mainMenu = document.createElement('a')
- mainMenu.style.cursor = 'pointer'
- mainMenu.innerText = "<== Назад в главное меню"
- mainMenu.onclick = () => {
- main.innerText = ''
- drawMainMenu()
- }
- let cards = document.createElement("section")
- for (let key of catById.data.CategoryFind[0].goods) {
- cardDraw(key, cards)
- }
- main.append(cards)
- aside.append(mainMenu, cats)
- }
- }
- if (route === 'good') {
- const goodById = store.getState().promise.goodById?.payload
- const catById = store.getState().promise.catById?.payload
- if (goodById) {
- while (main.lastChild) {
- main.lastChild.remove()
- }
- aside.innerText = ''
- let cats = document.createElement('p')
- cats.innerText = "Вы в категории ==>" + " " + catById.data.CategoryFind[0].name
- mainMenu.style.cursor = 'pointer'
- mainMenu.onclick = () => {
- main.innerText = ''
- drawMainMenu()
- }
- aside.append(cats, mainMenu)
- goodDraw(goodById.data.GoodFind[0], main, id)
- }
- }
- if (route === 'cart') {
- cartDraw(store.getState().cart, main)
- }
- if (route === 'login') {
- drawLog(main)
- }
- if (route === "registration") {
- drawReg(main)
- }
- })
|