123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711 |
- let loginValue = "";
- let passwordValue = "";
- const authDiv = document.createElement("div");
- const noAuthDiv = document.createElement("div");
- const cartIcon = document.createElement("div");
- const loginButton = document.createElement("button");
- const registerButton = document.createElement("button");
- const nameDiv = document.createElement("div");
- const logoutButton = document.createElement("button");
- cartIcon.innerHTML = "<a href = '#/cart'>Cart</a>";
- loginButton.innerText = "Login";
- loginButton.onclick = () => {
- window.location = "#/login";
- };
- registerButton.innerText = "Register";
- registerButton.onclick = () => {
- window.location = "#/register";
- };
- logoutButton.innerText = "Logout";
- noAuthDiv.append(loginButton);
- noAuthDiv.append(registerButton);
- authDiv.append(nameDiv);
- authDiv.append(logoutButton);
- authDiv.append(cartIcon);
- cartIcon.style.marginLeft = "auto";
- authDiv.style.display = "flex";
- header.append(authDiv);
- header.append(noAuthDiv);
- const jwtDecode = (token) => {
- try {
- let payload = JSON.parse(atob(token.split(".")[1]));
- return payload;
- } catch (e) {
- console.log(e);
- }
- };
- function createStore(reducer) {
- let state = reducer(undefined, {});
- let cbs = [];
- const getState = () => state;
- const subscribe = (cb) => (cbs.push(cb), () => (cbs = cbs.filter((c) => c !== cb)));
- const dispatch = (action) => {
- if (typeof action === "function") {
- return action(dispatch, getState);
- }
- const newState = reducer(state, action);
- if (newState !== state) {
- state = newState;
- for (let cb of cbs) cb();
- }
- };
- return {
- getState,
- dispatch,
- subscribe,
- };
- }
- function cartReducer(state = {}, { type, good, count = 1 }) {
- if (!Object.keys(state).length) {
- let savedData =
- (localStorage[jwtDecode(localStorage.authToken)?.sub.login] &&
- JSON.parse(localStorage[jwtDecode(localStorage.authToken)?.sub.login])) ||
- null;
- if (savedData) {
- state = savedData?.cart || {};
- } else {
- state = {};
- }
- }
- if (count <= 0) {
- type = "CART_DELETE";
- }
- if (type === "CART_ADD") {
- return {
- ...state,
- [good["_id"]]: {
- good,
- count: good["_id"] in state ? state[good._id].count + count : count,
- },
- };
- }
- if (type === "CART_CHANGE") {
- return {
- ...state,
- [good["_id"]]: {
- good,
- count: count,
- },
- };
- }
- if (type === "CART_DELETE") {
- let { [good._id]: toRemove, ...newState } = state;
- return newState;
- }
- if (type === "CART_CLEAR") {
- return {};
- }
- return state;
- }
- function promiseReducer(state = {}, { type, name, status, payload, error }) {
- if (type === "PROMISE") {
- return {
- ...state,
- [name]: { status, payload, error },
- };
- }
- return state;
- }
- function authReducer(state, { type, token }) {
- if (state === undefined) {
- if (localStorage.authToken) {
- token = localStorage.authToken;
- type = "AUTH_LOGIN";
- state = {};
- }
- }
- if (type === "AUTH_LOGIN") {
- if (!token || !jwtDecode(token)) return {};
- localStorage.authToken = token;
- return {
- ...state,
- token: token,
- payload: jwtDecode(token),
- };
- }
- if (type === "AUTH_LOGOUT") {
- localStorage.removeItem("authToken");
- return {};
- }
- return state || {};
- }
- const combineReducers =
- (reducers) =>
- (state = {}, action) => {
- let newState = {};
- for (let [key, reducer] of Object.entries(reducers)) {
- let reducerResult = reducer(state[key], action);
- if (state[key] !== reducerResult) {
- newState = { ...newState, [key]: reducerResult };
- }
- }
- if (Object.keys(newState).length) {
- state = { ...state, ...newState };
- }
- return state;
- };
- const store = createStore(combineReducers({ auth: authReducer, promise: promiseReducer, cart: cartReducer }));
- store.subscribe(() => console.log(store.getState()));
- store.subscribe(() => {
- let {
- cart,
- auth: { payload },
- } = store.getState();
- let localStorageLoginSave = {};
- let login = payload?.sub.login || null;
- if (!login) {
- return;
- }
- if (localStorage[login]) {
- localStorageLoginSave = JSON.parse(localStorage[login]);
- if (Object.keys(cart).length === 0) {
- let { cart, ...newState } = localStorageLoginSave;
- localStorage[login] = JSON.stringify(newState);
- return;
- }
- }
- if (Object.keys(cart).length) {
- localStorage[login] = JSON.stringify({ ...localStorageLoginSave, cart });
- }
- });
- 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 = (name, promise) => async (dispatch) => {
- dispatch(actionPending(name));
- try {
- let payload = await promise;
- dispatch(actionFulfilled(name, payload));
- return payload;
- } catch (error) {
- dispatch(actionRejected(name, 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.errors) {
- throw new Error(JSON.stringify(data.errors));
- } else return Object.values(data.data)[0];
- });
- const backendURL = "http://shop-roles.asmer.fs.a-level.com.ua";
- const gql = getGQL(backendURL + "/graphql");
- const actionRootCats = () =>
- actionPromise(
- "rootCats",
- gql(`query {
- CategoryFind(query: "[{\\"parent\\":null}]"){
- _id name
- }
- }`)
- );
- const actionGoodById = (_id) =>
- actionPromise(
- "good",
- gql(
- `query GoodById($q: String){
- GoodFindOne(query: $q){
- _id name price images{
- url
- }
- }
- }`,
- { q: JSON.stringify([{ _id }]) }
- )
- );
- 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 actionOrders = () => (dispatch) =>
- dispatch(
- actionPromise(
- "orders",
- gql(`
- query orders{
- OrderFind(query:"[{}]"){
- _id total createdAt orderGoods{
- _id count price good{
- name _id price images{
- url
- }
- }
- }
- }
- }
- `)
- )
- );
- const actionNewOrder =
- (orderGoods = []) =>
- async (dispatch, getState) => {
- await dispatch(
- actionPromise(
- "newOrder",
- gql(
- `mutation newOrder($order:OrderInput){
- OrderUpsert(order:$order){
- _id total
- }
- }
- `,
- {
- order: {
- orderGoods: orderGoods,
- },
- }
- )
- )
- );
- let {
- promise: { newOrder },
- } = getState();
- if (newOrder.status === "FULFILLED") {
- dispatch(actionCartClear());
- }
- };
- const actionAuthLogin = (token) => ({
- type: "AUTH_LOGIN",
- token: token,
- });
- const actionLogin = (login, password) => async (dispatch) => {
- const token = await dispatch(
- actionPromise(
- "login",
- gql(
- `query log($login:String,$password:String){
- login(login:$login,password:$password)
- }
- `,
- {
- login: login,
- password: password,
- }
- )
- )
- );
- await dispatch(actionAuthLogin(token));
- window.location = "#/home";
- };
- const actionAuthLogout = () => ({ type: "AUTH_LOGOUT" });
- const actionLogout = () => async (dispatch) => {
- await dispatch(actionAuthLogout());
- await dispatch(actionCartClear());
- window.location = "#/home";
- };
- const actionRegister = (login, password) => async (dispatch) => {
- await dispatch(
- actionPromise(
- "register",
- gql(
- `mutation register($login:String,$password:String){
- UserUpsert(user:{login:$login,password:$password}){
- _id login
- }
- }`,
- {
- login: login,
- password: password,
- }
- )
- )
- );
- await dispatch(actionLogin(loginValue, passwordValue));
- };
- 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" });
- store.dispatch(actionRootCats());
- // store.dispatch(actionCartAdd({ _id: "пиво", name: "одеколонь", price: 30 }));
- // //{пиво: {count: 1, good: {_id: 'пиво', name: 'одеколонь', price: 30}}}
- // store.dispatch(actionCartAdd({ _id: "чипсы", name: "одеколонь", price: 30 }));
- // //{пиво: {count: 1, good: {_id: 'пиво', name: 'одеколонь', price: 30}},
- // // чипсы: {count: 1, good: {_id: 'чипсы', name: 'огурец с молоком', price: 50}},
- // //}
- // store.dispatch(actionCartAdd({ _id: "пиво", name: "одеколонь", price: 30 })); //count: 2
- // //{пиво: {count: 2, good: {_id: 'пиво', name: 'одеколонь', price: 30}},
- // // чипсы: {count: 1, good: {_id: 'чипсы', name: 'огурец с молоком', price: 50}},
- // //}
- // store.dispatch(actionCartChange({ _id: "чипсы", name: "одеколонь", price: 30 }, 2));
- // //{пиво: {count: 2, good: {_id: 'пиво', name: 'одеколонь', price: 30}},
- // // чипсы: {count: 2, good: {_id: 'чипсы', name: 'огурец с молоком', price: 50}},
- // //}
- // store.dispatch(actionCartDelete({ _id: "пиво", name: "одеколонь", price: 30 }));
- // //{чипсы: {count: 2, good: {_id: 'чипсы', name: 'огурец с молоком', price: 50}},
- // //}
- // store.dispatch(actionCartClear()); // {}
- logoutButton.onclick = () => store.dispatch(actionLogout());
- store.subscribe(() => {
- const {
- auth: { token, payload },
- } = store.getState();
- if (token) {
- nameDiv.innerHTML = `<a href = "#/dashboard">${payload.sub.login}</a>`;
- authDiv.style.display = "flex";
- noAuthDiv.style.display = "none";
- } else {
- authDiv.style.display = "none";
- noAuthDiv.style.display = "block";
- }
- });
- store.subscribe(() => {
- const {
- promise: { rootCats },
- } = store.getState();
- if (rootCats?.payload) {
- aside.innerHTML = "";
- for (const { _id, name } of rootCats?.payload) {
- const link = document.createElement("a");
- link.href = `#/category/${_id}`;
- link.innerText = name;
- aside.append(link);
- }
- }
- });
- const updateCart = () => {
- let {
- cart,
- auth: { token },
- } = store.getState();
- if (!token) {
- return;
- }
- let orderGoods = [];
- Object.entries(cart).map(([index, order]) => {
- orderGoods[orderGoods.length] = { count: order.count, good: { _id: index } };
- });
- console.log(orderGoods);
- main.innerHTML = "";
- let orderList = document.createElement("div");
- let clearButton = document.createElement("button");
- let sum = 0;
- let sumField = document.createElement("div");
- let submitButton = document.createElement("button");
- Object.entries(cart).length ? (submitButton.disabled = false) : (submitButton.disabled = true);
- submitButton.innerText = "Buy";
- submitButton.style.display = "block";
- submitButton.style.marginLeft = "auto";
- submitButton.style.marginTop = "10px";
- sumField.style.marginLeft = "100%";
- sumField.style.fontWeight = "bold";
- clearButton.innerHTML = "Clear cart";
- clearButton.style.display = "block";
- clearButton.style.marginLeft = "auto";
- Object.keys(cart).length > 0 ? (clearButton.disabled = false) : (clearButton.disabled = true);
- Object.keys(cart).length > 0 ? (sumField.style.display = "block") : (sumField.style.display = "none");
- for (let [id, order] of Object.entries(cart)) {
- let { name, images, price } = order.good;
- let orderWrapper = document.createElement("div");
- orderWrapper.style.display = "flex";
- orderWrapper.style.width = "100%";
- let goodBox = document.createElement("div");
- goodBox.style = "display:flex; flex:1;";
- let countBox = document.createElement("div");
- let addButton = document.createElement("button");
- addButton.innerHTML = "+";
- let removeButton = document.createElement("button");
- removeButton.innerHTML = "-";
- let deleteButton = document.createElement("button");
- deleteButton.innerHTML = "X";
- let countField = document.createElement("span");
- countField.innerHTML = order.count;
- countField.innerHTML = order.count;
- goodBox.innerHTML = `
- <div >
- <div><img style="height:100px;" src = "${backendURL}/${images ? images[0].url : ""}"></div>
- <div><h3>${name}</h3></div>
- <div>${order.count} * ${price} = ${+order.count * +price}</div>
- </div>
- `;
- sum += +order.count * +price;
- countBox.append(addButton);
- countBox.append(countField);
- countBox.append(removeButton);
- countBox.append(deleteButton);
- orderWrapper.append(goodBox, countBox);
- addButton.onclick = () => {
- store.dispatch(actionCartChange(order.good, ++order.count));
- };
- removeButton.onclick = () => {
- store.dispatch(actionCartChange(order.good, --order.count));
- };
- deleteButton.onclick = () => {
- store.dispatch(actionCartDelete(order.good));
- };
- orderList.append(orderWrapper);
- }
- clearButton.onclick = () => store.dispatch(actionCartClear());
- submitButton.onclick = () => store.dispatch(actionNewOrder(orderGoods));
- sumField.innerText = sum;
- main.append(orderList);
- main.append(sumField);
- main.append(clearButton);
- main.append(submitButton);
- };
- window.onhashchange = () => {
- const [, route, _id] = location.hash.split("/");
- const routes = {
- home() {
- main.innerHTML = "Контент";
- },
- category() {
- store.dispatch(actionCatById(_id));
- },
- good() {
- //задиспатчить actionGoodById
- store.dispatch(actionGoodById(_id));
- },
- login() {
- const loginInput = document.createElement("input");
- const passwordInput = document.createElement("input");
- const loginSubmitButton = document.createElement("button");
- loginSubmitButton.innerHTML = "Login";
- main.innerHTML = "";
- main.append(loginInput);
- main.append(passwordInput);
- main.append(loginSubmitButton);
- loginSubmitButton.onclick = () => {
- loginValue = loginInput.value;
- passwordValue = passwordInput.value;
- store.dispatch(actionLogin(loginValue, passwordValue));
- };
- },
- register() {
- const loginInput = document.createElement("input");
- const passwordInput = document.createElement("input");
- const registerSubmitButton = document.createElement("button");
- registerSubmitButton.innerHTML = "Register";
- main.innerHTML = "";
- main.append(loginInput);
- main.append(passwordInput);
- main.append(registerSubmitButton);
- registerSubmitButton.onclick = () => {
- loginValue = loginInput.value;
- passwordValue = passwordInput.value;
- store.dispatch(actionRegister(loginValue, passwordValue));
- };
- },
- async dashboard() {
- await store.dispatch(actionOrders());
- let {
- promise: { orders },
- auth: { token },
- } = store.getState();
- if (!token || orders.status === "REJECTED") {
- return;
- }
- main.innerHTML = "";
- let orderList = document.createElement("div");
- for (let order of orders.payload) {
- let orderBlock = document.createElement("div");
- let orderGoodsBlock = document.createElement("div");
- let orderHeaderBlock = document.createElement("div");
- let orderSumBlock = document.createElement("div");
- let createdAtBlock = document.createElement("div");
- createdAtBlock.innerHTML = ("" + new Date(+order.createdAt)).slice(0, 25);
- for (let orderGood of order.orderGoods) {
- let {
- count,
- good: { name, price, images },
- } = orderGood;
- let goodBlock = document.createElement("div");
- goodBlock.innerHTML = `
- <div style = "width:30%;">${name}</div><div style = "width:40%;"><img src ="${backendURL}/${
- images[0].url
- }" style="height:100px"></div><div style = "width:30%;">${count}x${price} = ${
- +price * +count
- }</div>
- `;
- goodBlock.style.display = "flex";
- goodBlock.style.width = "100%";
- goodBlock.style.marginTop = "7px";
- goodBlock.style.background = "#EAEAEA";
- orderGoodsBlock.append(goodBlock);
- }
- orderSumBlock.innerHTML = `<b>TOTAL</b>:${order.total}`;
- orderHeaderBlock.style.padding = "10px";
- orderHeaderBlock.style.display = "flex";
- orderHeaderBlock.style.justifyContent = "space-between";
- orderHeaderBlock.append(createdAtBlock);
- orderHeaderBlock.append(orderSumBlock);
- orderBlock.append(orderHeaderBlock);
- orderBlock.append(orderGoodsBlock);
- orderGoodsBlock.style.marginTop = "10px";
- orderBlock.style.marginTop = "20px";
- orderBlock.style.borderBottom = "1px solid black";
- orderBlock.style.padding = "10px";
- orderList.append(orderBlock);
- }
- main.append(orderList);
- },
- cart() {
- updateCart();
- },
- };
- if (route in routes) routes[route]();
- };
- store.subscribe(() => {
- let { cart } = store.getState();
- const [, route, _id] = location.hash.split("/");
- if (cart && route === "cart") {
- updateCart();
- }
- });
- window.onhashchange();
- store.subscribe(() => {
- const {
- promise: { catById },
- } = store.getState();
- const [, route, _id] = location.hash.split("/");
- if (catById?.payload && route === "category") {
- const { name } = catById.payload;
- main.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}">${name}</a>
- `;
- main.append(card);
- }
- }
- });
- store.subscribe(() => {
- const {
- promise: { good },
- auth: { token },
- } = store.getState();
- const [, route, _id] = location.hash.split("/");
- if (good?.payload && route === "good") {
- const { name, price, images } = good.payload;
- main.innerHTML = `<h1>${name}</h1>`;
- const card = document.createElement("div");
- card.innerHTML = `<h2>${name}</h2>
- <img src="${backendURL}/${images[0].url}" />
- <strong>${price}</strong>
- `;
- if (token) {
- let buyButton = document.createElement("button");
- buyButton.innerHTML = "Купить";
- buyButton.onclick = () => store.dispatch(actionCartAdd(good.payload));
- card.append(buyButton);
- }
- main.append(card);
- }
- });
|