123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908 |
- const delay = ms => new Promise(ok => setTimeout(() => ok(ms), ms))
- function createStore(reducer) {
- let state = reducer(undefined, {}) //стартовая инициализация состояния, запуск редьюсера со state === undefined
- let cbs = [] //массив подписчиков
- const getState = () => state //функция, возвращающая переменную из замыкания
- const subscribe = cb => (cbs.push(cb), //запоминаем подписчиков в массиве
- () => cbs = cbs.filter(c => c !== cb)) //возвращаем функцию unsubscribe, которая удаляет подписчика из списка
- const dispatch = action => {
- if (typeof action === 'function') { //если action - не объект, а функция
- return action(dispatch, getState) //запускаем эту функцию и даем ей dispatch и getState для работы
- }
- const newState = reducer(state, action) //пробуем запустить редьюсер
- if (newState !== state) { //проверяем, смог ли редьюсер обработать action
- state = newState //если смог, то обновляем state
- /*state = {
- ...state,
- ...newState
- }*/ //если смог, то обновляем state
- for (let cb of cbs) cb() //и запускаем подписчиков
- }
- }
- return {
- getState, //добавление функции getState в результирующий объект
- dispatch,
- subscribe //добавление subscribe в объект
- }
- }
- function promiseReducer(state = {}, { promiseName, type, status, payload, error }) {
- if (type === 'PROMISE') {
- return {
- ...state,
- [promiseName]: { status, payload, error }
- }
- }
- return state
- }
- const actionPending = promiseName => ({ promiseName, type: 'PROMISE', status: 'PENDING' })
- const actionFulfilled = (promiseName, payload) => ({ promiseName, type: 'PROMISE', status: 'FULFILLED', payload })
- const actionRejected = (promiseName, error) => ({ promiseName, type: 'PROMISE', status: 'REJECTED', error })
- const actionPromise = (promiseName, promise) =>
- async dispatch => {
- dispatch(actionPending(promiseName)) //сигнализируем redux, что промис начался
- try {
- const payload = await promise //ожидаем промиса
- dispatch(actionFulfilled(promiseName, payload)) //сигнализируем redux, что промис успешно выполнен
- return payload //в месте запуска store.dispatch с этим thunk можно так же получить результат промиса
- }
- catch (error) {
- dispatch(actionRejected(promiseName, error)) //в случае ошибки - сигнализируем redux, что промис несложился
- }
- }
- // const store = createStore(promiseReducer)
- // store.subscribe(() => console.log(store.getState()))
- // store.dispatch(actionPromise('delay', delay(1000)))
- // store.dispatch(actionPromise('luke', fetch("https://swapi.dev/api/people/1").then(res => res.json())))
- // store.dispatch(actionPromise('tatooine', fetch("https://swapi.dev/api/planets/1").then(res => res.json())))
- //по итогу должен получится какой-то такой state:
- /*
- {
- delay: {status: 'FULFILLED', payload: 1000, error: undefined},
- luke: {status: 'FULFILLED', payload: { ..... траливали про люка}, error: undefined},
- tatooine: {status: 'FULFILLED', payload: { ..... траливали про планету татуин}, error: undefined},
- }
- */
- /* authReducer
- Этот редьюсер предназначен для хранения и обработки состояния залогиненности пользователя. У него бывает два вида состояний:
- Залогинен. state вида: {token: "jwt токен", payload: {.....раскодированная инфа из токена}}
- Незалогинен. state вида: {} (пустой объект)
- Редьюсер обрабатывает два типа экшонов:
- AUTH_LOGIN. Логинимся. Редьюсер должен попытаться раскодировать токен, и если это получилось, вернуть новый стейт вида {token, payload} Если токен не удалось раскодировать, вернуть пустой объект (т. е. разлогиниться)
- AUTH_LOGOUT. Разлогиниваемся. Возвращаем пустой объект.
- Проверочный код (и экшенкриейторы бонусом):*/
- function jwtDecode(token) {
- let result;
- try {
- let secondPartToken = token.split('.')[1];
- result = JSON.parse(atob(secondPartToken));
- } catch (e) {
- }
- return result;
- }
- function authReducer(state = {}, { type, token }) {
- if (type === 'AUTH_LOGIN') {
- payload = jwtDecode(token)
- console.log(payload)
- if (payload) return { token, payload }
- }
- if (type === 'AUTH_LOGOUT') return {}
- return state
- }
- const actionAuthLogin = token => ({ type: 'AUTH_LOGIN', token })
- const actionAuthLogout = () => ({ type: 'AUTH_LOGOUT' })
- // const store = createStore(authReducer)
- // store.subscribe(() => console.log(store.getState()))
- // store.dispatch(actionAuthLogout())
- // store.dispatch(actionAuthLogin(token))
- /*{
- token: "eyJhbGc.....",
- payload: {
- "sub": {
- "id": "6377e133b74e1f5f2ec1c125",
- "login": "test5",
- "acl": [
- "6377e133b74e1f5f2ec1c125",
- "user"
- ]
- },
- "iat": 1668812458
- }
- }*/
- //store.dispatch(actionAuthLogout()) // {}
- /*cartReducer
- Редьюсер, который хранит состояние корзины во время серфинга по интернет-магазину. Похож на редьюсер ларька, только работает немного наоборот - в то время как в ларьке товар уменьшается, тут он добавляется.
- Состояние:
- {
- idТовара1: {count: количество1, good: {....инфа про товар с бэкэнда, включая цену, описание и картинки}},
- idТовара2: {count: количество2, good: {....инфа про товар с бэкэнда, включая цену, описание и картинки}},
- }
- Типы экшенов
- */
- // Добавление товара. Должен добавлять новый ключ в state, или обновлять, если ключа в state ранее не было, увеличивая количество
- const actionCartAdd = (good, count = 1) => ({ type: 'CART_ADD', count, good })
- // Уменьшение количества товара. Должен уменьшать количество товара в state, или удалять его если количество будет 0 или отрицательным
- const actionCartSub = (good, count = 1) => ({ type: 'CART_SUB', count, good })
- // Удаление товара. Должен удалять ключ из state
- const actionCartDel = (good) => ({ type: 'CART_DEL', good })
- // Задание количества товара. В отличие от добавления и уменьшения, не учитывает того количества, которое уже было в корзине, а тупо назначает количество поверху (или создает новый ключ, если в корзине товара не было). Если count 0 или отрицательное число - удаляем ключ из корзины;
- const actionCartSet = (good, count = 1) => ({ type: 'CART_SET', count, good })
- // Очистка корзины. state должен стать пустым объектом {}
- const actionCartClear = () => ({ type: 'CART_CLEAR' })
- /*
- Проверочный код
- Наличие good как ключа в state немного избыточно - для оформления заказа достаточно id и количества. Однако это позволит хранить в редьюсере всю нужную информацию, например, для отображения страницы корзины без лишних запросов на сервер. На странице корзины обычно есть и описание, и цена, и фоточки.
- Проверочный код ниже использует в качестве id более наглядные вещи.
- */
- function cartReducer(state = {}, { type, count, good }) {
- if (type === 'CART_ADD') {
- if (good._id in state) {
- return {
- ...state,
- [good._id]: {
- good,
- count: state[good._id].count + count
- }
- }
- } else {
- return {
- ...state,
- [good._id]: {
- good,
- count
- }
- }
- }
- }
- if (type === 'CART_SUB') {
- let result = {}
- if (good._id in state) {
- if ((state[good._id].count - count) <= 0) {
- newState = { ...state }
- delete newState[good._id]
- return newState
- } else {
- return {
- ...state,
- [good._id]: {
- good,
- count: state[good._id].count - count
- }
- }
- }
- }
- }
- if (type === 'CART_DEL') {
- let newState = { ...state }
- delete newState[good._id]
- return newState
- }
- // Задание количества товара. В отличие от добавления и уменьшения, не учитывает того количества, которое уже было в корзине, а тупо назначает количество поверху (или создает новый ключ, если в корзине товара не было). Если count 0 или отрицательное число - удаляем ключ из корзины;
- if (type === 'CART_SET') {
- if (good._id in state && count <= 0) {
- let newState = { ...state }
- delete newState[good._id]
- return newState
- } else {
- let newState = {
- ...state,
- [good._id]: {
- good,
- count
- }
- }
- return newState
- }
- }
- if (type === 'CART_CLEAR') return {}
- return state
- }
- function combineReducers(reducers) {
- function totalReducer(state = {}, action) {
- const newTotalState = {}
- for (const [reducerName, reducer] of Object.entries(reducers)) {
- const newSubState = reducer(state[reducerName], action)
- if (newSubState !== state[reducerName]) {
- newTotalState[reducerName] = newSubState
- }
- }
- if (Object.keys(newTotalState).length) {
- return { ...state, ...newTotalState }
- }
- return state
- }
- return totalReducer
- }
- const reducers = {
- promise: promiseReducer, //допилить много имен для многих промисо
- auth: authReducer, //часть предыдущего ДЗ
- cart: cartReducer, //часть предыдущего ДЗ
- }
- const totalReducer = combineReducers(reducers)
- function localStoredReducer(originalReducer, localStorageKey) {
- let counter = 0
- function wrapper(state, action) {
- if (counter === 0) {
- counter++
- if (localStorage[localStorageKey]) {
- let result = JSON.parse(localStorage[localStorageKey])
- if (result) return result
- }
- } else {
- let result = originalReducer(state, action)
- localStorage[localStorageKey] = JSON.stringify(result)
- return result
- }
- }
- return wrapper
- }
- const store = createStore(localStoredReducer(totalReducer, "state")) //не забудьте combineReducers если он у вас уже есть
- store.subscribe(() => console.log(store.getState()))
- const actionRootCats = () => actionPromise("RootCats", gqlRootCats())
- store.dispatch(actionRootCats())
- store.subscribe(() => {
- let result = store.getState().promise.RootCats.payload
- if (result) {
- aside.innerHTML = ""
- for (let { _id, name } of result) {
- aside.innerHTML += `<a href='#/category/${_id}'>${name}</a>`
- }
- }
- })
- const actionCategoryGoodsAndSubCategoryGoods = (_id) => actionPromise("CategoryGoodsAndSubCategoryGoods", gqlCategoryGoodsAndSubCategoryGoods(_id))
- store.dispatch(actionCategoryGoodsAndSubCategoryGoods('62c94b10b74e1f5f2ec1a0dd'))
- store.subscribe(() => {
- if (location.hash === '') {
- const { status, payload, error } = store.getState().promise.CategoryGoodsAndSubCategoryGoods
- if (status === 'PENDING') {
- main.innerHTML = `<img src='giphy.gif'/>`
- }
- if (status === 'FULFILLED') {
- if (payload) categotyToMain(payload)
- }
- if (status === 'REJECTED') {
- main.innerHTML = `Что-то пошло не так, но мы скоро всё починим ;( \n сообщить о проблеме: <a href="mailto:mail@example.com">blablatest123@gmail.com</a>`
- }
- }
- })
- function categotyToMain(result) {
- main.innerHTML = ""
- let breadcrumbsContainer = document.createElement('div')
- main.append(breadcrumbsContainer)
- breadcrumbsContainer.classList.add('breadcrumbsContainer')
- let breadcrumbsHome = document.createElement('a')
- breadcrumbsContainer.append(breadcrumbsHome)
- breadcrumbsHome.innerText = 'Mystore.com'
- breadcrumbsHome.href = location.origin + location.pathname
- if (result.parent){
- breadcrumbsContainer.innerHTML += `<div>></div><div>...</div><div>></div><a href='#/category/${result.parent._id}'>${result.parent.name}</a>`
- }
- let h1 = document.createElement('h1')
- h1.innerText = result.name
- main.append(h1)
- if (result.subCategories && result.subCategories.length>0){
- const containerSubcategoryLink = document.createElement('div')
- containerSubcategoryLink.classList.add('containerSubcategoryLink')
- main.append(containerSubcategoryLink)
- for(const {_id, name} of result.subCategories){
- console.log(name)
- let subcategoryLink = document.createElement('a')
- containerSubcategoryLink.append(subcategoryLink)
- subcategoryLink.href = `#/category/${_id}`
- subcategoryLink.classList.add('subcategoryLink')
- subcategoryLink.innerText = name
- }
- }
- if (!result.goods){
- let emptyCategoryMessage = document.createElement('div')
- main.append(emptyCategoryMessage)
- emptyCategoryMessage.innerText = 'В этой категории пока нет товаров :('
- return
- }
- for (let { _id, name, images, price} of result?.goods) {
- let card = document.createElement('a')
- card.id = _id
- card.href = `#/good/${_id}`
- card.classList.add('card')
- main.append(card)
- let cardImgWrapper = document.createElement('div')
- cardImgWrapper.classList.add('cardImgWrapper')
- card.append(cardImgWrapper)
- let cardImg = document.createElement('img')
- cardImg.classList.add('cardImg')
- cardImgWrapper.append(cardImg)
- if (images.length>0){
- let { url } = images[0]
- cardImg.src = hostname + url
- } else{
- cardImg.src = 'https://lukachi.com.ua/source/default-image.jpg'
- }
- let cardName = document.createElement('h2')
- cardName.classList.add('cardName')
- cardName.innerText = name
- card.append(cardName)
- let cardPrice = document.createElement('div')
- cardPrice.classList.add('cardPrice')
- cardPrice.innerText = price + " грн"
- card.append(cardPrice)
- }
- }
- let hostname = 'http://shop-roles.node.ed.asmer.org.ua/'
- // store.subscribe(() => {
- // let result = store.getState().promise.CategoryGoodsAndSubCategoryGoods?.payload
- // const [, route, _id] = location.hash.split('/')
- // if (result && route === "category") {
- // categotyToMain(result)
- // }
- // })
- store.subscribe(() => {
- const [, route, _id] = location.hash.split('/')
- if (route !== "category") return
- const { status, payload, error } = store.getState().promise.CategoryGoodsAndSubCategoryGoods
- if (status === 'PENDING') {
- main.innerHTML = `<img src='giphy.gif'/>`
- }
- if (status === 'FULFILLED' && payload) {
- categotyToMain(payload)
- }
- if (status === 'REJECTED') {
- main.innerHTML = `Что-то пошло не так, но мы скоро всё починим ;( \n сообщить о проблеме: <a href="mailto:mail@example.com">blablatest123@gmail.com</a>`
- }
- })
- // store.subscribe(() => {
- // let result = store.getState().promise.OneGoodWithDescriptionAndImages?.payload
- // const [, route, _id] = location.hash.split('/')
- // if (result && route === "good") {
- // main.innerHTML = ""
- // let h1 = document.createElement('h1')
- // h1.innerText = result.name
- // main.append(h1)
- // let imgSlider = document.createElement('div')
- // imgSlider.classList.add('imgSlider')
- // main.append(imgSlider)
- // for (let { url } of result.images) {
- // imgSlider.innerHTML += `<img class="sliderImg" src="${hostname + url}"></img>`
- // }
- // let asideDesriptionPriceCard = document.createElement('div')
- // asideDesriptionPriceCard.classList.add('asideDesriptionPriceCard')
- // main.append(asideDesriptionPriceCard)
- // let goodPrice = document.createElement('div')
- // goodPrice.classList.add('goodPrice')
- // goodPrice.innerText = result.price + ' грн'
- // asideDesriptionPriceCard.append(goodPrice)
- // let goodCountInput = document.createElement('input')
- // goodCountInput.classList.add('goodCountInput')
- // goodCountInput.type = 'number'
- // goodCountInput.min = 1
- // goodCountInput.value = 1
- // asideDesriptionPriceCard.append(goodCountInput)
- // let goodButtonAddToCart = document.createElement('a')
- // goodButtonAddToCart.classList.add('goodButtonAddToCart')
- // goodButtonAddToCart.innerText = 'В КОРЗИНУ'
- // goodButtonAddToCart.onclick = () => store.dispatch(actionCartAdd(result, +goodCountInput.value))
- // asideDesriptionPriceCard.append(goodButtonAddToCart)
- // let description = document.createElement('div')
- // description.classList.add('description')
- // description.innerText = result.description
- // asideDesriptionPriceCard.append(description)
- // }
- // })
- store.subscribe(() => {
- const [, route, _id] = location.hash.split('/')
- if (route !== "good") return
- const { status, payload, error } = store.getState().promise.OneGoodWithDescriptionAndImages
- if (status === 'PENDING') {
- main.innerHTML = `<img src='giphy.gif'/>`
- }
- if (status === 'FULFILLED' && payload) {
- main.innerHTML = ""
- let h1 = document.createElement('h1')
- h1.innerText = payload.name
- main.append(h1)
- let imgSlider = document.createElement('div')
- imgSlider.classList.add('imgSlider')
- main.append(imgSlider)
- for (let { url } of payload.images) {
- imgSlider.innerHTML += `<img class="sliderImg" src="${hostname + url}"></img>`
- }
- let asideDesriptionPriceCard = document.createElement('div')
- asideDesriptionPriceCard.classList.add('asideDesriptionPriceCard')
- main.append(asideDesriptionPriceCard)
- let goodPrice = document.createElement('div')
- goodPrice.classList.add('goodPrice')
- goodPrice.innerText = payload.price + ' грн'
- asideDesriptionPriceCard.append(goodPrice)
- let goodCountInput = document.createElement('input')
- goodCountInput.classList.add('goodCountInput')
- goodCountInput.type = 'number'
- goodCountInput.min = 1
- goodCountInput.value = 1
- asideDesriptionPriceCard.append(goodCountInput)
- let goodButtonAddToCart = document.createElement('a')
- goodButtonAddToCart.classList.add('goodButtonAddToCart')
- goodButtonAddToCart.innerText = 'В КОРЗИНУ'
- goodButtonAddToCart.onclick = () => store.dispatch(actionCartAdd(payload, +goodCountInput.value))
- asideDesriptionPriceCard.append(goodButtonAddToCart)
- let description = document.createElement('div')
- description.classList.add('description')
- description.innerText = payload.description
- asideDesriptionPriceCard.append(description)
- }
- if (status === 'REJECTED') {
- main.innerHTML = `Что-то пошло не так, но мы скоро всё починим ;( \n сообщить о проблеме: <a href="mailto:mail@example.com">blablatest123@gmail.com</a>`
- }
- })
- const actionOneGoodWithDescriptionAndImages = (_id) => actionPromise("OneGoodWithDescriptionAndImages", gqlOneGoodWithDescriptionAndImages(_id))
- store.subscribe(() => {
- let result = 0
- let arrResult = Object.values(store.getState().cart)
- for (let { count } of arrResult) {
- result += count
- }
- cartIcon.innerText = result
- })
- store.subscribe(() => {
- let arrResult = Object.values(store.getState().cart)
- const [, route, _id] = location.hash.split('/')
- if (arrResult && route === "cart") {
- cartPageAdd()
- }
- })
- window.onhashchange = () => {
- const [, route, _id] = location.hash.split('/')
- const routes = {
- category() {
- store.dispatch(actionCategoryGoodsAndSubCategoryGoods(_id))
- },
- good() {
- store.dispatch(actionOneGoodWithDescriptionAndImages(_id))
- // тут был store.dispatch goodById
- console.log('good', _id)
- },
- // login() {
- // console.log('А ТУТ ЩА ДОЛЖНА БЫТЬ ФОРМА ЛОГИНА')
- // //нарисовать форму логина, которая по нажатию кнопки Login делает store.dispatch(actionFullLogin(login, password))
- // },
- // register() {
- // //нарисовать форму регистрации, которая по нажатию кнопки Login делает store.dispatch(actionFullRegister(login, password))
- // },
- cart() {
- cartPageAdd()
- },
- orders() {
- store.dispatch(actionOrderFind())
- }
- }
- if (route in routes) {
- routes[route]()
- }
- }
- function cartPageAdd() {
- let arrResult = Object.values(store.getState().cart)
- const [, route, _id] = location.hash.split('/')
- if (arrResult && route === "cart") {
- main.innerHTML = ""
- let h1 = document.createElement('h1')
- h1.innerText = "Оформление заказа"
- main.append(h1)
- let orderTable = document.createElement('table')
- main.append(orderTable)
- orderTable.classList.add('table_price')
- let orderTableBody = document.createElement('tbody')
- orderTable.append(orderTableBody)
-
- let firstTr = document.createElement('tr')
- orderTableBody.append(firstTr)
- firstTr.innerHTML = `<th></th><th>Название товара</th><th>Цена шт.</th><th>Количество</th><th>Итого</th><th></th>`
- let counter = 1
- let summ = 0
- for (let { good, count } of arrResult) {
- console.log(count)
- let trGood = document.createElement('tr')
- orderTableBody.append(trGood)
- trGood.innerHTML = `
- <td>${counter}</td>
- <td>${good.name}</td>
- <td>${good.price}</td>`
- let tdInput = document.createElement('td')
- trGood.append(tdInput)
- let inputCount = document.createElement('input')
- inputCount.type = 'number'
- inputCount.min = 1
- inputCount.value = count
- inputCount.oninput = () => store.dispatch(actionCartSet(good, +inputCount.value))
- tdInput.append(inputCount)
- let tdSummGood = document.createElement('td')
- trGood.append(tdSummGood)
- tdSummGood.innerText = count * good.price
- let tdDelete = document.createElement('td')
- trGood.append(tdDelete)
- let deleteButton = document.createElement('button')
- tdDelete.append(deleteButton)
- deleteButton.classList.add('deleteButton')
- deleteButton.innerText = 'удалить'
- deleteButton.onclick = () => store.dispatch(actionCartDel(good))
-
- //НЕ РАБОТАЕТ!? trGood.innerHTML += `<td>${count * good.price}</td>`
- counter += 1
- summ += count * good.price
- }
- let trSummTotal = document.createElement('tr')
- orderTableBody.append(trSummTotal)
- let tdColspan = document.createElement('td')
- trSummTotal.append(tdColspan)
- tdColspan.colSpan = 4
- let tdSummTotal = document.createElement('td')
- trSummTotal.append(tdSummTotal)
- tdSummTotal.innerText = summ +'грн'
- tdSummTotal.classList.add('tdSumm')
- let tdDeleteTotal = document.createElement('td')
- trSummTotal.append(tdDeleteTotal)
- let DeleteTotalButton = document.createElement('button')
- tdDeleteTotal.append(DeleteTotalButton)
- DeleteTotalButton.innerText = 'ОЧИСТИТЬ КОРЗИНУ'
- DeleteTotalButton.onclick = () => store.dispatch(actionCartClear())
-
- //orderTableBody.innerHTML += `<tr><td colspan="4"></td><td class="tdSumm">${summ} грн</td></tr>`
- let addOrder = document.createElement('div')
- addOrder.classList.add('addOrder')
- addOrder.innerText = "ОФОРМИТЬ ЗАКАЗ"
- main.append(addOrder)
- let arrGoods = Object.values(store.getState().cart).map(({ count, good: { _id } }) => { return { count, good: { _id } } })
- addOrder.onclick = () => {
- store.dispatch(actionFullAddOrder(arrGoods))
- }
- }
- }
- const actionAddOrder = (arrGoods) => {
- return actionPromise("orderUpsert", OrderUpsert2(arrGoods))
- }
- const actionFullAddOrder = (arrGoods) =>
- async dispatch => {
- await dispatch(actionAddOrder(arrGoods))
- dispatch(actionCartClear())
- location.hash = '#/orders'
- }
- const actionLogin = (login, password) => {
- return actionPromise("logAndPass", gqllogin(login, password))
- }
- const actionRegistration = (login, password) => {
- return actionPromise("newUser", gqlUserAdd(login, password))
- }
- const actionFullLogin = (login, password) =>
- async dispatch => {
- //dispatch возвращает то, что вернул thunk, возвращаемый actionLogin, а там промис,
- //так как actionPromise возвращает асинхронную функцию
- const token = await dispatch(actionLogin(login, password))
- //проверьте что token - строка и отдайте его в actionAuthLogin
- if (typeof token === 'string')
- store.dispatch(actionAuthLogin(token))
- }
- const actionFullRegistration = (login, password) =>
- async dispatch => {
- const userAddPromis = await dispatch(actionRegistration(login, password))
- if (userAddPromis) store.dispatch(actionFullLogin(login, password))
- //dispatch возвращает то, что вернул thunk, возвращаемый actionLogin, а там промис,
- //так как actionPromise возвращает асинхронную функцию
- //const token = await dispatch(actionLogin(login, password))
- //проверьте что token - строка и отдайте его в actionAuthLogin
- //if (typeof token === 'string')
- // store.dispatch(actionAuthLogin(token))
- }
- const actionOrderFind = () =>
- actionPromise("OrderFind", gqlOrderFind())
- function LoginFormFunc(parent, passOpenDefault = open) {
- function Password(parent, open) {
- const inputPass = document.createElement('input')
- parent.append(inputPass)
- const checkboxPass = document.createElement('input')
- checkboxPass.type = 'checkbox'
- parent.append(checkboxPass)
- this.setValue = (value) => {
- inputPass.value = value
- if (typeof this.onChange === 'function') this.onChange(this.getValue()) // запускается по событию oninput в поле ввода, передает текст в колбэк
- } //задает значение
- this.getValue = () => inputPass.value //читает значение
- this.setOpen = (open) => {
- if (open) {
- checkboxPass.checked = true
- inputPass.type = "text"
- }
- if (!open) {
- checkboxPass.checked = false
- inputPass.type = "password"
- }
- if (typeof this.onOpenChange === 'function') this.onOpenChange(this.getOpen()) // запускается по изменению состояния открытости пароля
- } //задает открытость текста в поле ввода
- this.getOpen = () => checkboxPass.checked //читает открытость текста в поле ввода
- this.setOpen(open)
- inputPass.oninput = () => this.setValue(this.getValue())
- checkboxPass.oninput = () => this.setOpen(this.getOpen())
- }
- const LoginForm = document.createElement('div')
- parent.append(LoginForm)
- const inputLogin = document.createElement('input')
- LoginForm.append(inputLogin)
- let p = new Password(LoginForm, passOpenDefault)
- const inputButton = document.createElement('input')
- inputButton.type = 'button'
- inputButton.value = 'войти'
- inputButton.id = 'signIn'
- LoginForm.append(inputButton)
- inputButton.disabled = true
- const newUserAddButton = document.createElement('input')
- newUserAddButton.type = 'button'
- newUserAddButton.value = 'зарегистрироваться'
- newUserAddButton.id = 'register'
- LoginForm.append(newUserAddButton)
- p.onChange = () => checkButtonDisabled()
- inputLogin.oninput = () => checkButtonDisabled()
- function checkButtonDisabled() {
- if (p.getValue() && inputLogin.value) inputButton.disabled = false
- else inputButton.disabled = true
- }
- this.getLogin = () => inputLogin.value
- this.setLogin = (value) => {
- inputLogin.value = value
- checkButtonDisabled()
- }
- this.getPass = () => p.getValue()
- this.setPass = (value) => {
- p.setValue(value)
- checkButtonDisabled()
- }
- inputButton.onclick = () => {
- if (typeof this.inputButtonOnclick === 'function') this.inputButtonOnclick() //функция при нажатии на кнопку войти
- }
- newUserAddButton.onclick = () => {
- if (typeof this.newUserAddButtonOnclick === 'function') this.newUserAddButtonOnclick()
- }
- }
- // let LoginFormInHeader = new LoginFormFunc(user)
- // LoginFormInHeader.inputButtonOnclick = function () {
- // store.dispatch(actionFullLogin(this.getLogin(), this.getPass()))
- // }
- //vasya321986320915sf5654755ssddgfg пороль
- store.subscribe(() => {
- let result = store.getState().auth?.payload?.sub?.login
- if (result) {
- user.innerHTML = result
- const buttonExitLogin = document.createElement('button')
- buttonExitLogin.innerHTML = 'выйти'
- buttonExitLogin.classList.add('buttonExitLogin')
- buttonExitLogin.onclick = () => {
- store.dispatch(actionAuthLogout())
- }
- user.append(buttonExitLogin)
- localStorage.authToken = store.getState().auth.token
- const buttonOrders = document.createElement('button')
- buttonOrders.innerHTML = 'история заказов'
- buttonOrders.classList.add('buttonOrders')
- buttonOrders.onclick = () => location.hash = '#/orders'
- user.append(buttonOrders)
- } else {
- delete localStorage.authToken
- user.innerHTML = "Unknown User"
- let LoginFormInHeader = new LoginFormFunc(user)
- LoginFormInHeader.inputButtonOnclick = () => {
- store.dispatch(actionFullLogin(this.getLogin(), this.getPass()))
- }
- LoginFormInHeader.newUserAddButtonOnclick = function () {
- store.dispatch(actionFullRegistration(this.getLogin(), this.getPass()))
- }
- }
- })
- // store.subscribe(() => {
- // let arrResult = store.getState().promise.OrderFind?.payload
- // const [, route, _id] = location.hash.split('/')
- // if (arrResult && route === "orders") {
- // main.innerHTML = ""
- // let h1 = document.createElement('h1')
- // h1.innerText = "История заказов"
- // main.append(h1)
- // let orderTable = document.createElement('table')
- // main.append(orderTable)
- // orderTable.classList.add('table_price')
- // let firstTr = document.createElement('tr')
- // orderTable.append(firstTr)
- // firstTr.innerHTML = `<th></th><th>Номер заказа</th><th>Дата</th><th>Сумма, грн</th>`
- // let counter = 1
- // let summ = 0
- // for (let { _id, createdAt, total } of arrResult) {
- // let createdAtFormat = new Date(+createdAt)
- // let year = createdAtFormat.getFullYear()
- // let month = createdAtFormat.getMonth() < 9 ? "0" + (createdAtFormat.getMonth() + 1) : createdAtFormat.getMonth() + 1
- // let day = createdAtFormat.getDate() < 9 ? "0" + (createdAtFormat.getDate() + 1) : createdAtFormat.getDate() + 1
- // let hours = createdAtFormat.getHours() < 10 ? "0" + (createdAtFormat.getHours()) : createdAtFormat.getHours()
- // let minutes = createdAtFormat.getMinutes() < 10 ? "0" + (createdAtFormat.getMinutes()) : createdAtFormat.getMinutes()
- // const createdAtForTable = `${year}.${month}.${day} ${hours}:${minutes} `
- // orderTable.innerHTML += `<tr>
- // <td>${counter}</td>
- // <td>${_id}</td>
- // <td>${createdAtForTable}</td>
- // <td>${total}</td>
- // </tr>`
- // counter += 1
- // summ += total
- // }
- // orderTable.innerHTML += `<tr><td colspan="3"></td><td class="tdSumm">${summ} грн</td></tr>`
- // }
- // })
- function ordersToHTML (payload) {
- main.innerHTML = ""
- let h1 = document.createElement('h1')
- h1.innerText = "История заказов"
- main.append(h1)
- let orderTable = document.createElement('table')
- main.append(orderTable)
- orderTable.classList.add('table_price')
- let orderTableBody = document.createElement('tbody')
- orderTable.append(orderTableBody)
- let firstTr = document.createElement('tr')
- orderTableBody.append(firstTr)
- firstTr.innerHTML = `<th></th><th>Номер заказа</th><th>Дата</th><th>Сумма, грн</th>`
- let counter = 1
- let summ = 0
- let arrRevers = [...payload]
- for (let { _id, createdAt, total } of arrRevers.reverse()) {
- let createdAtFormat = new Date(+createdAt)
- let year = createdAtFormat.getFullYear()
- let month = createdAtFormat.getMonth() < 9 ? "0" + (createdAtFormat.getMonth() + 1) : createdAtFormat.getMonth() + 1
- let day = createdAtFormat.getDate() < 10 ? "0" + (createdAtFormat.getDate()) : createdAtFormat.getDate()
- let hours = createdAtFormat.getHours() < 10 ? "0" + (createdAtFormat.getHours()) : createdAtFormat.getHours()
- let minutes = createdAtFormat.getMinutes() < 10 ? "0" + (createdAtFormat.getMinutes()) : createdAtFormat.getMinutes()
- const createdAtForTable = `${year}.${month}.${day} ${hours}:${minutes} `
- orderTableBody.innerHTML += `<tr>
- <td>${counter}</td>
- <td>${_id}</td>
- <td>${createdAtForTable}</td>
- <td>${total}</td>
- </tr>`
- counter += 1
- summ += total
- }
- orderTableBody.innerHTML += `<tr><td colspan="3"></td><td class="tdSumm">${summ} грн</td></tr>`
- }
- store.subscribe(() => {
- const [, route, _id] = location.hash.split('/')
- if (route !== "orders") return
- const {status, payload, error} = store.getState().promise.OrderFind
- if (status === 'PENDING') {
- main.innerHTML = `<img src='giphy.gif'/>`
- }
- if (status === 'FULFILLED' && payload) {
- ordersToHTML (payload)
- }
- if (status === 'REJECTED') {
- main.innerHTML = `Что-то пошло не так, но мы скоро всё починим ;( \n сообщить о проблеме: <a href="mailto:mail@example.com">blablatest123@gmail.com</a>`
- }
- })
|