From 58af1879f7ba33dac353304907d95f4669ecda35 Mon Sep 17 00:00:00 2001 From: "Dzmitry_Tamashevich@epam.com" Date: Tue, 24 Nov 2020 22:40:15 +0300 Subject: [PATCH] clean up things --- media-store/app/src/api/axiosInstance.js | 2 +- .../app/src/api/responseErrorInterceptor.js | 14 +-- .../app/src/components/CurrentPageHeader.js | 30 ----- media-store/app/src/components/Header.js | 28 +++-- media-store/app/src/components/Router.js | 40 +++---- media-store/app/src/hocs/withRestrictions.js | 13 +-- media-store/app/src/hooks/useErrors.js | 8 -- media-store/app/src/pages/ErrorPage.js | 35 +++--- .../src/pages/{invoice => }/InvoicePage.js | 50 +++++--- .../app/src/pages/{login => }/Login.js | 10 +- .../pages/{manage-store => }/ManageStore.js | 15 ++- .../MyInvoices.js => MyInvoicesPage.js} | 18 ++- .../app/src/pages/{person => }/PersonPage.js | 16 ++- .../app/src/pages/{tracks => }/TracksPage.css | 0 .../app/src/pages/{tracks => }/TracksPage.js | 50 ++++---- .../app/src/pages/invoice/InvoicePage.css | 4 - .../src/pages/manage-store/ManageStore.css | 0 .../tracks/{Track.css => ManagedTrack.css} | 0 .../app/src/pages/tracks/ManagedTrack.js | 42 +++++++ media-store/app/src/pages/tracks/Track.js | 108 ++++-------------- .../app/src/pages/tracks/TrackCardBody.js | 33 ++++++ media-store/app/src/util/constants.js | 6 + media-store/package.json | 8 +- media-store/srv/user-service.js | 4 +- 24 files changed, 256 insertions(+), 278 deletions(-) delete mode 100644 media-store/app/src/components/CurrentPageHeader.js rename media-store/app/src/pages/{invoice => }/InvoicePage.js (59%) rename media-store/app/src/pages/{login => }/Login.js (89%) rename media-store/app/src/pages/{manage-store => }/ManageStore.js (86%) rename media-store/app/src/pages/{person/MyInvoices.js => MyInvoicesPage.js} (91%) rename media-store/app/src/pages/{person => }/PersonPage.js (85%) rename media-store/app/src/pages/{tracks => }/TracksPage.css (100%) rename media-store/app/src/pages/{tracks => }/TracksPage.js (81%) delete mode 100644 media-store/app/src/pages/invoice/InvoicePage.css delete mode 100644 media-store/app/src/pages/manage-store/ManageStore.css rename media-store/app/src/pages/tracks/{Track.css => ManagedTrack.css} (100%) create mode 100644 media-store/app/src/pages/tracks/ManagedTrack.js create mode 100644 media-store/app/src/pages/tracks/TrackCardBody.js diff --git a/media-store/app/src/api/axiosInstance.js b/media-store/app/src/api/axiosInstance.js index d1fc2f2c..abde261a 100644 --- a/media-store/app/src/api/axiosInstance.js +++ b/media-store/app/src/api/axiosInstance.js @@ -16,6 +16,6 @@ const locale = getLocaleFromLS(); changeUserDefaults(user); changeLocaleDefaults(locale); -// axiosInstance.interceptors.response.use(null, responseErrorInterceptor); +axiosInstance.interceptors.response.use(null, responseErrorInterceptor); export { axiosInstance, changeLocaleDefaults, changeUserDefaults }; diff --git a/media-store/app/src/api/responseErrorInterceptor.js b/media-store/app/src/api/responseErrorInterceptor.js index ba68c2ab..40824e4d 100644 --- a/media-store/app/src/api/responseErrorInterceptor.js +++ b/media-store/app/src/api/responseErrorInterceptor.js @@ -8,8 +8,9 @@ let subscribers = []; function responseErrorInterceptor(error) { const originalRequest = error.config; + const user = getUserFromLS(); - if (error.response && error.response.status === 401) { + if (error.response && error.response.status === 401 && !!user) { if (originalRequest.url === "users/login") { return Promise.reject(error); } @@ -26,21 +27,18 @@ function responseErrorInterceptor(error) { if (!isRefreshing) { isRefreshing = true; - refreshTokens(getUserFromLS().refreshToken) + refreshTokens(user.refreshToken) .then((response) => { emitter.emit("UPDATE_USER", response.data); subscribers.forEach((request) => request.resolve(response.data.accessToken) ); - }) - .catch(() => { - subscribers.forEach((request) => request.reject(error)); - }) - .finally(() => { subscribers = []; isRefreshing = false; + }) + .catch(() => { + emitter.emit("UPDATE_USER", undefined); }); - return; } // holding requests which should be sended after users/refreshTokens complete diff --git a/media-store/app/src/components/CurrentPageHeader.js b/media-store/app/src/components/CurrentPageHeader.js deleted file mode 100644 index 121987f8..00000000 --- a/media-store/app/src/components/CurrentPageHeader.js +++ /dev/null @@ -1,30 +0,0 @@ -import React from "react"; -import { Breadcrumb, Spin } from "antd"; -import { useLocation } from "react-router-dom"; -import { useAppState } from "../hooks/useAppState"; - -const names = { - "/": "Browse / Tracks", - "/person": "Profile", - "/login": "Login form", - "/invoice": "Requested items", - "/manage": "Manage store", -}; - -const CurrentPageHeader = () => { - const location = useLocation(); - const { loading } = useAppState(); - - return ( - - - {names[location.pathname]} - {loading && } - - - ); -}; - -export { CurrentPageHeader }; diff --git a/media-store/app/src/components/Header.js b/media-store/app/src/components/Header.js index abf7ccc0..266c1daf 100644 --- a/media-store/app/src/components/Header.js +++ b/media-store/app/src/components/Header.js @@ -1,10 +1,11 @@ import React from "react"; -import { Menu, Badge } from "antd"; +import { Menu, Badge, Spin } from "antd"; import { isEmpty } from "lodash"; import { CreditCardOutlined, LogoutOutlined, LoginOutlined, + LoadingOutlined, } from "@ant-design/icons"; import { useHistory, useLocation } from "react-router-dom"; import { useAppState } from "../hooks/useAppState"; @@ -12,17 +13,18 @@ import { setLocaleToLS } from "../util/localStorageService"; import { changeLocaleDefaults } from "../api/axiosInstance"; import { emitter } from "../util/EventEmitter"; import "./Header.css"; +import { requireEmployee, requireCustomer } from "../util/constants"; const { SubMenu } = Menu; -const keys = ["/", "/person", "/login", "/manage", "/invoice"]; +const keys = ["/", "/person", "/login", "/manage", "/invoice", "/invoices"]; const AVAILABLE_LOCALES = ["en", "fr", "de"]; const RELOAD_LOCATION_NUMBER = 0; const Header = () => { const history = useHistory(); const location = useLocation(); - const { user, invoicedItems, locale, setLocale } = useAppState(); + const { user, invoicedItems, locale, setLocale, loading } = useAppState(); const currentKey = [keys.find((key) => key === location.pathname)]; const haveInvoicedItems = !isEmpty(invoicedItems); const invoicedItemsLength = invoicedItems.length; @@ -46,7 +48,6 @@ const Header = () => { const onUserLogout = () => { emitter.emit("UPDATE_USER", undefined); - history.push("/"); }; @@ -54,7 +55,8 @@ const Header = () => {
{ Profile )} - {!!user && user.roles.includes("employee") && ( + {requireCustomer(user) && ( + history.push("/invoices")}> + Invoices + + )} + {requireEmployee(user) && ( history.push("/manage")}> Manage )} + + {loading && ( + } + /> + )} + { mode="horizontal" selectedKeys={currentKey} > - {haveInvoicedItems && !!user && user.roles.includes("customer") && ( + {haveInvoicedItems && ( !!user && user.roles.includes("customer"); +import { Login } from "../pages/Login"; +import { withRestrictions } from "../hocs/withRestrictions"; +import { InvoicePage } from "../pages/InvoicePage"; +import { ManageStore } from "../pages/ManageStore"; +import { MyInvoicesPage } from "../pages/MyInvoicesPage"; +import { requireEmployee } from "../util/constants"; const RestrictedLogin = withRestrictions(Login, ({ user }) => !user); const RestrictedInvoicePage = withRestrictions( InvoicePage, - ({ user, invoicedItems }) => needCustomer({ user }) && !isEmpty(invoicedItems) -); -const RestrictedMyInvoicesSection = withRestrictedSection( - MyInvoices, - needCustomer + ({ user, invoicedItems }) => !requireEmployee(user) && !isEmpty(invoicedItems) ); const RestrictedPersonPage = withRestrictions(PersonPage, ({ user }) => !!user); -const RestrictedManageStore = withRestrictions( - ManageStore, - ({ user }) => !!user && user.roles.includes("employee") +const RestrictedManageStore = withRestrictions(ManageStore, ({ user }) => + requireEmployee(user) ); const MyRouter = () => { @@ -37,15 +27,12 @@ const MyRouter = () => {
- - } - /> + @@ -53,6 +40,9 @@ const MyRouter = () => { + + + diff --git a/media-store/app/src/hocs/withRestrictions.js b/media-store/app/src/hocs/withRestrictions.js index 1f9d0c2d..525cbae7 100644 --- a/media-store/app/src/hocs/withRestrictions.js +++ b/media-store/app/src/hocs/withRestrictions.js @@ -13,15 +13,4 @@ const withRestrictions = (Component, isUserMeetRestrictions) => { }; }; -const withRestrictedSection = (Component, isUserMeetRestrictions) => { - return (props) => { - const { user, invoicedItems } = useAppState(); - return ( - isUserMeetRestrictions({ user, invoicedItems }) && ( - - ) - ); - }; -}; - -export { withRestrictions, withRestrictedSection }; +export { withRestrictions }; diff --git a/media-store/app/src/hooks/useErrors.js b/media-store/app/src/hooks/useErrors.js index 0c9d7a8c..712ca779 100644 --- a/media-store/app/src/hooks/useErrors.js +++ b/media-store/app/src/hooks/useErrors.js @@ -1,8 +1,5 @@ import { useHistory } from "react-router-dom"; import { useAppState } from "./useAppState"; -import { emitter } from "../util/EventEmitter"; -import { message } from "antd"; -import { MESSAGE_TIMEOUT } from "../util/constants"; const useErrors = () => { const history = useHistory(); @@ -12,11 +9,6 @@ const useErrors = () => { console.error("Error", error); if (error.response) { - if (error.response.status === 401) { - emitter.emit("UPDATE_USER", undefined); - message.error("You are unauthorized, try login again", MESSAGE_TIMEOUT); - } - const { status, statusText, data } = error.response; setError({ status, diff --git a/media-store/app/src/pages/ErrorPage.js b/media-store/app/src/pages/ErrorPage.js index 584c9058..77a68af8 100644 --- a/media-store/app/src/pages/ErrorPage.js +++ b/media-store/app/src/pages/ErrorPage.js @@ -5,7 +5,7 @@ import { Result, Button } from "antd"; import { useAppState } from "../hooks/useAppState"; const ErrorPage = () => { - const { user, error, setError } = useAppState(); + const { error, setError } = useAppState(); const history = useHistory(); const onGoHome = () => { @@ -18,32 +18,33 @@ const ErrorPage = () => { history.push("/login"); }; + const goHomeButton = ( + + ); + const goLoginButton = ( + + ); + const errorResultProps = isEmpty(error) ? { status: 404, title: "Not found", subTitle: "Sorry, the page you visited does not exist.", + extra: goHomeButton, } : { - status: [404, 403, 500].includes(error.status) - ? error.status - : undefined, - title: `${error.status} ${error.statusText}`, + status: [404, 403, 500].includes(error.status) ? error.status : "error", + title: error.statusText, subTitle: error.message, + extra: + error.status === 401 ? [goHomeButton, goLoginButton] : goHomeButton, }; - return ( - - - - } - /> - ); + return ; }; export { ErrorPage }; diff --git a/media-store/app/src/pages/invoice/InvoicePage.js b/media-store/app/src/pages/InvoicePage.js similarity index 59% rename from media-store/app/src/pages/invoice/InvoicePage.js rename to media-store/app/src/pages/InvoicePage.js index 5a083281..b63efce1 100644 --- a/media-store/app/src/pages/invoice/InvoicePage.js +++ b/media-store/app/src/pages/InvoicePage.js @@ -1,12 +1,10 @@ import React from "react"; import { Table, Button, message } from "antd"; -import { useAppState } from "../../hooks/useAppState"; +import { useAppState } from "../hooks/useAppState"; import { useHistory } from "react-router-dom"; -import { invoice } from "../../api/calls"; -import { useErrors } from "../../hooks/useErrors"; -import { MESSAGE_TIMEOUT } from "../../util/constants"; - -import "./InvoicePage.css"; +import { invoice } from "../api/calls"; +import { useErrors } from "../hooks/useErrors"; +import { MESSAGE_TIMEOUT } from "../util/constants"; const columns = [ { @@ -30,7 +28,7 @@ const columns = [ const InvoicePage = () => { const history = useHistory(); const { handleError } = useErrors(); - const { invoicedItems, setInvoicedItems, setLoading } = useAppState(); + const { user, invoicedItems, setInvoicedItems, setLoading } = useAppState(); const data = invoicedItems.map(({ ID: key, ...otherProps }) => ({ key, @@ -48,7 +46,7 @@ const InvoicePage = () => { .then(() => { setInvoicedItems([]); message.success("Invoice successfully completed", MESSAGE_TIMEOUT); - history.push("/person"); + history.push("/invoices"); }) .catch(handleError) .finally(() => setLoading(false)); @@ -57,6 +55,9 @@ const InvoicePage = () => { setInvoicedItems([]); history.push("/"); }; + const goLogin = () => { + history.push("/login"); + }; return (
@@ -74,17 +75,28 @@ const InvoicePage = () => { padding: 5, }} > - - + {user ? ( + <> + + + + ) : ( +
+ + to buy selected +
+ )}
)} /> diff --git a/media-store/app/src/pages/login/Login.js b/media-store/app/src/pages/Login.js similarity index 89% rename from media-store/app/src/pages/login/Login.js rename to media-store/app/src/pages/Login.js index 9ed253f1..da856e84 100644 --- a/media-store/app/src/pages/login/Login.js +++ b/media-store/app/src/pages/Login.js @@ -1,11 +1,11 @@ import React from "react"; import { Form, Input, Button, Checkbox, message } from "antd"; -import { login } from "../../api/calls"; +import { login } from "../api/calls"; import { useHistory } from "react-router-dom"; -import { useAppState } from "../../hooks/useAppState"; -import { useErrors } from "../../hooks/useErrors"; -import { MESSAGE_TIMEOUT } from "../../util/constants"; -import { emitter } from "../../util/EventEmitter"; +import { useAppState } from "../hooks/useAppState"; +import { useErrors } from "../hooks/useErrors"; +import { MESSAGE_TIMEOUT } from "../util/constants"; +import { emitter } from "../util/EventEmitter"; const layout = { labelCol: { diff --git a/media-store/app/src/pages/manage-store/ManageStore.js b/media-store/app/src/pages/ManageStore.js similarity index 86% rename from media-store/app/src/pages/manage-store/ManageStore.js rename to media-store/app/src/pages/ManageStore.js index f0454a6b..c23c2e33 100644 --- a/media-store/app/src/pages/manage-store/ManageStore.js +++ b/media-store/app/src/pages/ManageStore.js @@ -1,13 +1,12 @@ import React, { useState, useMemo, useEffect } from "react"; import { Form, Radio, Button, message } from "antd"; -import { TrackForm } from "./TrackForm"; -import { AddArtistForm } from "./AddArtistForm"; -import { AddAlbumForm } from "./AddAlbumForm"; -import { useErrors } from "../../hooks/useErrors"; -import { useAppState } from "../../hooks/useAppState"; -import { addTrack, addArtist, addAlbum } from "../../api/calls"; -import { MESSAGE_TIMEOUT } from "../../util/constants"; -import "./ManageStore.css"; +import { TrackForm } from "./manage-store/TrackForm"; +import { AddArtistForm } from "./manage-store/AddArtistForm"; +import { AddAlbumForm } from "./manage-store/AddAlbumForm"; +import { useErrors } from "../hooks/useErrors"; +import { useAppState } from "../hooks/useAppState"; +import { addTrack, addArtist, addAlbum } from "../api/calls"; +import { MESSAGE_TIMEOUT } from "../util/constants"; const FORM_TYPES = { track: "track", diff --git a/media-store/app/src/pages/person/MyInvoices.js b/media-store/app/src/pages/MyInvoicesPage.js similarity index 91% rename from media-store/app/src/pages/person/MyInvoices.js rename to media-store/app/src/pages/MyInvoicesPage.js index 79aa6db8..a1edf62c 100644 --- a/media-store/app/src/pages/person/MyInvoices.js +++ b/media-store/app/src/pages/MyInvoicesPage.js @@ -1,10 +1,10 @@ import React, { useState, useEffect, useMemo, useCallback } from "react"; import { Button, message, Divider, Tag, Collapse, Table, Spin } from "antd"; import moment from "moment"; -import { useErrors } from "../../hooks/useErrors"; -import { useAppState } from "../../hooks/useAppState"; -import { cancelInvoice, fetchInvoices } from "../../api/calls"; -import { MESSAGE_TIMEOUT } from "../../util/constants"; +import { useErrors } from "../hooks/useErrors"; +import { useAppState } from "../hooks/useAppState"; +import { cancelInvoice, fetchInvoices } from "../api/calls"; +import { MESSAGE_TIMEOUT } from "../util/constants"; const { Panel } = Collapse; const INVOICE_STATUS = { @@ -106,7 +106,7 @@ const ExtraHeader = ({ ID, invoiceDate, status: initialStatus }) => { ); }; -const MyInvoices = () => { +const MyInvoicesPage = () => { const { handleError } = useErrors(); const { setLoading } = useAppState(); const [invoices, setInvoices] = useState([]); @@ -176,13 +176,11 @@ const MyInvoices = () => { return (
{invoiceElements && ( - <> - My invoices - {invoiceElements} - + {invoiceElements} )} + {"Pagination steel needed"}
); }; -export { MyInvoices }; +export { MyInvoicesPage }; diff --git a/media-store/app/src/pages/person/PersonPage.js b/media-store/app/src/pages/PersonPage.js similarity index 85% rename from media-store/app/src/pages/person/PersonPage.js rename to media-store/app/src/pages/PersonPage.js index ad1a590a..40284c3a 100644 --- a/media-store/app/src/pages/person/PersonPage.js +++ b/media-store/app/src/pages/PersonPage.js @@ -1,12 +1,12 @@ import React, { useState, useMemo } from "react"; import { Card, Button, message } from "antd"; import { omit } from "lodash"; -import { fetchPerson, confirmPerson } from "../../api/calls"; -import { useErrors } from "../../hooks/useErrors"; -import { useAppState } from "../../hooks/useAppState"; -import { Editable } from "../../components/Editable"; -import { MESSAGE_TIMEOUT } from "../../util/constants"; -import { useAbortableEffect } from "../../hooks/useAbortableEffect"; +import { fetchPerson, confirmPerson } from "../api/calls"; +import { useErrors } from "../hooks/useErrors"; +import { useAppState } from "../hooks/useAppState"; +import { Editable } from "../components/Editable"; +import { MESSAGE_TIMEOUT } from "../util/constants"; +import { useAbortableEffect } from "../hooks/useAbortableEffect"; const PERSON_PROP = { address: "Address ", @@ -22,7 +22,7 @@ const PERSON_PROP = { company: "Company: ", }; -const PersonPage = ({ myInvoicesSection }) => { +const PersonPage = () => { const { setLoading } = useAppState(); const { handleError } = useErrors(); const [initialPerson, setInitialPerson] = useState({}); @@ -46,7 +46,6 @@ const PersonPage = ({ myInvoicesSection }) => { fetchPerson() .then(({ data: personData }) => { personData = omit(personData, "@odata.context", "ID"); - console.log("personData", personData); if (!status.aborted) { setInitialPerson(personData); setPerson(personData); @@ -117,7 +116,6 @@ const PersonPage = ({ myInvoicesSection }) => { )} - {myInvoicesSection} ); }; diff --git a/media-store/app/src/pages/tracks/TracksPage.css b/media-store/app/src/pages/TracksPage.css similarity index 100% rename from media-store/app/src/pages/tracks/TracksPage.css rename to media-store/app/src/pages/TracksPage.css diff --git a/media-store/app/src/pages/tracks/TracksPage.js b/media-store/app/src/pages/TracksPage.js similarity index 81% rename from media-store/app/src/pages/tracks/TracksPage.js rename to media-store/app/src/pages/TracksPage.js index 73e34620..7e0c6a7a 100644 --- a/media-store/app/src/pages/tracks/TracksPage.js +++ b/media-store/app/src/pages/TracksPage.js @@ -1,12 +1,14 @@ import React, { useState } from "react"; import { debounce } from "lodash"; import { Input, Col, Row, Select, Pagination } from "antd"; -import { Track } from "./Track"; +import { Track } from "./tracks/Track"; +import { ManagedTrack } from "./tracks/ManagedTrack"; +import { useAppState } from "../hooks/useAppState"; +import { useErrors } from "../hooks/useErrors"; +import { fetchTacks, countTracks, fetchGenres } from "../api/calls"; +import { useAbortableEffect } from "../hooks/useAbortableEffect"; +import { requireEmployee } from "../util/constants"; import "./TracksPage.css"; -import { useAppState } from "../../hooks/useAppState"; -import { useErrors } from "../../hooks/useErrors"; -import { fetchTacks, countTracks, fetchGenres } from "../../api/calls"; -import { useAbortableEffect } from "../../hooks/useAbortableEffect"; let counter = 0; @@ -27,7 +29,7 @@ const renderGenres = (genres) => )); const TracksContainer = () => { - const { setLoading, invoicedItems } = useAppState(); + const { setLoading, user } = useAppState(); const { handleError } = useErrors(); const [state, setState] = useState({ tracks: [], @@ -149,29 +151,25 @@ const TracksContainer = () => { tracks: state.tracks.filter(({ ID: curID }) => curID !== ID), }); }; - const renderTracks = (tracks, invoicedItems) => - tracks.map( - ({ ID, name, composer, genre, unitPrice, alreadyOrdered, album }) => ( - - curID === ID)} - onDeleteTrack={(ID) => deleteTrack(ID)} + const renderTracks = (tracks) => { + const isEmployee = requireEmployee(user); + const TrackComponent = isEmployee ? ManagedTrack : Track; + return tracks.map((track) => { + const isAlreadyOrdered = !isEmployee && track.alreadyOrdered; + const onDeleteTrack = isEmployee && ((ID) => deleteTrack(ID)); + return ( + + - ) - ); + ); + }); + }; - const trackElements = renderTracks(state.tracks, invoicedItems); + const trackElements = renderTracks(state.tracks); const genreElements = renderGenres(state.genres); return ( diff --git a/media-store/app/src/pages/invoice/InvoicePage.css b/media-store/app/src/pages/invoice/InvoicePage.css deleted file mode 100644 index 654e4407..00000000 --- a/media-store/app/src/pages/invoice/InvoicePage.css +++ /dev/null @@ -1,4 +0,0 @@ -.ant-table-cell, -.ant-table-footer { - background: white !important; -} diff --git a/media-store/app/src/pages/manage-store/ManageStore.css b/media-store/app/src/pages/manage-store/ManageStore.css deleted file mode 100644 index e69de29b..00000000 diff --git a/media-store/app/src/pages/tracks/Track.css b/media-store/app/src/pages/tracks/ManagedTrack.css similarity index 100% rename from media-store/app/src/pages/tracks/Track.css rename to media-store/app/src/pages/tracks/ManagedTrack.css diff --git a/media-store/app/src/pages/tracks/ManagedTrack.js b/media-store/app/src/pages/tracks/ManagedTrack.js new file mode 100644 index 00000000..8beaa37c --- /dev/null +++ b/media-store/app/src/pages/tracks/ManagedTrack.js @@ -0,0 +1,42 @@ +import React, { useState, useRef } from "react"; +import { Card } from "antd"; +import { EditAction } from "./EditAction"; +import { DeleteAction } from "./DeleteAction"; +import { TrackCardBody } from "./TrackCardBody"; +import "./ManagedTrack.css"; + +const ManagedTrack = ({ initialTrack, onDeleteTrack }) => { + const trackElement = useRef(); + const [track, setTrack] = useState(initialTrack); + + return ( +
+ { + trackElement.current.style.opacity = 0; + setTimeout(() => onDeleteTrack(track.ID), 500); + }} + />, + setTrack(value)} + />, + ]} + title={track.name} + bordered={false} + > + + +
+ ); +}; + +export { ManagedTrack }; diff --git a/media-store/app/src/pages/tracks/Track.js b/media-store/app/src/pages/tracks/Track.js index 558c4e6a..ff88e565 100644 --- a/media-store/app/src/pages/tracks/Track.js +++ b/media-store/app/src/pages/tracks/Track.js @@ -2,114 +2,52 @@ import React, { useState, useRef } from "react"; import { Card, Button } from "antd"; import { PlusOutlined, MinusOutlined } from "@ant-design/icons"; import { useAppState } from "../../hooks/useAppState"; -import { withRestrictedSection } from "../../hocs/withRestrictions"; -import { EditAction } from "./EditAction"; -import { DeleteAction } from "./DeleteAction"; -import "./Track.css"; +import { TrackCardBody } from "./TrackCardBody"; -const RestrictedButton = withRestrictedSection(Button, ({ user }) => { - return !!user && user.roles.includes("customer"); -}); - -const RestrictedEditAction = withRestrictedSection( - EditAction, - ({ user }) => !!user && user.roles.includes("employee") -); -const RestrictedDeleteAction = withRestrictedSection( - DeleteAction, - ({ user }) => !!user && user.roles.includes("employee") -); - -const Track = ({ - initialTrack, - isButtonVisible, - isInvoiced: isInvoicedProp, - onDeleteTrack, -}) => { +const Track = ({ initialTrack, isAlreadyOrdered }) => { const trackElement = useRef(); const { setInvoicedItems, invoicedItems } = useAppState(); - const [isInvoiced, setIsInvoiced] = useState(isInvoicedProp); - const [track, setTrack] = useState(initialTrack); + const [isJustInvoiced, setIsJustInvoiced] = useState( + invoicedItems.find((curTrack) => curTrack.ID === initialTrack.ID) + ); const onChangedStatus = () => { - const newInvoiced = !isInvoiced; - if (newInvoiced) { + const newIsJustInvoiced = !isJustInvoiced; + if (newIsJustInvoiced) { setInvoicedItems([ ...invoicedItems, { - ID: track.ID, - name: track.name, - artist: track.album.artist.name, - albumTitle: track.album.title, - unitPrice: track.unitPrice, + ID: initialTrack.ID, + name: initialTrack.name, + artist: initialTrack.album.artist.name, + albumTitle: initialTrack.album.title, + unitPrice: initialTrack.unitPrice, }, ]); } else { setInvoicedItems( - invoicedItems.filter(({ ID: curID }) => curID !== track.ID) + invoicedItems.filter(({ ID: curID }) => curID !== initialTrack.ID) ); } - setIsInvoiced(newInvoiced); + setIsJustInvoiced(newIsJustInvoiced); }; return (
{ - trackElement.current.style.opacity = 0; - setTimeout(() => onDeleteTrack(track.ID), 500); - }} - />, - setTrack(value)} - />, + <> + {!isAlreadyOrdered && ( + + )} + , ]} - title={track.name} + title={initialTrack.name} bordered={false} > -
- Artist:{" "} - {track.album.artist.name} -
-
- Album: {track.album.title} -
-
- Genre: {track.genre.name} -
-
- {track.composer && ( - - Compositor:{" "} - {track.composer} - - )} -
-
- - Price: {track.unitPrice} - - {isButtonVisible && ( - - {isInvoiced ? : } - - )} -
+
); diff --git a/media-store/app/src/pages/tracks/TrackCardBody.js b/media-store/app/src/pages/tracks/TrackCardBody.js new file mode 100644 index 00000000..d3174e2f --- /dev/null +++ b/media-store/app/src/pages/tracks/TrackCardBody.js @@ -0,0 +1,33 @@ +import React from "react"; + +const TrackCardBody = ({ track }) => { + return ( + <> +
+ Artist:{" "} + {track.album.artist.name} +
+
+ Album: {track.album.title} +
+
+ Genre: {track.genre.name} +
+
+ {track.composer && ( + + Compositor:{" "} + {track.composer} + + )} +
+
+ + Price: {track.unitPrice} + +
+ + ); +}; + +export { TrackCardBody }; diff --git a/media-store/app/src/util/constants.js b/media-store/app/src/util/constants.js index f699d530..c844c903 100644 --- a/media-store/app/src/util/constants.js +++ b/media-store/app/src/util/constants.js @@ -6,3 +6,9 @@ export const MESSAGE_TIMEOUT = 2; // in prod mode using proxy export const API = process.env.NODE_ENV === "development" ? "http://localhost:4004/" : "api/"; + +export const requireEmployee = (user) => + !!user && user.roles.includes("employee"); + +export const requireCustomer = (user) => + !!user && user.roles.includes("customer"); diff --git a/media-store/package.json b/media-store/package.json index b7ca56bd..67157eef 100644 --- a/media-store/package.json +++ b/media-store/package.json @@ -30,11 +30,15 @@ "REFRESH_TOKEN_SECRET": "refresh-secret", "requires": { "db": { - "kind": "hana" + "kind": "sqlite", + "model": "*", + "credentials": { + "database": "mychinook.db" + } }, "auth": { "impl": "srv/auth.js" } } } -} +} \ No newline at end of file diff --git a/media-store/srv/user-service.js b/media-store/srv/user-service.js index eb305111..1fb37cce 100644 --- a/media-store/srv/user-service.js +++ b/media-store/srv/user-service.js @@ -3,8 +3,8 @@ const jwt = require("jsonwebtoken"); const bcrypt = require("bcryptjs"); const { ACCESS_TOKEN_SECRET, REFRESH_TOKEN_SECRET } = cds.env; -const ACCESS_TOKEN_EXP_IN = "10m"; -const REFRESH_TOKEN_EXPIRES_IN = "20m"; +const ACCESS_TOKEN_EXP_IN = "10s"; +const REFRESH_TOKEN_EXPIRES_IN = "16s"; const comparePasswords = async (password, hashedPassword) => { return new Promise((resolve, reject) =>