|
@@ -0,0 +1,727 @@
|
|
|
|
+
|
|
|
|
+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
|
|
|
|
+ for (let cb of cbs) cb() //и запускаем подписчиков
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return {
|
|
|
|
+ getState, //добавление функции getState в результирующий объект
|
|
|
|
+ dispatch,
|
|
|
|
+ subscribe //добавление subscribe в объект
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function jwtDecode(token) {
|
|
|
|
+ try {
|
|
|
|
+ return JSON.parse(atob(token.split('.')[1]))
|
|
|
|
+ }
|
|
|
|
+ catch (e) {
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function authReducer(state = {}, { type, token }) {
|
|
|
|
+ //{
|
|
|
|
+ // token, payload
|
|
|
|
+ //}
|
|
|
|
+
|
|
|
|
+ if (type === 'AUTH_LOGIN') {
|
|
|
|
+ //пытаемся токен раскодировать
|
|
|
|
+ const payload = jwtDecode(token)
|
|
|
|
+ if (payload) { //и если получилось
|
|
|
|
+ return {
|
|
|
|
+ token, payload //payload - раскодированный токен;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (type === 'AUTH_LOGOUT') {
|
|
|
|
+ return {}
|
|
|
|
+ }
|
|
|
|
+ return state;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function countReducer(state = { count: 0 }, { type }) {
|
|
|
|
+ if (type === "COUNT_INC") {
|
|
|
|
+ return {
|
|
|
|
+ count: state.count + 1
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (type === "COUNT_DEC") {
|
|
|
|
+ return {
|
|
|
|
+ count: state.count - 1
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return state
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function localStoreReducer(reducer, localStorageKey) {
|
|
|
|
+ function localStoredReducer(state, action) {
|
|
|
|
+ // Если state === undefined, то достать старый state из local storage
|
|
|
|
+ if (state === undefined) {
|
|
|
|
+ try {
|
|
|
|
+ return JSON.parse(localStorage[localStorageKey])
|
|
|
|
+ } catch (e) { }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ const newState = reducer(state, action)
|
|
|
|
+ // Сохранить newState в local storage
|
|
|
|
+ localStorage[localStorageKey] = JSON.stringify(newState)
|
|
|
|
+ return newState
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ return localStoredReducer
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function promiseReducer(state = {}, { type, name, status, payload, error }) {
|
|
|
|
+ ////?????
|
|
|
|
+ //ОДИН ПРОМИС:
|
|
|
|
+ //состояние: PENDING/FULFILLED/REJECTED
|
|
|
|
+ //результат
|
|
|
|
+ //ошибка:
|
|
|
|
+ //{status, payload, error}
|
|
|
|
+ //{
|
|
|
|
+ // name1:{status, payload, error}
|
|
|
|
+ // name2:{status, payload, error}
|
|
|
|
+ // name3:{status, payload, error}
|
|
|
|
+ //}
|
|
|
|
+ if (type === 'PROMISE') {
|
|
|
|
+ return {
|
|
|
|
+ ...state,
|
|
|
|
+ [name]: { status, payload, error }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return state
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const actionPending = (name) => ({
|
|
|
|
+ type: 'PROMISE',
|
|
|
|
+ status: 'PENDING',
|
|
|
|
+ name
|
|
|
|
+})
|
|
|
|
+const actionFulfilled = (name, payload) => ({
|
|
|
|
+ type: 'PROMISE',
|
|
|
|
+ status: 'FULFILLED',
|
|
|
|
+ name,
|
|
|
|
+ payload
|
|
|
|
+})
|
|
|
|
+const actionRejected = (name, error) => ({
|
|
|
|
+ type: 'PROMISE',
|
|
|
|
+ status: 'REJECTED',
|
|
|
|
+ name,
|
|
|
|
+ error
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+const actionPromise = (name, promise) =>
|
|
|
|
+ async dispatch => {
|
|
|
|
+ try {
|
|
|
|
+ dispatch(actionPending(name))
|
|
|
|
+ let payload = await promise
|
|
|
|
+ dispatch(actionFulfilled(name, payload))
|
|
|
|
+ return payload
|
|
|
|
+ }
|
|
|
|
+ catch (e) {
|
|
|
|
+ dispatch(actionRejected(name, e))
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+const delay = ms => new Promise(ok => setTimeout(() => ok(ms), ms))
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function combineReducers(reducers) { //пачку редьюсеров как объект {auth: authReducer, promise: promiseReducer}
|
|
|
|
+ function combinedReducer(combinedState = {}, action) { //combinedState - типа {auth: {...}, promise: {....}}
|
|
|
|
+ const newCombinedState = {}
|
|
|
|
+ for (const [reducerName, reducer] of Object.entries(reducers)) {
|
|
|
|
+ const newSubState = reducer(combinedState[reducerName], action)
|
|
|
|
+ if (newSubState !== combinedState[reducerName]) {
|
|
|
|
+ newCombinedState[reducerName] = newSubState
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (Object.keys(newCombinedState).length === 0) {
|
|
|
|
+ return combinedState
|
|
|
|
+ }
|
|
|
|
+ return { ...combinedState, ...newCombinedState }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return combinedReducer //нам возвращают один редьюсер, который имеет стейт вида {auth: {...стейт authReducer-а}, promise: {...стейт promiseReducer-а}}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function cartReducer(state = {}, { type, count = 1, good }) {
|
|
|
|
+ // type CART_ADD CART_REMOVE CART_CLEAR CART_DEL
|
|
|
|
+ // {
|
|
|
|
+ // id1: {count: 1, good: {name, price, images, id}}
|
|
|
|
+ // }
|
|
|
|
+ if (type === "CART_ADD") {
|
|
|
|
+ return {
|
|
|
|
+ ...state,
|
|
|
|
+ [good._id]: { count: count + (state[good._id]?.count || 0), good },
|
|
|
|
+ };
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (type === "CART_DELETE") {
|
|
|
|
+ if (state[good._id].count > 1) {
|
|
|
|
+ return {
|
|
|
|
+ ...state,
|
|
|
|
+ [good._id]: {
|
|
|
|
+ count: -count + (state[good._id]?.count || 0),
|
|
|
|
+ good,
|
|
|
|
+ },
|
|
|
|
+ };
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (state[good._id].count === 1) {
|
|
|
|
+ let { [good._id]: id1, ...newState } = state; //o4en strashnoe koldunstvo
|
|
|
|
+ //delete newState[good._id]
|
|
|
|
+ return newState;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (type === "CART_CLEAR") {
|
|
|
|
+ return {};
|
|
|
|
+ }
|
|
|
|
+ if (type === "CART_REMOVE") {
|
|
|
|
+ // let newState = {...state}
|
|
|
|
+ let { [good._id]: id1, ...newState } = state; //o4en strashnoe koldunstvo
|
|
|
|
+ //delete newState[good._id]
|
|
|
|
+ return newState;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return state;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+const backendURL = 'http://shop-roles.node.ed.asmer.org.ua/'
|
|
|
|
+//store.dispatch(actionPromise('delay1000', delay(1000)))
|
|
|
|
+//store.dispatch(actionPromise('delay3000', delay(3000)))
|
|
|
|
+
|
|
|
|
+//store.dispatch(actionPending('delay1000'))
|
|
|
|
+
|
|
|
|
+//delay(1000).then(result => store.dispatch(actionFulfilled('delay1000', result)),
|
|
|
|
+//error => store.dispatch(actionRejected('delay1000', error)))
|
|
|
|
+
|
|
|
|
+//store.dispatch(actionPending('delay3000'))
|
|
|
|
+
|
|
|
|
+//delay(3000).then(result => store.dispatch(actionFulfilled('delay3000', result)),
|
|
|
|
+//error => store.dispatch(actionRejected('delay3000', error)))
|
|
|
|
+
|
|
|
|
+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())
|
|
|
|
+ .then((data) => {
|
|
|
|
+ if (data.data) {
|
|
|
|
+ return Object.values(data.data)[0];
|
|
|
|
+ } else throw new Error(JSON.stringify(data.errors));
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+const gql = getGQL(backendURL + "graphql");
|
|
|
|
+
|
|
|
|
+// const gql = (url, query, variables) => fetch(url, {
|
|
|
|
+// method: 'POST',
|
|
|
|
+// headers: {
|
|
|
|
+// "Content-Type": "application/json",
|
|
|
|
+// Accept: "application/json",
|
|
|
|
+// },
|
|
|
|
+// body: JSON.stringify({ query, variables })
|
|
|
|
+// }).then(res => res.json())
|
|
|
|
+
|
|
|
|
+// const backendURL = 'http://shop-roles.node.ed.asmer.org.ua/graphql'
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+const actionRootCats = () =>
|
|
|
|
+ actionPromise(
|
|
|
|
+ 'rootCats',
|
|
|
|
+ gql(
|
|
|
|
+
|
|
|
|
+ `query {
|
|
|
|
+ CategoryFind(query: "[{\\"parent\\":null}]"){
|
|
|
|
+ _id name
|
|
|
|
+ }
|
|
|
|
+ }`
|
|
|
|
+ )
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+const actionCatById = (_id) => //добавить подкатегории
|
|
|
|
+ actionPromise(
|
|
|
|
+ 'catById',
|
|
|
|
+ gql(
|
|
|
|
+
|
|
|
|
+ `query catById($q: String){
|
|
|
|
+ CategoryFindOne(query: $q){
|
|
|
|
+ _id name goods {
|
|
|
|
+ _id name price images {
|
|
|
|
+ url
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }`,
|
|
|
|
+ { q: JSON.stringify([{ _id }]) }
|
|
|
|
+ )
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+const actionGoodById = (_id) =>
|
|
|
|
+ actionPromise(
|
|
|
|
+ 'goodByID',
|
|
|
|
+ gql(
|
|
|
|
+
|
|
|
|
+ `query goodByID($q:String){
|
|
|
|
+ GoodFindOne(query: $q){
|
|
|
|
+ _id
|
|
|
|
+ name
|
|
|
|
+ description
|
|
|
|
+ price
|
|
|
|
+ categories{
|
|
|
|
+ _id
|
|
|
|
+ name
|
|
|
|
+ }
|
|
|
|
+ images{
|
|
|
|
+ url
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }`,
|
|
|
|
+ { q: JSON.stringify([{ _id }]) }
|
|
|
|
+ )
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+const actionRegistr = (login, password) =>
|
|
|
|
+ actionPromise(
|
|
|
|
+ 'registr',
|
|
|
|
+ gql(
|
|
|
|
+
|
|
|
|
+ `mutation register($login:String, $password:String){
|
|
|
|
+ UserUpsert(user: {login:$login, password:$password}){
|
|
|
|
+ _id login
|
|
|
|
+ }
|
|
|
|
+ }`,
|
|
|
|
+ { login: login, password: password }
|
|
|
|
+ )
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+const actionLogin = (login, password) =>
|
|
|
|
+ actionPromise(
|
|
|
|
+ 'login',
|
|
|
|
+ gql(
|
|
|
|
+
|
|
|
|
+ `query log($login:String, $password:String){
|
|
|
|
+ login(login:$login, password:$password)
|
|
|
|
+ }`,
|
|
|
|
+ { login: login, password: password }
|
|
|
|
+ )
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ const actionOrder = () => async (dispatch, getState) => {
|
|
|
|
+ let { cart } = getState();
|
|
|
|
+ const orderGoods = Object.entries(cart).map(([_id, { count }]) => ({
|
|
|
|
+ good: { _id },
|
|
|
|
+ count,
|
|
|
|
+ }));
|
|
|
|
+
|
|
|
|
+ let result = await dispatch(
|
|
|
|
+ actionPromise(
|
|
|
|
+ "order",
|
|
|
|
+ gql(
|
|
|
|
+ `
|
|
|
|
+ mutation newOrder($order:OrderInput){
|
|
|
|
+ OrderUpsert(order:$order)
|
|
|
|
+ { _id total }
|
|
|
|
+ }
|
|
|
|
+ `,
|
|
|
|
+ { order: { orderGoods } }
|
|
|
|
+ )
|
|
|
|
+ )
|
|
|
|
+ );
|
|
|
|
+ if (result?._id) {
|
|
|
|
+ dispatch(actionCartClear());
|
|
|
|
+ document.location.hash = "#/cart/";
|
|
|
|
+ alert("Покупка успішна")
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ const orderHistory = () =>
|
|
|
|
+ actionPromise(
|
|
|
|
+ "history",
|
|
|
|
+ gql(` query OrderFind{
|
|
|
|
+ OrderFind(query:"[{}]"){
|
|
|
|
+ _id total createdAt orderGoods{
|
|
|
|
+ count good{
|
|
|
|
+ _id name price images{
|
|
|
|
+ url
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ owner{
|
|
|
|
+ _id login
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ `)
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+const actionAuthLogin = (token) =>
|
|
|
|
+ (dispatch, getState) => {
|
|
|
|
+ const oldState = getState()
|
|
|
|
+ dispatch({ type: 'AUTH_LOGIN', token })
|
|
|
|
+ const newState = getState()
|
|
|
|
+ if (oldState !== newState)
|
|
|
|
+ localStorage.authToken = token
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+const actionAuthLogout = () =>
|
|
|
|
+ dispatch => {
|
|
|
|
+ dispatch({ type: 'AUTH_LOGOUT' })
|
|
|
|
+ localStorage.removeItem('authToken')
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+const actionCartAdd = (good, count = 1) => ({
|
|
|
|
+ type: "CART_ADD",
|
|
|
|
+ good,
|
|
|
|
+ count
|
|
|
|
+});
|
|
|
|
+const actionCartChange = (good, count = 1) => ({
|
|
|
|
+ type: "CART_CHANGE",
|
|
|
|
+ good,
|
|
|
|
+ count,
|
|
|
|
+}); ///oninput меняяем полностью
|
|
|
|
+const actionCartDelete = (good) => ({
|
|
|
|
+ type: "CART_DELETE",
|
|
|
|
+ good
|
|
|
|
+});
|
|
|
|
+const actionCartClear = () => ({
|
|
|
|
+ type: "CART_CLEAR"
|
|
|
|
+});
|
|
|
|
+
|
|
|
|
+const actionFullLogin = (login, password) => async (dispatch) => {
|
|
|
|
+ let token = await dispatch(actionLogin(login, password))
|
|
|
|
+ if (token) {
|
|
|
|
+ dispatch(actionAuthLogin(token))
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const actionFullRegistr = (login, password) => async (dispatch) => {
|
|
|
|
+ try {
|
|
|
|
+ await dispatch(actionRegistr(login, password))
|
|
|
|
+ }
|
|
|
|
+ catch (e) {
|
|
|
|
+ return console.log(e)
|
|
|
|
+ }
|
|
|
|
+ await dispatch(actionFullLogin(login, password))
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const store = createStore(combineReducers({ auth: authReducer, promise: promiseReducer, cart: localStoreReducer(cartReducer, "cart") })) //не забудьте combineReducers если он у вас уже есть
|
|
|
|
+if (localStorage.authToken) {
|
|
|
|
+ store.dispatch(actionAuthLogin(localStorage.authToken))
|
|
|
|
+}
|
|
|
|
+//const store = createStore(combineReducers({promise: promiseReducer, auth: authReducer, cart: cartReducer}))
|
|
|
|
+store.subscribe(() => console.log(store.getState()))
|
|
|
|
+
|
|
|
|
+store.dispatch(actionRootCats())
|
|
|
|
+// store.dispatch(actionLogin('test456', '123123'))
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+store.subscribe(() => {
|
|
|
|
+ const { rootCats } = store.getState().promise
|
|
|
|
+ if (rootCats?.payload) {
|
|
|
|
+ aside.innerHTML = ''
|
|
|
|
+ for (let { _id, name } of rootCats?.payload) {
|
|
|
|
+ const a = document.createElement('a')
|
|
|
|
+ a.href = `#/category/${_id}`
|
|
|
|
+ a.innerHTML = name
|
|
|
|
+ aside.append(a)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+store.subscribe(() => {
|
|
|
|
+ const { catById } = store.getState().promise
|
|
|
|
+ const [, route, _id] = location.hash.split('/')
|
|
|
|
+ if (catById?.payload && route === 'category') {
|
|
|
|
+ const { name, goods, _id } = catById?.payload
|
|
|
|
+ main.innerHTML = `<h1>${name}</h1>`
|
|
|
|
+ for (let { _id, name, price, images } of goods) {
|
|
|
|
+ const cards = document.createElement("div")
|
|
|
|
+ cards.innerHTML = `<h2>${name}</h2>
|
|
|
|
+ <img src="${backendURL}/${images[0].url}"/>
|
|
|
|
+ <strong>Ціна ${price} грн</strong>
|
|
|
|
+ <a href="#/good/${_id}">Перейти</a> `;
|
|
|
|
+ main.append(cards);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ // const a = document.createElement('a')
|
|
|
|
+ // const p = document.createElement('p')
|
|
|
|
+ // p.href = `#/good/${_id}`
|
|
|
|
+ // a.href = `#/good/${_id}`
|
|
|
|
+ // a.innerHTML = name
|
|
|
|
+ // p.innerHTML = price
|
|
|
|
+ // main.append(a)
|
|
|
|
+ // main.append(p)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+store.subscribe(() => {
|
|
|
|
+ const { goodByID } = store.getState().promise
|
|
|
|
+ const [, route, _id] = location.hash.split('/')
|
|
|
|
+ if (goodByID?.payload && route === 'good') {
|
|
|
|
+ main.innerHTML = ""
|
|
|
|
+ const { name, images, price, description } = goodByID?.payload
|
|
|
|
+ // main.innerHTML = `<h1>${name}</h1> Продукт`
|
|
|
|
+ const cards = document.createElement("div")
|
|
|
|
+ cards.innerHTML = `<h2>${name}</h2>
|
|
|
|
+ <img src="${backendURL}/${images[0].url}"/>
|
|
|
|
+ <strong> Ціна ${price} грн</strong>
|
|
|
|
+ <button id='buy'> Придбати</button>
|
|
|
|
+ <p>${description}</p>`;
|
|
|
|
+ main.append(cards)
|
|
|
|
+ cards.style.marginTop = "10px"
|
|
|
|
+ var btn = document.getElementById('buy')
|
|
|
|
+ btn.onclick = () => {
|
|
|
|
+ store.dispatch(actionCartAdd(goodByID.payload))
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+const bPopupContent = document.createElement("div");
|
|
|
|
+const obertkaDlyaTovara = document.createElement("div")
|
|
|
|
+
|
|
|
|
+const all = document.createElement('h2')
|
|
|
|
+const checkout = document.createElement("button")
|
|
|
|
+const clearToCart = document.createElement("button")
|
|
|
|
+store.subscribe(() => {
|
|
|
|
+ obertkaDlyaTovara.innerHTML = ""
|
|
|
|
+ const cartById = store.getState().cart
|
|
|
|
+ let productCount = 0;
|
|
|
|
+ let productPrice = 0
|
|
|
|
+ for (let gPC of Object.values(cartById)) {
|
|
|
|
+ const { good,count } = gPC
|
|
|
|
+ productCount += count
|
|
|
|
+ productPrice += good.price * count
|
|
|
|
+ const tovar = document.createElement("div")
|
|
|
|
+ tovar.id = "tovar"
|
|
|
|
+ tovar.style.border = "3px solid blue"
|
|
|
|
+ tovar.style.marginTop = "10px"
|
|
|
|
+ const name = document.createElement('h1')
|
|
|
|
+ const price = document.createElement('h3')
|
|
|
|
+ const countById = document.createElement('p')
|
|
|
|
+ const divDlyaKnopok = document.createElement("div")
|
|
|
|
+ const plus = document.createElement("button")
|
|
|
|
+ const minus = document.createElement("button")
|
|
|
|
+ plus.innerText = "+"
|
|
|
|
+ minus.innerText = "-"
|
|
|
|
+ tovar.append(name)
|
|
|
|
+ tovar.append(price)
|
|
|
|
+ tovar.append(countById)
|
|
|
|
+ divDlyaKnopok.append(plus)
|
|
|
|
+ divDlyaKnopok.append(minus)
|
|
|
|
+ tovar.append(divDlyaKnopok)
|
|
|
|
+ name.innerHTML = good.name
|
|
|
|
+ price.innerHTML = good.price
|
|
|
|
+ countById.innerHTML = count
|
|
|
|
+ obertkaDlyaTovara.append(tovar)
|
|
|
|
+ bPopupContent.append(obertkaDlyaTovara)
|
|
|
|
+
|
|
|
|
+ plus.onclick = () => {
|
|
|
|
+ store.dispatch(actionCartAdd(good))
|
|
|
|
+ }
|
|
|
|
+ minus.onclick = () => {
|
|
|
|
+ store.dispatch(actionCartDelete(good))
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ clearToCart.id = "clearToCart"
|
|
|
|
+ clearToCart.innerHTML = "Очистити кошик"
|
|
|
|
+ clearToCart.style.margin = "0 auto"
|
|
|
|
+ clearToCart.style.marginBottom = "20px"
|
|
|
|
+ clearToCart.style.background = "blue"
|
|
|
|
+ clearToCart.style.color = "yellow"
|
|
|
|
+ bPopupContent.append(clearToCart)
|
|
|
|
+ checkout.id = "checkout"
|
|
|
|
+ checkout.innerHTML = "Оформити замовлення"
|
|
|
|
+ checkout.style.margin = "0 auto"
|
|
|
|
+ checkout.style.background = "blue"
|
|
|
|
+ checkout.style.color = "yellow"
|
|
|
|
+ bPopupContent.append(checkout)
|
|
|
|
+ all.id = "all"
|
|
|
|
+ all.innerHTML = "Всього: " + productPrice
|
|
|
|
+ bPopupContent.append(all)
|
|
|
|
+ all.style.marginLeft = "90%"
|
|
|
|
+ clearToCart.onclick = () => {
|
|
|
|
+ all.innerHTML = " "
|
|
|
|
+ store.dispatch(actionCartClear())
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ checkout.onclick = () => {
|
|
|
|
+ all.innerHTML = " "
|
|
|
|
+ store.dispatch(actionOrder());
|
|
|
|
+ store.dispatch(orderHistory());
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+store.subscribe(() => {
|
|
|
|
+ batton.onclick = () => {
|
|
|
|
+ store.dispatch(actionFullLogin(login.value, password.value))
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ battonchik.onclick = () => {
|
|
|
|
+ store.dispatch(actionFullRegistr(login.value, password.value))
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ battonSMakom.onclick = () => {
|
|
|
|
+ store.dispatch(actionAuthLogout())
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ const payload = store.getState().auth.token;
|
|
|
|
+ if (payload) {
|
|
|
|
+ korzina.style.display = "block"
|
|
|
|
+ login.style.display = "none"
|
|
|
|
+ password.style.display = "none"
|
|
|
|
+ batton.style.display = "none"
|
|
|
|
+ battonchik.style.display = "none"
|
|
|
|
+ battonSMakom.style.display = "block"
|
|
|
|
+ accaunt.style.display = "block"
|
|
|
|
+ accaunt.innerText = jwtDecode(payload).sub.login;
|
|
|
|
+ purchaseHistory.style.display = "block"
|
|
|
|
+
|
|
|
|
+ } else {
|
|
|
|
+ korzina.style.display = "none"
|
|
|
|
+ battonSMakom.style.display = "none"
|
|
|
|
+ login.style.display = "block"
|
|
|
|
+ password.style.display = "block"
|
|
|
|
+ batton.style.display = "block"
|
|
|
|
+ battonchik.style.display = "block"
|
|
|
|
+ accaunt.style.display = "none"
|
|
|
|
+ purchaseHistory.style.display = "none"
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+})
|
|
|
|
+store.dispatch(orderHistory());
|
|
|
|
+const h2 = document.createElement("h2")
|
|
|
|
+store.subscribe(() => {
|
|
|
|
+ const { history } = store.getState().promise;
|
|
|
|
+ const [, route] = location.hash.split("/");
|
|
|
|
+ purchaseHistory.onclick = () => {
|
|
|
|
+ const bPopup = document.createElement("div");
|
|
|
|
+ const bPopupContent = document.createElement("div");
|
|
|
|
+ bPopup.id = "b-popup";
|
|
|
|
+ bPopup.className = "b-popup";
|
|
|
|
+ bPopupContent.className = "b-popup-content b-poput-container-flex";
|
|
|
|
+ header.append(bPopup);
|
|
|
|
+ bPopup.append(bPopupContent);
|
|
|
|
+ const buttonCloseCart = document.createElement("button");
|
|
|
|
+ buttonCloseCart.innerText = "×";
|
|
|
|
+ buttonCloseCart.id = "buttonCloseCartId";
|
|
|
|
+ bPopupContent.append(buttonCloseCart);
|
|
|
|
+ buttonCloseCart.onclick = () => {
|
|
|
|
+ var parent = document.getElementById("header");
|
|
|
|
+ var child = document.getElementById("b-popup");
|
|
|
|
+ parent.removeChild(child);
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ for (let [key, value] of Object.entries(history.payload)) {
|
|
|
|
+ const { _id, createdAt, total, orderGoods } = value;
|
|
|
|
+ const h2 = document.createElement("h2");
|
|
|
|
+ h2.className = "h2History"
|
|
|
|
+ const dateOfOrder = new Date(+createdAt);
|
|
|
|
+ h2.innerHTML = `${dateOfOrder.toLocaleDateString()} ${dateOfOrder.toLocaleTimeString()}
|
|
|
|
+ Order ID: ${_id} от , c ${orderGoods.length} goods worth: ${total}`;
|
|
|
|
+ bPopupContent.append(h2);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (Object.keys(history.payload).length == 0) {
|
|
|
|
+ const p = document.createElement("p");
|
|
|
|
+ p.innerHTML = "<p>Ще немає покупок</p>";
|
|
|
|
+ card.append(p);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+});
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+const buttonCloseCart = document.createElement("button");
|
|
|
|
+buttonCloseCart.innerText = `×`;
|
|
|
|
+buttonCloseCart.id = "buttonCloseCartId";
|
|
|
|
+bPopupContent.append(buttonCloseCart);
|
|
|
|
+
|
|
|
|
+buttonCloseCart.onclick = () => {
|
|
|
|
+ var parent = document.getElementById("header");
|
|
|
|
+ var child = document.getElementById("b-popup");
|
|
|
|
+ parent.removeChild(child);
|
|
|
|
+};
|
|
|
|
+function bPopupCreate() {
|
|
|
|
+ const bPopup = document.createElement("div");
|
|
|
|
+ bPopup.id = "b-popup";
|
|
|
|
+ bPopup.className = "b-popup";
|
|
|
|
+ bPopupContent.className = "b-popup-content b-poput-container-flex";
|
|
|
|
+ header.append(bPopup);
|
|
|
|
+ bPopup.append(bPopupContent);
|
|
|
|
+}
|
|
|
|
+korzina.onclick = () => {
|
|
|
|
+ bPopupCreate()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+window.onhashchange = () => {
|
|
|
|
+ const [, route, _id] = location.hash.split('/')
|
|
|
|
+ console.log(route, _id)
|
|
|
|
+ const routes = {
|
|
|
|
+ category() {
|
|
|
|
+ store.dispatch(actionCatById(_id))
|
|
|
|
+ },
|
|
|
|
+ good() {
|
|
|
|
+ store.dispatch(actionGoodById(_id))
|
|
|
|
+ },
|
|
|
|
+ dashboard() {
|
|
|
|
+ store.dispatch(orderHistory());
|
|
|
|
+ },
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (route in routes) {
|
|
|
|
+ routes[route]()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+window.onhashchange()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|