diff --git a/media-store/README.md b/media-store/README.md index a75fab77..e93c0d68 100644 --- a/media-store/README.md +++ b/media-store/README.md @@ -4,18 +4,18 @@ Welcome to your new project. It contains these folders and files, following our recommended project layout: -| File or Folder | Purpose | -| -------------- | ------------------------------------ | -| `app/` | will contain compiled front bundles | -| `app-src/` | contains frontend app on react | -| `deployers/` | contains deployment staff | -| `db/` | your domain models and data go here | -| `srv/` | your service models and code go here | -| `test/` | your services tests | -| `package.json` | project metadata and configuration | -| `mta.yaml` | deployment config | -| `readme.md` | this getting started guide | -| `server.js` | initial server set up | +| File or Folder | Purpose | +|------------------|--------------------------------------| +| `app/` | will contain compiled front bundles | +| `app/react/` | contains frontend app on react | +| `app/deployers/` | contains deployment staff | +| `db/` | your domain models and data go here | +| `srv/` | your service models and code go here | +| `test/` | your services tests | +| `package.json` | project metadata and configuration | +| `mta.yaml` | deployment config | +| `readme.md` | this getting started guide | +| `server.js` | initial server set up | ## Development @@ -31,7 +31,7 @@ npm run deploy cds watch ``` -- Open `app-src` folder and run next commands. This will install dependencies and run frontend src files watcher. When you will change src files your bundles in app directory will re-compiled. Now you can enjoy development: +- Open `app/react` folder and run next commands. This will install dependencies and run frontend src files watcher. When you will change src files your bundles in app directory will re-compiled. Now you can enjoy development: ```json npm install @@ -62,14 +62,14 @@ npm run watch cf login ``` -- Open `app-src` folder and run the following commands. This will create frontend production bundles in app subfolder: +- Open `app/react` folder and run the following commands. This will create frontend production bundles in app subfolder: ```json npm install npm run build ``` -- Clean up deployers/html5Deployer/resources folder from the previous frontend build +- Clean up app/deployers/html5Deployer/resources folder from the previous frontend build - From root directory run: diff --git a/media-store/app-src/.babelrc b/media-store/app-src/.babelrc deleted file mode 100644 index d3472902..00000000 --- a/media-store/app-src/.babelrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "presets": ["@babel/preset-react", "@babel/preset-env"], - "plugins": ["@babel/plugin-transform-runtime", "babel-plugin-syntax-dynamic-import"] -} - \ No newline at end of file diff --git a/media-store/app-src/.eslintrc.json b/media-store/app-src/.eslintrc.json deleted file mode 100644 index 1dfa1b45..00000000 --- a/media-store/app-src/.eslintrc.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "env": { - "browser": true, - "es2020": true - }, - "extends": ["plugin:react/recommended", "airbnb", "prettier"], - "parserOptions": { - "ecmaFeatures": { - "jsx": true - }, - "ecmaVersion": 11, - "sourceType": "module" - }, - "plugins": ["react", "prettier"], - "rules": { - "prettier/prettier": ["error", { "parser": "flow", "endOfLine": "auto" }], - "linebreak-style": [0, "error", "windows"], - "import/prefer-default-export": "off", - "no-shadow": "off", - "react/forbid-prop-types": "off", - "no-alert": "off", - "jsx-a11y/label-has-associated-control": [ - "error", - { - "required": { - "some": ["nesting", "id"] - } - } - ], - "jsx-a11y/label-has-for": [ - "error", - { - "required": { - "some": ["nesting", "id"] - } - } - ], - "react/jsx-props-no-spreading": "off", // props spreading, - "no-console": "off", - "consistent-return": "off", - "prefer-destructuring": "off" - } -} diff --git a/media-store/app-src/.gitignore b/media-store/app-src/.gitignore deleted file mode 100644 index 4d29575d..00000000 --- a/media-store/app-src/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/media-store/app-src/.prettierrc b/media-store/app-src/.prettierrc deleted file mode 100644 index 5ac85e27..00000000 --- a/media-store/app-src/.prettierrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "printWidth": 100, - "singleQuote": true -} diff --git a/media-store/app-src/.vscode/launch.json b/media-store/app-src/.vscode/launch.json deleted file mode 100644 index d4e0b5d5..00000000 --- a/media-store/app-src/.vscode/launch.json +++ /dev/null @@ -1,13 +0,0 @@ - -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Chrome", - "type": "chrome", - "request": "launch", - "url": "http://localhost:3000", - "webRoot": "${workspaceRoot}/src" - } - ] -} \ No newline at end of file diff --git a/media-store/app-src/README.md b/media-store/app-src/README.md deleted file mode 100644 index 269c0546..00000000 --- a/media-store/app-src/README.md +++ /dev/null @@ -1 +0,0 @@ -"# Media store UI" diff --git a/media-store/app-src/package.json b/media-store/app-src/package.json deleted file mode 100644 index 457556aa..00000000 --- a/media-store/app-src/package.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "name": "mediastore", - "version": "0.1.0", - "private": false, - "scripts": { - "start": "./node_modules/.bin/webpack-dev-server --config ./webpack/webpack-dev-server.js", - "watch": "./node_modules/.bin/webpack -w --config ./webpack/webpack.dev.js", - "build:dev": "./node_modules/.bin/webpack --config ./webpack/webpack.dev.js", - "build:prod": "./node_modules/.bin/webpack --config ./webpack/webpack.prod.js", - "lint": "./node_modules/.bin/eslint" - }, - "dependencies": { - "@testing-library/jest-dom": "^4.2.4", - "@testing-library/react": "^9.3.2", - "@testing-library/user-event": "^7.1.2", - "@umijs/hooks": "^1.9.3", - "antd": "^4.8.2", - "@ant-design/icons": "4.3.0", - "axios": "^0.20.0", - "clean-webpack-plugin": "^3.0.0", - "copy-webpack-plugin": "^6.3.2", - "css-minimizer-webpack-plugin": "^1.1.5", - "events": "^3.2.0", - "html-webpack-plugin": "^4.5.0", - "lodash": "^4.17.20", - "mini-css-extract-plugin": "^1.3.1", - "moment": "^2.29.1", - "prop-types": "^15.7.2", - "react": "^16.14.0", - "react-dev-utils": "^11.0.1", - "react-dom": "^16.14.0", - "react-router-dom": "^5.2.0", - "terser-webpack-plugin": "^5.0.3", - "webpack": "5.8.0", - "webpack-dev-server": "^3.11.0", - "webpack-merge": "^5.4.0" - }, - "devDependencies": { - "@babel/core": "^7.12.9", - "@babel/plugin-transform-runtime": "^7.12.1", - "@babel/polyfill": "^7.12.1", - "@babel/preset-env": "^7.12.7", - "@babel/preset-react": "^7.12.7", - "@babel/runtime": "^7.12.5", - "babel-loader": "^8.2.2", - "babel-plugin-syntax-dynamic-import": "^6.18.0", - "cowsay": "^1.4.0", - "css-loader": "^5.0.1", - "eslint": "^7.14.0", - "eslint-config-airbnb": "^18.2.1", - "eslint-config-prettier": "^6.15.0", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-jsx-a11y": "^6.4.1", - "eslint-plugin-prettier": "^3.1.4", - "eslint-plugin-react": "^7.21.5", - "eslint-plugin-react-hooks": "^4.2.0", - "prettier": "^2.2.1", - "style-loader": "^2.0.0", - "url-loader": "^4.1.1", - "webpack-cli": "^3.3.12" - }, - "eslintConfig": { - "extends": "react-app" - } -} diff --git a/media-store/app-src/public/index.html b/media-store/app-src/public/index.html deleted file mode 100644 index e2722955..00000000 --- a/media-store/app-src/public/index.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - React App - - - - -
- - - - \ No newline at end of file diff --git a/media-store/app-src/public/logo192.png b/media-store/app-src/public/logo192.png deleted file mode 100644 index fc44b0a3..00000000 Binary files a/media-store/app-src/public/logo192.png and /dev/null differ diff --git a/media-store/app-src/public/logo512.png b/media-store/app-src/public/logo512.png deleted file mode 100644 index a4e47a65..00000000 Binary files a/media-store/app-src/public/logo512.png and /dev/null differ diff --git a/media-store/app-src/public/manifest.json b/media-store/app-src/public/manifest.json deleted file mode 100644 index 45979ace..00000000 --- a/media-store/app-src/public/manifest.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "short_name": "React App", - "name": "Create React App Sample", - "icons": [ - { - "src": "favicon.ico", - "sizes": "64x64 32x32 24x24 16x16", - "type": "image/x-icon" - }, - { - "src": "logo192.png", - "type": "image/png", - "sizes": "192x192" - }, - { - "src": "logo512.png", - "type": "image/png", - "sizes": "512x512" - } - ], - "start_url": ".", - "display": "standalone", - "theme_color": "#000000", - "background_color": "#ffffff", - "sap.app": { - "id": "mediastore", - "applicationVersion": { - "version": "1.0.0" - } - } -} diff --git a/media-store/app-src/public/robots.txt b/media-store/app-src/public/robots.txt deleted file mode 100644 index e9e57dc4..00000000 --- a/media-store/app-src/public/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -# https://www.robotstxt.org/robotstxt.html -User-agent: * -Disallow: diff --git a/media-store/app-src/public/xs-app.json b/media-store/app-src/public/xs-app.json deleted file mode 100644 index 930c40ee..00000000 --- a/media-store/app-src/public/xs-app.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "welcomeFile": "/index.html", - "routes": [ - { - "source": "^(.*)", - "target": "$1", - "service": "html5-apps-repo-rt" - } - ] -} \ No newline at end of file diff --git a/media-store/app-src/src/App.css b/media-store/app-src/src/App.css deleted file mode 100644 index 1ec8f2fe..00000000 --- a/media-store/app-src/src/App.css +++ /dev/null @@ -1,57 +0,0 @@ -@import "~antd/dist/antd.css"; - -html { - overflow: hidden; -} -#root { - height: 100%; -} -section.ant-layout { - height: 100vh; - overflow: auto; -} - -/* Layout -*/ -.site-layout .site-layout-background { - background: #fff; -} - -.App { - text-align: center; -} - -.App-logo { - height: 40vmin; - pointer-events: none; -} - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} diff --git a/media-store/app-src/src/App.jsx b/media-store/app-src/src/App.jsx deleted file mode 100644 index d1657522..00000000 --- a/media-store/app-src/src/App.jsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import 'antd/dist/antd.css'; -import './App.css'; -import { Layout } from 'antd'; -import { MyRouter } from './components/Router'; -import { AppStateContextProvider } from './contexts/AppStateContext'; - -const App = () => { - return ( - - - - - - ); -}; - -export default App; diff --git a/media-store/app-src/src/api/axiosInstance.js b/media-store/app-src/src/api/axiosInstance.js deleted file mode 100644 index 2be83d03..00000000 --- a/media-store/app-src/src/api/axiosInstance.js +++ /dev/null @@ -1,168 +0,0 @@ -import axios from 'axios'; -import { getUserFromLS, getLocaleFromLS } from '../util/localStorageService'; -import { emitter } from '../util/EventEmitter'; - -const TIMEOUT = 2000; -const RETRY_COUNT = 3; - -/** - * This is axios instance - */ -const axiosInstance = axios.create({ - baseURL: process.env.SERVICE_URL, - timeout: TIMEOUT, - retryDelay: TIMEOUT, - retry: RETRY_COUNT, -}); - -/** - * Changing user axios default params, - * which are used in api call functions (calls.js) - * @param {*} currentUser current user from react state and local storage - */ -function changeUserDefaults(currentUser) { - if (currentUser) { - axiosInstance.defaults.headers.common.Authorization = `Basic ${currentUser.accessToken}`; - axiosInstance.defaults.userID = currentUser.ID; - if (currentUser.roles.includes('customer')) { - axiosInstance.defaults.userEntity = `Customers/${currentUser.ID}`; - axiosInstance.defaults.tracksEntity = 'MarkedTracks'; - } else { - axiosInstance.defaults.userEntity = `Employees/${currentUser.ID}`; - axiosInstance.defaults.tracksEntity = 'Tracks'; - } - } else { - axiosInstance.defaults.tracksEntity = 'Tracks'; - } -} -/** - * This func changing axios instance default params - * @param {*} locale current locale from react state and local storage - */ -function changeLocaleDefaults(locale) { - if (locale) { - axiosInstance.defaults.headers.common['Accept-language'] = locale; - } -} - -/** - * Init axios defaults - */ -const user = getUserFromLS(); -const locale = getLocaleFromLS(); -changeUserDefaults(user); -changeLocaleDefaults(locale); - -/** - * Retry request if response time is too long - * See link below - * {@link https://github.com/axios/axios/issues/164#issuecomment-327837467 GitHub} - * @param {*} err response error object - */ -function axiosRetryInterceptor(err) { - const config = err.config; - // If config does not exist or the retry option is not set, reject - if (config && config.retry) { - // Set the variable for keeping track of the retry count - config.retryCount = config.retryCount || 0; - - // Check if we've maxed out the total number of retries - if (config.retryCount >= config.retry) { - // Reject with the error - return Promise.reject(err); - } - - // Increase the retry count - config.retryCount += 1; - - // Create new promise to handle exponential backoff - const backoff = new Promise((resolve) => { - setTimeout(() => { - resolve(); - }, config.retryDelay || 1); - }); - - // Return the promise in which recalls axios to retry the request - return backoff.then(() => { - return axios(config); - }); - } -} - -/** - * Things below needed for refresh tokens mechanism implementation - */ -let isRefreshing = false; -let subscribers = []; -const refreshTokens = (refreshToken) => { - return axiosInstance.post( - 'users/refreshTokens', - { refreshToken }, - { - headers: { 'content-type': 'application/json' }, - } - ); -}; - -/** - * Refresh tokens interceptor - * See link below - * {@link https://gist.github.com/mkjiau/650013a99c341c9f23ca00ccb213db1c#gistcomment-3536511 GitHub} - * @param {*} error error response object - */ -function axiosRefreshTokensInterceptor(error) { - const originalRequest = error.config; - const user = getUserFromLS(); - - if (error.response && error.response.status === 401 && !!user) { - if (originalRequest.url === 'users/login') { - return Promise.reject(error); - } - - // if users/refreshTokens request failed - if (isRefreshing && originalRequest.url === 'users/refreshTokens') { - subscribers.forEach((request) => request.reject(error)); - subscribers = []; - isRefreshing = false; - return Promise.reject(error); - } - - // if got a 401 error we sending users/refreshTokens request - if (!isRefreshing) { - isRefreshing = true; - - refreshTokens(user.refreshToken) - .then((response) => { - emitter.emit('UPDATE_USER', response.data); - subscribers.forEach((request) => request.resolve(response.data.accessToken)); - subscribers = []; - isRefreshing = false; - }) - .catch(() => { - emitter.emit('UPDATE_USER', undefined); - }); - } - - // holding requests which should be sended after users/refreshTokens complete - // otherwise if users/refreshTokens failed an error will be thrown - return new Promise((resolve, reject) => { - subscribers.push({ - resolve: (newAccessToken) => { - originalRequest.headers.Authorization = `Basic ${newAccessToken}`; - resolve(axiosInstance(originalRequest)); - }, - reject: (err) => { - reject(err); - }, - }); - }); - } -} - -axiosInstance.interceptors.response.use(null, (error) => { - return ( - axiosRefreshTokensInterceptor(error) || axiosRetryInterceptor(error) || Promise.reject(error) - ); -}); - -export { axiosInstance, changeLocaleDefaults, changeUserDefaults }; diff --git a/media-store/app-src/src/api/calls.js b/media-store/app-src/src/api/calls.js deleted file mode 100644 index 10b6abb5..00000000 --- a/media-store/app-src/src/api/calls.js +++ /dev/null @@ -1,164 +0,0 @@ -import { isEmpty } from 'lodash'; -import { axiosInstance } from './axiosInstance'; - -const BROWSE_TRACKS_SERVICE = 'browse-tracks'; -const INVOICES_SERVICE = 'browse-invoices'; -const USER_SERVICE = 'users'; -const MANAGE_STORE = 'manage-store'; - -const constructGenresQuery = (genreIds) => { - return !isEmpty(genreIds) - ? ` and ${genreIds.map((value) => `genre_ID eq ${value}`).join(' or ')}` - : ''; -}; - -const fetchTacks = ({ $top = 20, $skip = 0, genreIds = [], substr = '' } = {}) => { - const serializeTracksUrl = () => { - return `$expand=genre,album($expand=artist)&$top=${$top}&$skip=${$skip}&$filter=${`contains(name,'${substr}')${constructGenresQuery( - genreIds - )}`}`; - }; - - return axiosInstance.get(`${BROWSE_TRACKS_SERVICE}/${axiosInstance.defaults.tracksEntity}`, { - params: {}, - paramsSerializer: () => serializeTracksUrl(), - }); -}; - -const countTracks = ({ genreIds = [], substr = '' } = {}) => { - const { tracksEntity } = axiosInstance.defaults; - - return axiosInstance.get( - `${BROWSE_TRACKS_SERVICE}/${tracksEntity}/$count?$filter=${`contains(name,'${substr}')${constructGenresQuery( - genreIds - )}`}` - ); -}; - -const fetchGenres = () => { - return axiosInstance.get(`${BROWSE_TRACKS_SERVICE}/Genres`); -}; - -const invoice = (tracks) => { - return axiosInstance.post( - `${INVOICES_SERVICE}/invoice`, - { - tracks, - }, - { - headers: { 'content-type': 'application/json' }, - } - ); -}; - -const fetchPerson = () => { - return axiosInstance.get(`${USER_SERVICE}/${axiosInstance.defaults.userEntity}`); -}; - -const confirmPerson = (person) => { - return axiosInstance.put( - `${USER_SERVICE}/${axiosInstance.defaults.userEntity}`, - { - ...person, - }, - { - headers: { 'content-type': 'application/json' }, - } - ); -}; - -const fetchInvoices = () => { - return axiosInstance.get( - `${INVOICES_SERVICE}/Invoices?$expand=invoiceItems($expand=track($expand=album($expand=artist)))` - ); -}; - -const cancelInvoice = (ID) => { - return axiosInstance.post( - `${INVOICES_SERVICE}/cancelInvoice`, - { - ID, - }, - { - headers: { 'content-type': 'application/json' }, - } - ); -}; - -const fetchAlbumsByName = (substr = '', top) => { - return axiosInstance.get( - `${BROWSE_TRACKS_SERVICE}/Albums?$filter=${`contains(title,'${substr}')&$top=${top}`}` - ); -}; - -const addTrack = (data) => { - return axiosInstance.post(`${MANAGE_STORE}/Tracks`, data, { - headers: { 'content-type': 'application/json;IEEE754Compatible=true' }, - }); -}; - -const addArtist = (data) => { - return axiosInstance.post(`${MANAGE_STORE}/Artists`, data, { - headers: { 'content-type': 'application/json' }, - }); -}; - -const addAlbum = (data) => { - return axiosInstance.post(`${MANAGE_STORE}/Albums`, data, { - headers: { 'content-type': 'application/json' }, - }); -}; - -const fetchArtistsByName = (substr = '', top) => { - return axiosInstance.get( - `${MANAGE_STORE}/Artists?$filter=${`contains(name,'${substr}')&$top=${top}`}` - ); -}; - -const login = (data) => { - return axiosInstance.post(`${USER_SERVICE}/login`, data, { - headers: { 'content-type': 'application/json' }, - }); -}; - -const updateTrack = (track) => { - return axiosInstance.put( - `${MANAGE_STORE}/Tracks/${track.ID}`, - { - ...track, - }, - { - headers: { 'content-type': 'application/json;IEEE754Compatible=true' }, - } - ); -}; - -const getTrack = (ID) => { - return axiosInstance.get( - `${BROWSE_TRACKS_SERVICE}/${axiosInstance.defaults.tracksEntity}/${ID}?$expand=genre,album($expand=artist)` - ); -}; - -const deleteTrack = (ID) => { - return axiosInstance.delete(`${MANAGE_STORE}/Tracks(${ID})`); -}; - -export { - fetchTacks, - countTracks, - fetchGenres, - invoice, - fetchPerson, - confirmPerson, - fetchInvoices, - cancelInvoice, - fetchAlbumsByName, - addTrack, - addArtist, - addAlbum, - fetchArtistsByName, - login, - updateTrack, - getTrack, - deleteTrack, -}; diff --git a/media-store/app-src/src/components/ErrorPage.jsx b/media-store/app-src/src/components/ErrorPage.jsx deleted file mode 100644 index e39c7f52..00000000 --- a/media-store/app-src/src/components/ErrorPage.jsx +++ /dev/null @@ -1,49 +0,0 @@ -import React from 'react'; -import { useHistory } from 'react-router-dom'; -import { isEmpty } from 'lodash'; -import { Result, Button } from 'antd'; -import { useAppState } from '../hooks/useAppState'; - -const ErrorPage = () => { - const { error, setError } = useAppState(); - const history = useHistory(); - - const onGoHome = () => { - setError({}); - history.push('/'); - }; - - const goLoginPage = () => { - setError({}); - 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 : 'error', - title: error.statusText, - subTitle: error.message, - extra: error.status === 401 ? [goHomeButton, goLoginButton] : goHomeButton, - }; - - return ; -}; - -export default ErrorPage; diff --git a/media-store/app-src/src/components/Header.css b/media-store/app-src/src/components/Header.css deleted file mode 100644 index 3d78184d..00000000 --- a/media-store/app-src/src/components/Header.css +++ /dev/null @@ -1,3 +0,0 @@ -.ant-menu-item .anticon { - margin: 0; -} diff --git a/media-store/app-src/src/components/Header.jsx b/media-store/app-src/src/components/Header.jsx deleted file mode 100644 index a965ff8c..00000000 --- a/media-store/app-src/src/components/Header.jsx +++ /dev/null @@ -1,141 +0,0 @@ -import React from 'react'; -import { Menu, Badge, Spin, message } 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'; -import { setLocaleToLS } from '../util/localStorageService'; -import { changeLocaleDefaults } from '../api/axiosInstance'; -import { emitter } from '../util/EventEmitter'; -import './Header.css'; -import { requireEmployee, requireCustomer, MESSAGE_TIMEOUT } from '../util/constants'; - -const { SubMenu } = Menu; - -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, loading } = useAppState(); - const currentKey = [keys.find((key) => key === location.pathname)]; - const haveInvoicedItems = !isEmpty(invoicedItems); - const invoicedItemsLength = invoicedItems.length; - - const onChangeLocale = (value) => { - setLocaleToLS(value); - changeLocaleDefaults(value); - setLocale(value); - history.go(RELOAD_LOCATION_NUMBER); - }; - const localeElements = AVAILABLE_LOCALES.filter((localeName) => localeName !== locale).map( - (curLocale) => ( - onChangeLocale(curLocale)}> - {curLocale} - - ) - ); - - const onUserLogout = () => { - emitter.emit('UPDATE_USER', undefined); - message.warn( - 'Now you are not authenticated. Log in to use full functionality', - MESSAGE_TIMEOUT - ); - history.push('/'); - }; - - return ( -
- - history.push('/')}> - Browse - - - {!!user && ( - history.push('/person')}> - Profile - - )} - {requireCustomer(user) && ( - history.push('/invoices')}> - Invoices - - )} - {requireEmployee(user) && ( - history.push('/manage')}> - Manages - - )} - - - - - {loading && } />} - - {haveInvoicedItems && ( - history.push('/invoice')} - key="/invoice" - > -
- - - -
-
- )} - {localeElements} - {user ? ( - } - /> - ) : ( - history.push('/login')} - icon={} - /> - )} -
-
- ); -}; - -export default Header; diff --git a/media-store/app-src/src/components/InvoicePage.jsx b/media-store/app-src/src/components/InvoicePage.jsx deleted file mode 100644 index 505ccd9a..00000000 --- a/media-store/app-src/src/components/InvoicePage.jsx +++ /dev/null @@ -1,101 +0,0 @@ -import React from 'react'; -import { Table, Button, message } from 'antd'; -import { useHistory } from 'react-router-dom'; -import { useAppState } from '../hooks/useAppState'; -import { invoice } from '../api/calls'; -import { useErrors } from '../hooks/useErrors'; -import { MESSAGE_TIMEOUT } from '../util/constants'; - -const columns = [ - { - title: 'Name', - dataIndex: 'name', - }, - { - title: 'Artist', - dataIndex: 'artist', - }, - { - title: 'Album', - dataIndex: 'albumTitle', - }, - { - title: 'Price', - dataIndex: 'unitPrice', - }, -]; - -const InvoicePage = () => { - const history = useHistory(); - const { handleError } = useErrors(); - const { user, invoicedItems, setInvoicedItems, setLoading } = useAppState(); - - const data = invoicedItems.map(({ ID, ...otherProps }) => ({ - key: `invoiceItem${ID}`, - ...otherProps, - })); - - const onBuy = () => { - setLoading(true); - invoice( - invoicedItems.map(({ ID }) => ({ - ID, - })) - ) - .then(() => { - setInvoicedItems([]); - message.success('Invoice successfully completed', MESSAGE_TIMEOUT); - history.push('/invoices'); - }) - .catch(handleError) - .finally(() => setLoading(false)); - }; - const onCancel = () => { - setInvoicedItems([]); - history.push('/'); - }; - const goLogin = () => { - history.push('/login'); - }; - - return ( -
- ( -
- {user ? ( - <> - - - - ) : ( -
- - to buy selected -
- )} -
- )} - /> - - ); -}; - -export default InvoicePage; diff --git a/media-store/app-src/src/components/Login.jsx b/media-store/app-src/src/components/Login.jsx deleted file mode 100644 index 91ca97e8..00000000 --- a/media-store/app-src/src/components/Login.jsx +++ /dev/null @@ -1,107 +0,0 @@ -import React from 'react'; -import { Form, Input, Button, Checkbox, message } from 'antd'; -import { useHistory } from 'react-router-dom'; -import { login } from '../api/calls'; -import { useAppState } from '../hooks/useAppState'; -import { useErrors } from '../hooks/useErrors'; -import { MESSAGE_TIMEOUT } from '../util/constants'; -import { emitter } from '../util/EventEmitter'; - -const layout = { - labelCol: { - span: 8, - }, - wrapperCol: { - span: 8, - }, -}; -const tailLayout = { - wrapperCol: { - offset: 8, - span: 8, - }, -}; - -const Login = () => { - const [form] = Form.useForm(); - const history = useHistory(); - const { setLoading, setInvoicedItems } = useAppState(); - const { handleError } = useErrors(); - - const onFinish = (values) => { - setLoading(true); - login({ email: values.email, password: values.password }) - .then(({ data: user }) => { - emitter.emit('UPDATE_USER', user); - if (user.roles.includes('employee')) { - setInvoicedItems([]); - } - history.push('/'); - }) - .catch((error) => { - console.log(error); - if (error.response && error.response.status === 401) { - form.resetFields(); - message.error('Invalid credentials!', MESSAGE_TIMEOUT); - } else { - handleError(error); - } - }) - .finally(() => setLoading(false)); - }; - - const onFinishFailed = (errorInfo) => { - console.log('Validation Failed:', errorInfo); - }; - - return ( - - - - - - - - - - - Remember me - - - - - - - ); -}; - -export default Login; diff --git a/media-store/app-src/src/components/ManageStore.jsx b/media-store/app-src/src/components/ManageStore.jsx deleted file mode 100644 index 71167a7c..00000000 --- a/media-store/app-src/src/components/ManageStore.jsx +++ /dev/null @@ -1,115 +0,0 @@ -import React, { useState, useMemo, useEffect } from 'react'; -import { Form, Radio, Button, message } from 'antd'; -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', - artist: 'artist', - album: 'album', - playlist: '', -}; - -const chooseForm = (type) => { - return ( - (type === 'track' && ) || - (type === 'artist' && ) || - (type === 'album' && ) - ); -}; - -const ManageStore = () => { - const [form] = Form.useForm(); - const { handleError } = useErrors(); - const { setLoading } = useAppState(); - const [formType, setFormType] = useState('track'); - - useEffect(() => { - form.resetFields(); - }, [formType]); - - const formElement = useMemo(() => { - return chooseForm(formType); - }, [formType]); - - const onChangeForm = (event) => { - setFormType(event.target.value); - }; - - const sendCreateRequest = ({ type, ...data }) => { - setLoading(true); - - let promise; - switch (type) { - case FORM_TYPES.track: - promise = addTrack({ - name: data.name, - composer: data.composer, - album: { ID: data.albumID }, - genre: { ID: data.genreID }, - unitPrice: data.unitPrice.toString(), - }); - break; - case FORM_TYPES.artist: - promise = addArtist(data); - break; - case FORM_TYPES.album: - promise = addAlbum({ title: data.name, artist: { ID: data.artistID } }); - break; - default: - } - - promise - .then(() => { - message.success('Entity successfully created', MESSAGE_TIMEOUT); - form.resetFields(); - }) - .catch(handleError) - .finally(() => setLoading(false)); - }; - - return ( -
console.log('Not valid params provided')} - > - - - Track - Album - Artist - - - {formElement} - - - - - ); -}; - -export default ManageStore; diff --git a/media-store/app-src/src/components/MyInvoicesPage.jsx b/media-store/app-src/src/components/MyInvoicesPage.jsx deleted file mode 100644 index bb490282..00000000 --- a/media-store/app-src/src/components/MyInvoicesPage.jsx +++ /dev/null @@ -1,170 +0,0 @@ -import React, { useState, useEffect, useMemo, useCallback } from 'react'; -import PropTypes from 'prop-types'; -import { Button, message, 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'; - -const { Panel } = Collapse; -const INVOICE_STATUS = { - 2: { - tagTitle: 'Shipped', - color: 'green', - }, - 1: { - tagTitle: 'Submitted', - color: 'processing', - canCancel: true, - }, - '-1': { - tagTitle: 'Cancelled', - color: 'default', - }, -}; -const CANCELLED_STATUS = -1; -const DATE_TIME_FORMAT_PATTERN = 'LLLL'; -const UTC_DATE_TIME_FORMAT = 'YYYY-MM-DDThh:mm:ss'; -const INVOICE_ITEMS_COLUMNS = [ - { - title: 'Track name', - dataIndex: 'name', - }, - { - title: 'Artist', - dataIndex: 'artistName', - }, - { - title: 'Album', - dataIndex: 'albumTitle', - }, - { - title: 'Price', - dataIndex: 'unitPrice', - }, -]; -const LEVERAGE_DURATION = 1; // in hours -const STATUSES = { submitted: 1, shipped: 2, canceled: -1 }; - -const isLeverageTimeExpired = (utcNowTimestamp, invoiceDate) => { - const duration = moment.duration(moment(utcNowTimestamp).diff(moment(invoiceDate).valueOf())); - return duration.asHours() > LEVERAGE_DURATION; -}; - -const chooseStatus = (utcNowTimestamp, invoiceDate, statusFromDb) => { - if (isLeverageTimeExpired(utcNowTimestamp, invoiceDate) && statusFromDb !== STATUSES.canceled) { - return INVOICE_STATUS[STATUSES.shipped]; - } - return INVOICE_STATUS[statusFromDb]; -}; - -const ExtraHeader = ({ ID, invoiceDate, status: initialStatus }) => { - const { loading, setLoading } = useAppState(); - const { handleError } = useErrors(); - const [loadingHeaderId, setLoadingHeaderId] = useState(); - const [status, setStatus] = useState(initialStatus); - - const statusConfig = useMemo(() => { - const utcNowTimestamp = moment(moment().utc().format(UTC_DATE_TIME_FORMAT)).valueOf(); - return chooseStatus(utcNowTimestamp, invoiceDate, status); - }, [status]); - - const onCancelInvoice = (event, ID) => { - event.stopPropagation(); - setLoading(true); - setLoadingHeaderId(ID); - cancelInvoice(ID) - .then(() => { - message.success('Invoice successfully cancelled', MESSAGE_TIMEOUT); - setLoadingHeaderId(undefined); - setStatus(CANCELLED_STATUS); - }) - .catch(handleError) - .finally(() => setLoading(false)); - }; - - return ( - - {statusConfig.tagTitle} - {statusConfig.canCancel && ( - - )} - - ); -}; -ExtraHeader.propTypes = { - ID: PropTypes.number.isRequired, - status: PropTypes.number.isRequired, - invoiceDate: PropTypes.string.isRequired, -}; - -const MyInvoicesPage = () => { - const { handleError } = useErrors(); - const { setLoading } = useAppState(); - const [invoices, setInvoices] = useState([]); - - useEffect(() => { - setLoading(true); - fetchInvoices() - .then(({ data: { value } }) => setInvoices(value)) - .catch(handleError) - .finally(() => setLoading(false)); - }, []); - - const genExtra = useCallback( - (ID, status, invoiceDate) => , - [] - ); - const invoiceElements = useMemo(() => { - return invoices.map(({ ID, status, invoiceDate, total, invoiceItems }) => { - const invoiceItemsData = invoiceItems.map( - ({ - ID, - track: { - name, - unitPrice, - album: { - title: albumTitle, - artist: { name: artistName }, - }, - }, - }) => ({ - key: ID, - ID, - name, - unitPrice, - albumTitle, - artistName, - }) - ); - - return ( - -
-
{`Total price: ${total}`}} - /> - - - ); - }); - }, [invoices]); - - return ( -
{invoiceElements && {invoiceElements}}
- ); -}; - -export default MyInvoicesPage; diff --git a/media-store/app-src/src/components/PersonPage.jsx b/media-store/app-src/src/components/PersonPage.jsx deleted file mode 100644 index d312a233..00000000 --- a/media-store/app-src/src/components/PersonPage.jsx +++ /dev/null @@ -1,108 +0,0 @@ -import React, { useState } from 'react'; -import { Form, Button, message, Input } from 'antd'; -import { omit, map } from 'lodash'; -import { fetchPerson, confirmPerson } from '../api/calls'; -import { useErrors } from '../hooks/useErrors'; -import { useAppState } from '../hooks/useAppState'; -import { MESSAGE_TIMEOUT } from '../util/constants'; -import { useAbortableEffect } from '../hooks/useAbortableEffect'; - -const PERSON_PROP = { - address: 'Address ', - city: 'City ', - country: 'Country ', - fax: 'Fax: ', - firstName: 'First name: ', - lastName: 'Last name: ', - phone: 'Phone: ', - postalCode: 'Postal code: ', - state: 'State', - email: 'email', - company: 'Company: ', -}; - -const PersonPage = () => { - const { setLoading } = useAppState(); - const { handleError } = useErrors(); - const [form] = Form.useForm(); - const [person, setPerson] = useState({ - lastName: '', - firstName: '', - city: '', - state: '', - address: '', - country: '', - phone: '', - postalCode: '', - fax: '', - email: '', - company: '', - }); - - useAbortableEffect((status) => { - setLoading(true); - - fetchPerson() - .then(({ data }) => { - const personData = omit(data, '@odata.context', 'ID'); - if (!status.aborted) { - setPerson(personData); - } - }) - .catch(handleError) - .finally(() => setLoading(false)); - }, []); - - const onConfirmChanges = (newPerson) => { - setLoading(true); - confirmPerson(newPerson) - .then(() => { - message.success('Person successfully updated', MESSAGE_TIMEOUT); - }) - .catch(handleError) - .finally(() => setLoading(false)); - }; - - const personProperties = map(Object.keys(person), (currentKey) => ( -
- - - -
- )); - - return ( - <> - {person.lastName !== '' && ( - console.log('Not valid params provided')} - initialValues={{ - ...person, - }} - > - {personProperties} - - - - - )} - - ); -}; - -export default PersonPage; diff --git a/media-store/app-src/src/components/Router.jsx b/media-store/app-src/src/components/Router.jsx deleted file mode 100644 index e0cf5d4f..00000000 --- a/media-store/app-src/src/components/Router.jsx +++ /dev/null @@ -1,58 +0,0 @@ -import React from 'react'; -import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'; -import { isEmpty } from 'lodash'; -import TracksContainer from './TracksPage'; -import Header from './Header'; -import PersonPage from './PersonPage'; -import ErrorPage from './ErrorPage'; -import InvoicePage from './InvoicePage'; -import ManageStore from './ManageStore'; -import MyInvoicesPage from './MyInvoicesPage'; -import Login from './Login'; -import { withRestrictions } from '../hocs/withRestrictions'; -import { requireEmployee } from '../util/constants'; - -const RestrictedLogin = withRestrictions(Login, ({ user }) => !user); -const RestrictedInvoicePage = withRestrictions( - InvoicePage, - ({ user, invoicedItems }) => !requireEmployee(user) && !isEmpty(invoicedItems) -); -const RestrictedPersonPage = withRestrictions(PersonPage, ({ user }) => !!user); -const RestrictedManageStore = withRestrictions(ManageStore, ({ user }) => requireEmployee(user)); - -const MyRouter = () => { - return ( - -
-
- Loading...
}> - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -}; - -export { MyRouter }; diff --git a/media-store/app-src/src/components/TracksPage.css b/media-store/app-src/src/components/TracksPage.css deleted file mode 100644 index c3855497..00000000 --- a/media-store/app-src/src/components/TracksPage.css +++ /dev/null @@ -1,4 +0,0 @@ -.ant-select > div.ant-select-selector { - padding: 5px; - min-width: 300px; -} diff --git a/media-store/app-src/src/components/TracksPage.jsx b/media-store/app-src/src/components/TracksPage.jsx deleted file mode 100644 index ed6c9835..00000000 --- a/media-store/app-src/src/components/TracksPage.jsx +++ /dev/null @@ -1,215 +0,0 @@ -import React, { useState } from 'react'; -import { debounce } from 'lodash'; -import { Input, Col, Row, Select, Pagination } from 'antd'; -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'; - -const { Search } = Input; -const { Option } = Select; - -const DEBOUNCE_TIMER = 500; -const DEBOUNCE_OPTIONS = { - leading: true, - trailing: false, -}; - -const renderGenres = (genres) => - genres.map(({ ID, name }) => ( - - )); - -const TracksContainer = () => { - const { setLoading, user } = useAppState(); - const { handleError } = useErrors(); - const [state, setState] = useState({ - tracks: [], - genres: [], - pagination: { - currentPage: 1, - totalItems: 0, - pageSize: 20, - }, - searchOptions: { - substr: '', - genreIds: [], - }, - }); - - useAbortableEffect((status) => { - setLoading(true); - - const countTracksReq = countTracks(); - const getTracksRequest = fetchTacks(); - const getGenresReq = fetchGenres(); - - Promise.all([countTracksReq, getTracksRequest, getGenresReq]) - .then( - ([ - { data: totalItems }, - { - data: { value: tracks }, - }, - { - data: { value: genres }, - }, - ]) => { - if (!status.aborted) { - setState({ - ...state, - tracks, - genres, - pagination: { ...state.pagination, totalItems }, - }); - } - } - ) - .catch(handleError) - .finally(() => setLoading(false)); - }, []); - - const onSearch = debounce( - () => { - setLoading(true); - const options = { - $top: state.pagination.pageSize, - substr: state.searchOptions.substr.replace(`'`, `''`), - genreIds: state.searchOptions.genreIds, - }; - - Promise.all([ - fetchTacks(options), - countTracks({ - substr: options.substr, - genreIds: options.genreIds, - }), - ]) - .then(([{ data: { value: tracks } }, { data: totalItems }]) => - setState({ - ...state, - tracks, - pagination: { ...state.pagination, totalItems }, - }) - ) - .catch(handleError) - .finally(() => setLoading(false)); - }, - DEBOUNCE_TIMER, - DEBOUNCE_OPTIONS - ); - const onSelectChange = (genres) => { - setState({ - ...state, - searchOptions: { - ...state.searchOptions, - genreIds: genres.map((value) => parseInt(value, 10)), - }, - }); - }; - const onSearchChange = (event) => { - setState({ - ...state, - searchOptions: { ...state.searchOptions, substr: event.target.value }, - }); - }; - const onChangePage = (pageNumber) => { - document.querySelector('section.ant-layout').scrollTo({ top: 0, left: 0, behavior: 'smooth' }); - setLoading(true); - - const options = { - $top: state.pagination.pageSize, - substr: state.searchOptions.substr, - genreIds: state.searchOptions.genreIds, - $skip: (pageNumber - 1) * state.pagination.pageSize, - }; - fetchTacks(options) - .then((response) => - setState({ - ...state, - tracks: response.data.value, - pagination: { ...state.pagination, currentPage: pageNumber }, - }) - ) - .catch(handleError) - .finally(() => setLoading(false)); - }; - const deleteTrack = (ID) => { - setState({ - ...state, - tracks: state.tracks.filter(({ ID: curID }) => curID !== 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); - const genreElements = renderGenres(state.genres); - - return ( - <> -
- - -
-
- {trackElements} -
-
- -
- - ); -}; - -export default TracksContainer; diff --git a/media-store/app-src/src/components/manage-store/AddAlbumForm.jsx b/media-store/app-src/src/components/manage-store/AddAlbumForm.jsx deleted file mode 100644 index 0a4978ae..00000000 --- a/media-store/app-src/src/components/manage-store/AddAlbumForm.jsx +++ /dev/null @@ -1,62 +0,0 @@ -import React, { useEffect } from 'react'; -import { Form, Input, Select } from 'antd'; -import { useSearch } from '@umijs/hooks'; -import { useErrors } from '../../hooks/useErrors'; -import { fetchArtistsByName } from '../../api/calls'; - -const REQUIRED = [ - { - required: true, - message: 'This filed is required!', - }, -]; -const ARTISTS_LIMIT = 10; - -const getArtists = function (value) { - return fetchArtistsByName(value, ARTISTS_LIMIT) - .then((response) => response.data.value) - .catch(this.handleError); -}; - -const AddAlbumForm = () => { - const { handleError } = useErrors(); - const { - data: artists, - loading: isArtistsLoading, - onChange: onChangeArtistInput, - cancel: onArtistCancel, - } = useSearch(getArtists.bind({ handleError })); - - useEffect(() => { - onChangeArtistInput(); - }, []); - - return ( - <> -

Add album

- - - - - - - - ); -}; - -export { AddAlbumForm }; diff --git a/media-store/app-src/src/components/manage-store/AddArtistForm.jsx b/media-store/app-src/src/components/manage-store/AddArtistForm.jsx deleted file mode 100644 index 3cc7567f..00000000 --- a/media-store/app-src/src/components/manage-store/AddArtistForm.jsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; -import { Form, Input } from 'antd'; - -const REQUIRED = [ - { - required: true, - message: 'This filed is required!', - }, -]; - -const AddArtistForm = () => { - return ( - <> -

Add artist

- - - - - ); -}; - -export { AddArtistForm }; diff --git a/media-store/app-src/src/components/manage-store/TrackForm.jsx b/media-store/app-src/src/components/manage-store/TrackForm.jsx deleted file mode 100644 index 47a7d9fe..00000000 --- a/media-store/app-src/src/components/manage-store/TrackForm.jsx +++ /dev/null @@ -1,96 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import PropTypes from 'prop-types'; -import { Form, Input, Select, InputNumber } from 'antd'; -import { head } from 'lodash'; -import { useSearch } from '@umijs/hooks'; -import { useAppState } from '../../hooks/useAppState'; -import { fetchAlbumsByName, fetchGenres } from '../../api/calls'; -import { useErrors } from '../../hooks/useErrors'; - -const ALBUMS_LIMIT = 10; -const REQUIRED = [ - { - required: true, - message: 'This filed is required!', - }, -]; - -function getAlbums(value) { - return fetchAlbumsByName(value, ALBUMS_LIMIT) - .then((response) => response.data.value) - .catch(this.handleError); -} - -const TrackForm = ({ initialAlbumTitle }) => { - const { handleError } = useErrors(); - const { - data: albums, - loading: isAlbumsLoading, - onChange: onChangeAlbumInput, - cancel: onAlbumCancel, - } = useSearch(getAlbums.bind({ handleError })); - const { setLoading } = useAppState(); - const [genres, setGenres] = useState([]); - - useEffect(() => { - setLoading(true); - Promise.all([fetchGenres(), onChangeAlbumInput(initialAlbumTitle)]) - .then((responses) => setGenres(head(responses).data.value)) - .catch(handleError) - .finally(() => setLoading(false)); - }, []); - - return ( -
- - - - - - - - - - - - - - value.replace(/\$\s?|(,*)/g, '')} - /> - -
- ); -}; - -TrackForm.propTypes = { - initialAlbumTitle: PropTypes.string, -}; -TrackForm.defaultProps = { - initialAlbumTitle: undefined, -}; - -export { TrackForm }; diff --git a/media-store/app-src/src/components/tracks/DeleteAction.jsx b/media-store/app-src/src/components/tracks/DeleteAction.jsx deleted file mode 100644 index 948fc7ab..00000000 --- a/media-store/app-src/src/components/tracks/DeleteAction.jsx +++ /dev/null @@ -1,44 +0,0 @@ -import React, { useState } from 'react'; -import PropTypes from 'prop-types'; -import { Modal, message } from 'antd'; -import { DeleteOutlined } from '@ant-design/icons'; -import { deleteTrack } from '../../api/calls'; -import { useErrors } from '../../hooks/useErrors'; -import { MESSAGE_TIMEOUT } from '../../util/constants'; - -const DeleteAction = ({ ID, onDeleteTrack }) => { - const [modalVisible, setModalVisible] = useState(false); - const { handleError } = useErrors(); - - const onOk = () => { - setModalVisible(false); - deleteTrack(ID) - .then(() => { - onDeleteTrack(); - setModalVisible(false); - message.success('Track successfully deleted!', MESSAGE_TIMEOUT); - }) - .catch(handleError); - }; - - const onCancel = () => setModalVisible(false); - const onOpenModal = () => { - setModalVisible(true); - }; - - return ( - <> - Delete - -

Are You really want to delete this track?

-
- - ); -}; - -DeleteAction.propTypes = { - ID: PropTypes.number.isRequired, - onDeleteTrack: PropTypes.func.isRequired, -}; - -export { DeleteAction }; diff --git a/media-store/app-src/src/components/tracks/EditAction.jsx b/media-store/app-src/src/components/tracks/EditAction.jsx deleted file mode 100644 index 1c8c42e6..00000000 --- a/media-store/app-src/src/components/tracks/EditAction.jsx +++ /dev/null @@ -1,113 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { Button, Modal, Form, message } from 'antd'; -import { EditOutlined, LoadingOutlined } from '@ant-design/icons'; -import { useErrors } from '../../hooks/useErrors'; -import { TrackForm } from '../manage-store/TrackForm'; -import { updateTrack, getTrack } from '../../api/calls'; -import { MESSAGE_TIMEOUT } from '../../util/constants'; - -const EditAction = ({ ID, name, composer, genre, unitPrice, album, afterTrackUpdate }) => { - const [visible, setVisible] = React.useState(false); - const [confirmLoading, setConfirmLoading] = React.useState(false); - const [updateLoading, setUpdateLoading] = React.useState(false); - const [form] = Form.useForm(); - const { handleError } = useErrors(); - - const onShowModal = () => { - setVisible(true); - }; - - const afterCloseModal = () => { - setUpdateLoading(true); - getTrack(ID) - .then((response) => { - afterTrackUpdate(response.data); - setUpdateLoading(false); - }) - .catch(handleError); - }; - - const onFinish = (value) => { - setConfirmLoading(true); - updateTrack({ - ID, - name: value.name, - composer: value.composer, - album: { ID: value.albumID }, - genre: { ID: value.genreID }, - unitPrice: value.unitPrice.toString(), - }) - .then(() => { - message.success('Track successfully updated!', MESSAGE_TIMEOUT); - setConfirmLoading(false); - setVisible(false); - afterCloseModal(); - }) - .catch(handleError); - }; - - const handleOk = () => { - form.submit(); - }; - - const handleCancel = () => { - setVisible(false); - }; - - return ( - <> - {updateLoading ? : } - - Cancel - , - , - ]} - > -
console.log('Not valid params provided')} - initialValues={{ - name, - composer, - genreID: genre.ID, - albumID: album.ID, - unitPrice, - }} - > - - -
- - ); -}; - -EditAction.propTypes = { - ID: PropTypes.number.isRequired, - name: PropTypes.string.isRequired, - composer: PropTypes.string.isRequired, - genre: PropTypes.object.isRequired, - unitPrice: PropTypes.number.isRequired, - album: PropTypes.object.isRequired, - afterTrackUpdate: PropTypes.func.isRequired, -}; - -export { EditAction }; diff --git a/media-store/app-src/src/components/tracks/ManagedTrack.css b/media-store/app-src/src/components/tracks/ManagedTrack.css deleted file mode 100644 index e2107b16..00000000 --- a/media-store/app-src/src/components/tracks/ManagedTrack.css +++ /dev/null @@ -1,7 +0,0 @@ -span > span.anticon.anticon-delete:hover { - color: #ff4d4f; -} - -.card-element { - transition: opacity 0.5s ease-in-out; -} diff --git a/media-store/app-src/src/components/tracks/ManagedTrack.jsx b/media-store/app-src/src/components/tracks/ManagedTrack.jsx deleted file mode 100644 index 42bea8c8..00000000 --- a/media-store/app-src/src/components/tracks/ManagedTrack.jsx +++ /dev/null @@ -1,48 +0,0 @@ -import React, { useState, useRef } from 'react'; -import { Card } from 'antd'; -import PropTypes from 'prop-types'; -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} - > - - -
- ); -}; - -ManagedTrack.propTypes = { - initialTrack: PropTypes.object.isRequired, - onDeleteTrack: PropTypes.func.isRequired, -}; - -export { ManagedTrack }; diff --git a/media-store/app-src/src/components/tracks/Track.jsx b/media-store/app-src/src/components/tracks/Track.jsx deleted file mode 100644 index 3fb90950..00000000 --- a/media-store/app-src/src/components/tracks/Track.jsx +++ /dev/null @@ -1,63 +0,0 @@ -import React, { useState, useRef } from 'react'; -import PropTypes from 'prop-types'; -import { Card, Button } from 'antd'; -import { PlusOutlined, MinusOutlined } from '@ant-design/icons'; -import { useAppState } from '../../hooks/useAppState'; -import { TrackCardBody } from './TrackCardBody'; - -const Track = ({ initialTrack, isAlreadyOrdered }) => { - const trackElement = useRef(); - const { setInvoicedItems, invoicedItems } = useAppState(); - const [isJustInvoiced, setIsJustInvoiced] = useState( - invoicedItems.find((curTrack) => curTrack.ID === initialTrack.ID) - ); - - const onChangedStatus = () => { - const newIsJustInvoiced = !isJustInvoiced; - if (newIsJustInvoiced) { - setInvoicedItems([ - ...invoicedItems, - { - 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 !== initialTrack.ID)); - } - setIsJustInvoiced(newIsJustInvoiced); - }; - - return ( -
- - {!isAlreadyOrdered && ( - - )} - , - ]} - title={initialTrack.name} - bordered={false} - > - - -
- ); -}; - -Track.propTypes = { - initialTrack: PropTypes.object.isRequired, - isAlreadyOrdered: PropTypes.bool, -}; -Track.defaultProps = { - isAlreadyOrdered: undefined, -}; - -export { Track }; diff --git a/media-store/app-src/src/components/tracks/TrackCardBody.jsx b/media-store/app-src/src/components/tracks/TrackCardBody.jsx deleted file mode 100644 index 7587c99a..00000000 --- a/media-store/app-src/src/components/tracks/TrackCardBody.jsx +++ /dev/null @@ -1,41 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -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} - -
- - ); -}; - -TrackCardBody.propTypes = { - track: PropTypes.object.isRequired, -}; - -export { TrackCardBody }; diff --git a/media-store/app-src/src/contexts/AppStateContext.jsx b/media-store/app-src/src/contexts/AppStateContext.jsx deleted file mode 100644 index 5b5dd180..00000000 --- a/media-store/app-src/src/contexts/AppStateContext.jsx +++ /dev/null @@ -1,66 +0,0 @@ -import React, { useMemo, createContext, useState, useEffect } from 'react'; -import PropTypes from 'prop-types'; -import { getUserFromLS, getLocaleFromLS, setUserToLS } from '../util/localStorageService'; -import { changeUserDefaults } from '../api/axiosInstance'; -import { emitter } from '../util/EventEmitter'; - -const globalContext = { - error: {}, - loading: true, - user: { - ID: undefined, - roles: [], - email: undefined, - accessToken: undefined, - refreshToken: undefined, - }, - locale: undefined, - invoicedItems: [], - notifications: [], -}; -const AppStateContext = createContext(globalContext); - -const AppStateContextProvider = ({ children }) => { - const [invoicedItems, setInvoicedItems] = useState([]); - const [loading, setLoading] = useState(false); - const [error, setError] = useState({}); - const [user, setUser] = useState(getUserFromLS()); - const [locale, setLocale] = useState(getLocaleFromLS()); - - useEffect(() => { - const updateUser = (newUser) => { - console.log('USER_UPDATE WAS TRIGGERED'); - changeUserDefaults(newUser); - setUserToLS(newUser); - setUser(newUser); - }; - emitter.on('UPDATE_USER', updateUser); - return () => { - emitter.removeListener('UPDATE_USER', updateUser); - }; - }, []); - - const value = useMemo( - () => ({ - error, - loading, - invoicedItems, - user, - locale, - setLoading, - setError, - setInvoicedItems, - setUser, - setLocale, - }), - [locale, user, loading, error, invoicedItems] - ); - - return {children}; -}; - -AppStateContextProvider.propTypes = { - children: PropTypes.element.isRequired, -}; - -export { AppStateContextProvider, AppStateContext }; diff --git a/media-store/app-src/src/hocs/withRestrictions.jsx b/media-store/app-src/src/hocs/withRestrictions.jsx deleted file mode 100644 index 26eedba3..00000000 --- a/media-store/app-src/src/hocs/withRestrictions.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; -import { Redirect } from 'react-router-dom'; -import { useAppState } from '../hooks/useAppState'; - -const withRestrictions = (Component, isUserMeetRestrictions) => { - return (props) => { - const { user, invoicedItems } = useAppState(); - return isUserMeetRestrictions({ user, invoicedItems }) ? ( - - ) : ( - - ); - }; -}; - -export { withRestrictions }; diff --git a/media-store/app-src/src/hooks/useAbortableEffect.js b/media-store/app-src/src/hooks/useAbortableEffect.js deleted file mode 100644 index 648d923d..00000000 --- a/media-store/app-src/src/hooks/useAbortableEffect.js +++ /dev/null @@ -1,22 +0,0 @@ -import { useEffect } from 'react'; - -function useAbortableEffect(effect, dependencies) { - const status = {}; // mutable status object - useEffect(() => { - status.aborted = false; - // pass the mutable object to the effect callback - // store the returned value for cleanup - const cleanUpFn = effect(status); - return () => { - // mutate the object to signal the consumer - // this effect is cleaning up - status.aborted = true; - if (typeof cleanUpFn === 'function') { - // run the cleanup function - cleanUpFn(); - } - }; - }, [...dependencies]); -} - -export { useAbortableEffect }; diff --git a/media-store/app-src/src/hooks/useAppState.js b/media-store/app-src/src/hooks/useAppState.js deleted file mode 100644 index 831ae73d..00000000 --- a/media-store/app-src/src/hooks/useAppState.js +++ /dev/null @@ -1,6 +0,0 @@ -import { useContext } from 'react'; -import { AppStateContext } from '../contexts/AppStateContext'; - -const useAppState = () => useContext(AppStateContext); - -export { useAppState }; diff --git a/media-store/app-src/src/hooks/useErrors.js b/media-store/app-src/src/hooks/useErrors.js deleted file mode 100644 index 4ccdd694..00000000 --- a/media-store/app-src/src/hooks/useErrors.js +++ /dev/null @@ -1,34 +0,0 @@ -import { useHistory } from 'react-router-dom'; -import { useAppState } from './useAppState'; - -const useErrors = () => { - const history = useHistory(); - const { setError } = useAppState(); - - const handleError = (error) => { - console.error('Error', error); - - if (error.response) { - const { status, statusText, data } = error.response; - setError({ - status, - statusText, - message: data.error ? data.error.message : data, - }); - } else { - setError({ - status: '', - statusText: 'Error', - message: 'Something went wrong. Seems like request is too long', - }); - } - - history.push('/error'); - }; - - return { - handleError, - }; -}; - -export { useErrors }; diff --git a/media-store/app-src/src/index.jsx b/media-store/app-src/src/index.jsx deleted file mode 100644 index 8110e69e..00000000 --- a/media-store/app-src/src/index.jsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import App from './App'; -// import * as serviceWorker from './serviceWorker'; - -ReactDOM.render(, document.getElementById('root')); - -// If you want your app to work offline and load faster, you can change -// unregister() to register() below. Note this comes with some pitfalls. -// Learn more about service workers: https://bit.ly/CRA-PWA -// serviceWorker.unregister(); diff --git a/media-store/app-src/src/logo.svg b/media-store/app-src/src/logo.svg deleted file mode 100644 index 6b60c104..00000000 --- a/media-store/app-src/src/logo.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/media-store/app-src/src/serviceWorker.js b/media-store/app-src/src/serviceWorker.js deleted file mode 100644 index e69de29b..00000000 diff --git a/media-store/app-src/src/setupTests.js b/media-store/app-src/src/setupTests.js deleted file mode 100644 index 74b1a275..00000000 --- a/media-store/app-src/src/setupTests.js +++ /dev/null @@ -1,5 +0,0 @@ -// jest-dom adds custom jest matchers for asserting on DOM nodes. -// allows you to do things like: -// expect(element).toHaveTextContent(/react/i) -// learn more: https://github.com/testing-library/jest-dom -import '@testing-library/jest-dom/extend-expect'; diff --git a/media-store/app-src/src/util/EventEmitter.js b/media-store/app-src/src/util/EventEmitter.js deleted file mode 100644 index b28a45af..00000000 --- a/media-store/app-src/src/util/EventEmitter.js +++ /dev/null @@ -1,5 +0,0 @@ -import EventEmitter from 'events'; - -const emitter = new EventEmitter(); - -export { emitter }; diff --git a/media-store/app-src/src/util/constants.js b/media-store/app-src/src/util/constants.js deleted file mode 100644 index 4b9b4460..00000000 --- a/media-store/app-src/src/util/constants.js +++ /dev/null @@ -1,7 +0,0 @@ -export const AVAILABLE_LOCALES = ['en', 'fr', 'de']; - -export const MESSAGE_TIMEOUT = 2; - -export const requireEmployee = (user) => !!user && user.roles.includes('employee'); - -export const requireCustomer = (user) => !!user && user.roles.includes('customer'); diff --git a/media-store/app-src/src/util/localStorageService.js b/media-store/app-src/src/util/localStorageService.js deleted file mode 100644 index 853b4817..00000000 --- a/media-store/app-src/src/util/localStorageService.js +++ /dev/null @@ -1,36 +0,0 @@ -import { isValidUser } from './validateUser'; -import { AVAILABLE_LOCALES } from './constants'; - -const setUserToLS = (user) => { - if (user) { - localStorage.setItem('user', JSON.stringify(user)); - } else { - localStorage.removeItem('user'); - } -}; - -const getUserFromLS = () => { - let userFromLS; - try { - userFromLS = JSON.parse(localStorage.getItem('user')); - if (isValidUser(userFromLS)) { - return userFromLS; - } - } catch (e) { - console.error('User from local storage are not valid'); - } - return undefined; -}; - -const getLocaleFromLS = () => { - const localeFromLS = localStorage.getItem('locale'); - return localeFromLS && localeFromLS !== 'undefined' && AVAILABLE_LOCALES.includes(localeFromLS) - ? localeFromLS - : 'en'; -}; - -const setLocaleToLS = (locale) => { - localStorage.setItem('locale', locale); -}; - -export { setLocaleToLS, getLocaleFromLS, getUserFromLS, setUserToLS }; diff --git a/media-store/app-src/src/util/validateUser.js b/media-store/app-src/src/util/validateUser.js deleted file mode 100644 index b2d52b29..00000000 --- a/media-store/app-src/src/util/validateUser.js +++ /dev/null @@ -1,18 +0,0 @@ -import { isArray, isEmpty, isString, isNumber } from 'lodash'; - -const CUSTOMER_ROLE = 'customer'; -const EMPLOYEE_ROLE = 'employee'; - -const isValidUser = (user) => { - return ( - !isEmpty(user) && - isNumber(user.ID) && - isArray(user.roles) && - !!user.roles.some((role) => role === CUSTOMER_ROLE || role === EMPLOYEE_ROLE) && - isString(user.email) && - isString(user.accessToken) && - isString(user.refreshToken) - ); -}; - -export { isValidUser }; diff --git a/media-store/app-src/webpack/common-plugins.js b/media-store/app-src/webpack/common-plugins.js deleted file mode 100644 index 9ae39a04..00000000 --- a/media-store/app-src/webpack/common-plugins.js +++ /dev/null @@ -1,33 +0,0 @@ -const path = require('path'); -const webpack = require('webpack'); -const { CleanWebpackPlugin } = require('clean-webpack-plugin'); -const HtmlWebpackPlugin = require('html-webpack-plugin'); -const CopyPlugin = require('copy-webpack-plugin'); -const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); - -module.exports = { - plugins: [ - new CleanWebpackPlugin(), - new HtmlWebpackPlugin({ - template: path.join(__dirname, '../public/index.html'), - filename: path.join(__dirname, '../../app/index.html'), - publicPath: '/static/', // for js bundles path - }), - new InterpolateHtmlPlugin(HtmlWebpackPlugin, { - PUBLIC_URL: '', - }), - new CopyPlugin({ - patterns: [ - { - from: path.join(__dirname, '../public'), - to: path.join(__dirname, '../../app'), - globOptions: { - dot: true, - ignore: ['**/index.html'], - }, - }, - ], - }), - new webpack.ProgressPlugin(), - ], -}; diff --git a/media-store/app-src/webpack/common-rules.js b/media-store/app-src/webpack/common-rules.js deleted file mode 100644 index 1afcc25e..00000000 --- a/media-store/app-src/webpack/common-rules.js +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = { - rules: [ - { - test: /\.(js|jsx)$/, - exclude: /(node_modules)/, - use: { - loader: 'babel-loader', - options: { - presets: ['@babel/preset-env', '@babel/preset-react'], - }, - }, - }, - { - test: /\.(png|jpg)$/, - use: [{ loader: 'url-loader' }], - }, - ], -}; diff --git a/media-store/app-src/webpack/webpack-dev-server.js b/media-store/app-src/webpack/webpack-dev-server.js deleted file mode 100644 index f0efb72e..00000000 --- a/media-store/app-src/webpack/webpack-dev-server.js +++ /dev/null @@ -1,56 +0,0 @@ -const path = require('path'); -const webpack = require('webpack'); -const HtmlWebpackPlugin = require('html-webpack-plugin'); -const { CleanWebpackPlugin } = require('clean-webpack-plugin'); -const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); -const { rules } = require('./common-rules'); - -module.exports = { - mode: 'development', - devtool: 'inline-source-map', - entry: { - index: './src/index.jsx', - }, - devServer: { - contentBase: './dist', - compress: true, // compress files to gzip to increase download speed - port: 3000, - disableHostCheck: false, // by default true, it is not recomended, - // because it makes app vulnerable to DNS rebinding attacks - headers: { - 'X-Custom-header': 'custom', // this requires apps with authentication - // useful config obj - }, - open: true, // open the browser after server had been started - hot: true, // hot module replacement - historyApiFallback: true, // needs for react-router-dom - }, - plugins: [ - new CleanWebpackPlugin({ cleanStaleWebpackAssets: false }), - new HtmlWebpackPlugin({ - template: path.join(__dirname, '../public/index.html'), - }), - new InterpolateHtmlPlugin(HtmlWebpackPlugin, { - PUBLIC_URL: '', - }), - new webpack.ProgressPlugin(), - new webpack.DefinePlugin({ - 'process.env.SERVICE_URL': JSON.stringify('http://localhost:4004/'), - }), - // new webpack.HotModuleReplacementPlugin(), // for hot module replacement option of devServer - ], - output: { - filename: '[name].[fullhash].js', - path: path.resolve(__dirname, 'dist'), - }, - module: { - rules: [ - ...rules, - { - test: /\.css$/, - use: [{ loader: 'style-loader' }, { loader: 'css-loader' }], - }, - ], - }, - resolve: { extensions: ['*', '.js', '.jsx'] }, -}; diff --git a/media-store/app-src/webpack/webpack.common.js b/media-store/app-src/webpack/webpack.common.js deleted file mode 100644 index 83b11f1f..00000000 --- a/media-store/app-src/webpack/webpack.common.js +++ /dev/null @@ -1,25 +0,0 @@ -const path = require('path'); - -module.exports = { - entry: { - app: './src/index.jsx', // Bundle with our code - react: ['react', 'react-dom'], - lodash: ['lodash'], - moment: ['moment'], - events: ['events'], - axios: ['axios'], - antd: ['antd'], - }, - output: { - // [name] - name of the entry (bundle), - // [checksum] or [hash] - to cache different bundles - // from update when developing (doing changes in the files) - filename: '[name].[fullhash].js', - // in this folder path bundles will be placed - path: path.resolve(__dirname, '../../app/static'), - // where you uploaded your bundled files. (Relative to server root) - // needs for react-router-dom - publicPath: '/static/', - }, - resolve: { extensions: ['*', '.js', '.jsx'] }, -}; diff --git a/media-store/app-src/webpack/webpack.dev.js b/media-store/app-src/webpack/webpack.dev.js deleted file mode 100644 index ef02a698..00000000 --- a/media-store/app-src/webpack/webpack.dev.js +++ /dev/null @@ -1,25 +0,0 @@ -const webpack = require('webpack'); -const { merge } = require('webpack-merge'); -const common = require('./webpack.common.js'); -const { rules } = require('./common-rules'); -const { plugins } = require('./common-plugins'); - -module.exports = merge(common, { - mode: 'development', - devtool: 'inline-source-map', - plugins: [ - ...plugins, - new webpack.DefinePlugin({ - 'process.env.SERVICE_URL': JSON.stringify('http://localhost:4004/'), - }), - ], - module: { - rules: [ - ...rules, - { - test: /\.css$/, - use: [{ loader: 'style-loader' }, { loader: 'css-loader' }], - }, - ], - }, -}); diff --git a/media-store/app-src/webpack/webpack.prod.js b/media-store/app-src/webpack/webpack.prod.js deleted file mode 100644 index bb047d76..00000000 --- a/media-store/app-src/webpack/webpack.prod.js +++ /dev/null @@ -1,40 +0,0 @@ -const webpack = require('webpack'); -const { merge } = require('webpack-merge'); -const MiniCssExtractPlugin = require('mini-css-extract-plugin'); -const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); -const TerserPlugin = require('terser-webpack-plugin'); -const common = require('./webpack.common.js'); -const { rules } = require('./common-rules'); -const { plugins } = require('./common-plugins'); - -module.exports = merge(common, { - mode: 'production', - devtool: 'source-map', - plugins: [ - ...plugins, - new webpack.DefinePlugin({ - 'process.env.SERVICE_URL': JSON.stringify('api/'), - }), - new MiniCssExtractPlugin({ - filename: '[name].css', - chunkFilename: '[id].css', - }), - ], - optimization: { - splitChunks: { - // To split up js code to different bundles. - chunks: 'all', // Now bundle with our code will be cleaned up - }, // from vendors imports (2mb ~> 100kb) - minimize: true, - minimizer: [new TerserPlugin(), new CssMinimizerPlugin()], // to minimize file size - }, - module: { - rules: [ - ...rules, - { - test: /\.css$/, - use: [MiniCssExtractPlugin.loader, 'css-loader'], - }, - ], - }, -}); diff --git a/media-store/deployers/approuter/package.json b/media-store/deployers/approuter/package.json deleted file mode 100644 index d9a4cd89..00000000 --- a/media-store/deployers/approuter/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "media-store-approuter", - "description": "Approuter", - "version": "1.0.0", - "dependencies": { - "@sap/approuter": "^6.8.2" - }, - "scripts": { - "start": "node node_modules/@sap/approuter/approuter.js" - } -} diff --git a/media-store/deployers/approuter/xs-app.json b/media-store/deployers/approuter/xs-app.json deleted file mode 100644 index 4270e0cb..00000000 --- a/media-store/deployers/approuter/xs-app.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "welcomeFile": "/index.html", - "authenticationMethod": "none", - "routes": [ - { - "source": "/api/(.*)", - "target": "$1", - "destination": "srv-binding", - "authenticationType": "none" - }, - { - "source": "^(.*)", - "target": "mediastore/$1", - "service": "html5-apps-repo-rt" - } - ] -} diff --git a/media-store/deployers/html5Deployer/package.json b/media-store/deployers/html5Deployer/package.json deleted file mode 100644 index 09f597b2..00000000 --- a/media-store/deployers/html5Deployer/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "media-store-html5deployer", - "engines": { - "node": ">=6.0.0" - }, - "dependencies": { - "@sap/html5-app-deployer": "^2.0.0" - }, - "scripts": { - "start": "node node_modules/@sap/html5-app-deployer/index.js" - } -} diff --git a/media-store/deployers/xs-security.json b/media-store/deployers/xs-security.json deleted file mode 100644 index fd42b7a2..00000000 --- a/media-store/deployers/xs-security.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "xsappname": "media-store-xsuaa", - "tenant-mode": "dedicated", - "scopes": [], - "attributes": [], - "role-templates": [] -} diff --git a/media-store/mta.yaml b/media-store/mta.yaml index 60f2ca04..fff60868 100644 --- a/media-store/mta.yaml +++ b/media-store/mta.yaml @@ -48,7 +48,7 @@ modules: - name: media-store-hmtl5-deployer # ------------------------------------------------------------ type: com.sap.html5.application-content - path: deployers/html5Deployer + path: app/deployers/html5Deployer requires: - name: media-store-html5-host build-parameters: @@ -71,7 +71,7 @@ modules: - name: media-store-approuter # ------------------------------------------------------------ type: approuter.nodejs - path: deployers/approuter + path: app/deployers/approuter requires: - name: media-store-html5-runtime - name: media-store-xsuaa @@ -119,7 +119,7 @@ resources: - name: media-store-xsuaa # ------------------------------------------------------------ parameters: - path: deployers/xs-security.json + path: app/deployers/xs-security.json service-plan: application service: xsuaa type: org.cloudfoundry.managed-service