Compare commits
2 commits
fa97a8f126
...
ac3df61fec
Author | SHA1 | Date | |
---|---|---|---|
|
ac3df61fec | ||
|
187ae9cfbb |
16 changed files with 446 additions and 28 deletions
45
bfrontend/package-lock.json
generated
45
bfrontend/package-lock.json
generated
|
@ -3487,8 +3487,7 @@
|
||||||
"binary-extensions": {
|
"binary-extensions": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
|
||||||
"integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
|
"integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ=="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"bluebird": {
|
"bluebird": {
|
||||||
"version": "3.7.2",
|
"version": "3.7.2",
|
||||||
|
@ -3884,7 +3883,6 @@
|
||||||
"version": "3.4.3",
|
"version": "3.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz",
|
||||||
"integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==",
|
"integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"anymatch": "~3.1.1",
|
"anymatch": "~3.1.1",
|
||||||
"braces": "~3.0.2",
|
"braces": "~3.0.2",
|
||||||
|
@ -7566,7 +7564,6 @@
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"binary-extensions": "^2.0.0"
|
"binary-extensions": "^2.0.0"
|
||||||
}
|
}
|
||||||
|
@ -10075,6 +10072,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
|
||||||
"integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE="
|
"integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE="
|
||||||
},
|
},
|
||||||
|
"nan": {
|
||||||
|
"version": "2.14.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
|
||||||
|
"integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"nanoid": {
|
"nanoid": {
|
||||||
"version": "3.1.20",
|
"version": "3.1.20",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz",
|
||||||
|
@ -10253,6 +10256,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.67.tgz",
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.67.tgz",
|
||||||
"integrity": "sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg=="
|
"integrity": "sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg=="
|
||||||
},
|
},
|
||||||
|
"nord": {
|
||||||
|
"version": "0.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/nord/-/nord-0.2.1.tgz",
|
||||||
|
"integrity": "sha1-BE7Y4AMxyEqW3ExnDwgKclcsPPk="
|
||||||
|
},
|
||||||
"normalize-package-data": {
|
"normalize-package-data": {
|
||||||
"version": "2.5.0",
|
"version": "2.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
|
||||||
|
@ -12193,6 +12201,11 @@
|
||||||
"whatwg-fetch": "^3.4.1"
|
"whatwg-fetch": "^3.4.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-content-loader": {
|
||||||
|
"version": "5.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-content-loader/-/react-content-loader-5.1.4.tgz",
|
||||||
|
"integrity": "sha512-hTq7pZi2GKCK6a9d3u6XStozm0QGCEjw8cSqQReiWnh2up6IwCha5R5TF0o6SY5qUDpByloEZEZtnFxpJyENFw=="
|
||||||
|
},
|
||||||
"react-dev-utils": {
|
"react-dev-utils": {
|
||||||
"version": "11.0.1",
|
"version": "11.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.1.tgz",
|
||||||
|
@ -12306,6 +12319,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||||
},
|
},
|
||||||
|
"react-media-hook": {
|
||||||
|
"version": "0.4.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-media-hook/-/react-media-hook-0.4.9.tgz",
|
||||||
|
"integrity": "sha512-FZr/2xA1+23vDJ1IZ794yLqMRRkBoCNOiJATdtTfB5GyVc5djf8FL2qEB/68pSkiNgHdHsmKknMSDr0sC4zBKQ=="
|
||||||
|
},
|
||||||
"react-redux": {
|
"react-redux": {
|
||||||
"version": "7.2.2",
|
"version": "7.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.2.tgz",
|
||||||
|
@ -12528,7 +12546,6 @@
|
||||||
"version": "3.5.0",
|
"version": "3.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
|
||||||
"integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
|
"integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"picomatch": "^2.2.1"
|
"picomatch": "^2.2.1"
|
||||||
}
|
}
|
||||||
|
@ -13241,6 +13258,14 @@
|
||||||
"resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-10.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-10.0.0.tgz",
|
||||||
"integrity": "sha512-vTxrZz4dX5W86M6oVWVdOVe72ZiPs41Oi7Z6Km4W5Turyz28mrXSJhhEBZoRtzJWIv3833WKVwLSDWWkEfupMg=="
|
"integrity": "sha512-vTxrZz4dX5W86M6oVWVdOVe72ZiPs41Oi7Z6Km4W5Turyz28mrXSJhhEBZoRtzJWIv3833WKVwLSDWWkEfupMg=="
|
||||||
},
|
},
|
||||||
|
"sass": {
|
||||||
|
"version": "1.32.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/sass/-/sass-1.32.0.tgz",
|
||||||
|
"integrity": "sha512-fhyqEbMIycQA4blrz/C0pYhv2o4x2y6FYYAH0CshBw3DXh5D5wyERgxw0ptdau1orc/GhNrhF7DFN2etyOCEng==",
|
||||||
|
"requires": {
|
||||||
|
"chokidar": ">=2.0.0 <4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"sass-loader": {
|
"sass-loader": {
|
||||||
"version": "8.0.2",
|
"version": "8.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-8.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-8.0.2.tgz",
|
||||||
|
@ -15176,7 +15201,10 @@
|
||||||
"version": "1.2.13",
|
"version": "1.2.13",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
|
||||||
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
|
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
|
||||||
"optional": true
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"nan": "^2.12.1"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"glob-parent": {
|
"glob-parent": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
|
@ -15775,7 +15803,10 @@
|
||||||
"version": "1.2.13",
|
"version": "1.2.13",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
|
||||||
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
|
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
|
||||||
"optional": true
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"nan": "^2.12.1"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"glob-parent": {
|
"glob-parent": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
|
|
|
@ -6,12 +6,16 @@
|
||||||
"@testing-library/jest-dom": "^5.11.6",
|
"@testing-library/jest-dom": "^5.11.6",
|
||||||
"@testing-library/react": "^11.2.2",
|
"@testing-library/react": "^11.2.2",
|
||||||
"@testing-library/user-event": "^12.6.0",
|
"@testing-library/user-event": "^12.6.0",
|
||||||
|
"nord": "^0.2.1",
|
||||||
"react": "^17.0.1",
|
"react": "^17.0.1",
|
||||||
|
"react-content-loader": "^5.1.4",
|
||||||
"react-dom": "^17.0.1",
|
"react-dom": "^17.0.1",
|
||||||
|
"react-media-hook": "^0.4.9",
|
||||||
"react-redux": "^7.2.2",
|
"react-redux": "^7.2.2",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-scripts": "4.0.1",
|
"react-scripts": "4.0.1",
|
||||||
"redux": "^4.0.5",
|
"redux": "^4.0.5",
|
||||||
|
"sass": "^1.32.0",
|
||||||
"web-vitals": "^0.2.4"
|
"web-vitals": "^0.2.4"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -20,7 +24,7 @@
|
||||||
"test": "react-scripts test",
|
"test": "react-scripts test",
|
||||||
"eject": "react-scripts eject"
|
"eject": "react-scripts eject"
|
||||||
},
|
},
|
||||||
"proxy": "http://localhost:3002",
|
"proxy": "http://localhost:3005",
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": [
|
"extends": [
|
||||||
"react-app",
|
"react-app",
|
||||||
|
|
|
@ -1,38 +1,66 @@
|
||||||
import Login from './Auth/Login';
|
import Login from './Auth/Login';
|
||||||
import Root from './Root';
|
import Root from './Root';
|
||||||
import Authenticator from './../Authenticator';
|
import Authenticator from './../Authenticator';
|
||||||
|
import Notification from './Notification';
|
||||||
|
import './../Styles/App.scss';
|
||||||
|
import { couldNotReach } from '../Errors';
|
||||||
|
import CategoryView from './Categories/CategoryView';
|
||||||
|
import Sidebar from './UI/Sidebar';
|
||||||
|
|
||||||
import { useEffect } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useDispatch, connect } from 'react-redux'
|
import { useDispatch, connect } from 'react-redux'
|
||||||
import { BrowserRouter, Switch, Route } from 'react-router-dom';
|
import { BrowserRouter, Switch, Route } from 'react-router-dom';
|
||||||
|
|
||||||
function App({ user }) {
|
function App({ user }) {
|
||||||
|
const [ notificationText, setNotificationText ] = useState('');
|
||||||
|
const [ hasError, setHasError ] = useState(false);
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
Authenticator.getLoggedInUserFromCookie()
|
Authenticator.getLoggedInUserFromCookie()
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
dispatch({ type: 'authenticator/updatelocaluserobject', user: res })
|
dispatch({ type: 'authenticator/updatelocaluserobject', user: res })
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setNotificationText(couldNotReach);
|
||||||
|
setHasError(true);
|
||||||
});
|
});
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
return (
|
if (!hasError) {
|
||||||
<BrowserRouter>
|
return (
|
||||||
<Switch>
|
<div id="main-container">
|
||||||
<Route path="/login">
|
<div id="root-container" className="main-display">
|
||||||
<Login />
|
<BrowserRouter>
|
||||||
</Route>
|
<Switch>
|
||||||
<Route path="/">
|
<Route path="/login">
|
||||||
<Root user={user} />
|
<Login />
|
||||||
</Route>
|
</Route>
|
||||||
</Switch>
|
<Route path="/categories/:id">
|
||||||
</BrowserRouter>
|
<Sidebar />
|
||||||
);
|
<CategoryView />
|
||||||
|
</Route>
|
||||||
|
<Route path="/">
|
||||||
|
<Root user={user} />
|
||||||
|
</Route>
|
||||||
|
</Switch>
|
||||||
|
</BrowserRouter>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<div id="main-container">
|
||||||
|
<Notification text={notificationText}/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const stateToProps = (state) => {
|
const stateToProps = (state) => {
|
||||||
return {
|
return {
|
||||||
user: state?.user || undefined
|
user: state?.user,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
11
bfrontend/src/Components/Categories/CategoryButton.js
Normal file
11
bfrontend/src/Components/Categories/CategoryButton.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
|
export default function CategoryButton({ category }) {
|
||||||
|
const history = useHistory();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button className="button category-button" onClick={ () => history.push(`/categories/${category._id}`) }>
|
||||||
|
{ category.title }
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
53
bfrontend/src/Components/Categories/CategoryList.js
Normal file
53
bfrontend/src/Components/Categories/CategoryList.js
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import CategoryListLoader from './CategoryListLoader';
|
||||||
|
import CategoryButton from './CategoryButton';
|
||||||
|
import APIRequest from '../../APIRequest';
|
||||||
|
import { couldNotReach } from '../../Errors';
|
||||||
|
|
||||||
|
import { useDispatch } from 'react-redux'
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
export default function CategoryList() {
|
||||||
|
const [ categoryList, setCategoryList ] = useState();
|
||||||
|
const [ error, setError ] = useState();
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
APIRequest.authenticated('/api/v1/content/category/list?count=50')
|
||||||
|
.then(({ isOK, json }) => {
|
||||||
|
if (!isOK) return setError(true);
|
||||||
|
setCategoryList(json.categories || []);
|
||||||
|
|
||||||
|
dispatch({ type: 'categories/updatecategorylist', categories: json.categories });
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setError(true);
|
||||||
|
});
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
|
if (!categoryList) {
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
{ couldNotReach }
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<CategoryListLoader />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<div className="category-list">
|
||||||
|
{categoryList.map((category) =>
|
||||||
|
<CategoryButton key={ category._id } category={ category } />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
44
bfrontend/src/Components/Categories/CategoryListLoader.js
Normal file
44
bfrontend/src/Components/Categories/CategoryListLoader.js
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import ContentLoader from "react-content-loader"
|
||||||
|
import { useMediaPredicate } from "react-media-hook";
|
||||||
|
|
||||||
|
export default function CategoryListLoader(props) {
|
||||||
|
const lessThan600 = useMediaPredicate("(max-width: 600px)");
|
||||||
|
|
||||||
|
if (lessThan600) {
|
||||||
|
return (
|
||||||
|
<ContentLoader
|
||||||
|
speed={1.5}
|
||||||
|
width={62}
|
||||||
|
height={300}
|
||||||
|
viewBox="0 0 62 300"
|
||||||
|
backgroundColor="#434c5e"
|
||||||
|
foregroundColor="#4c566a"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<rect x="6" y="5" rx="0" ry="0" width="50" height="25" />
|
||||||
|
<rect x="6" y="35" rx="0" ry="0" width="50" height="25" />
|
||||||
|
<rect x="6" y="65" rx="0" ry="0" width="50" height="25" />
|
||||||
|
<rect x="6" y="95" rx="0" ry="0" width="50" height="25" />
|
||||||
|
<rect x="6" y="125" rx="0" ry="0" width="50" height="25" />
|
||||||
|
</ContentLoader>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<ContentLoader
|
||||||
|
speed={1.5}
|
||||||
|
width={112}
|
||||||
|
height={300}
|
||||||
|
viewBox="0 0 112 300"
|
||||||
|
backgroundColor="#434c5e"
|
||||||
|
foregroundColor="#4c566a"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<rect x="6" y="5" rx="0" ry="0" width="100" height="25" />
|
||||||
|
<rect x="6" y="35" rx="0" ry="0" width="100" height="25" />
|
||||||
|
<rect x="6" y="65" rx="0" ry="0" width="100" height="25" />
|
||||||
|
<rect x="6" y="95" rx="0" ry="0" width="100" height="25" />
|
||||||
|
<rect x="6" y="125" rx="0" ry="0" width="100" height="25" />
|
||||||
|
</ContentLoader>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
55
bfrontend/src/Components/Categories/CategoryView.js
Normal file
55
bfrontend/src/Components/Categories/CategoryView.js
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
import CategoryViewLoader from './CategoryViewLoader';
|
||||||
|
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
|
||||||
|
function CategoryView({ categories }) {
|
||||||
|
const { id } = useParams();
|
||||||
|
|
||||||
|
let category;
|
||||||
|
|
||||||
|
if (categories) {
|
||||||
|
category = categories.find(x => x._id === id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (category) {
|
||||||
|
return (
|
||||||
|
<div className="card main-card main-content-card">
|
||||||
|
<div className="card bar-card">
|
||||||
|
{ category.title }
|
||||||
|
</div>
|
||||||
|
<div className="card message-list-card">
|
||||||
|
In terms of development, the first year of a cat’s life is equal to the first 15 years of a human life. After its second year, a cat is 25 in human years. And after that, each year of a cat’s life is equal to about 7 human years.
|
||||||
|
Cats can rotate their ears 180 degrees.
|
||||||
|
</div>
|
||||||
|
<div className="card bar-card-bottom">
|
||||||
|
The hearing of the average cat is at least five times keener than that of a human adult.
|
||||||
|
In the largest cat breed, the average male weighs approximately 20 pounds.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<div className="card main-card main-content-card">
|
||||||
|
<div className="card bar-card">
|
||||||
|
<CategoryViewLoader />
|
||||||
|
</div>
|
||||||
|
<div className="card message-list-card">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div className="card bar-card-bottom">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const stateToProps = (state) => {
|
||||||
|
return {
|
||||||
|
categories: state?.categories
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(stateToProps)(CategoryView);
|
17
bfrontend/src/Components/Categories/CategoryViewLoader.js
Normal file
17
bfrontend/src/Components/Categories/CategoryViewLoader.js
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import ContentLoader from "react-content-loader"
|
||||||
|
|
||||||
|
export default function CategoryViewLoader(props) {
|
||||||
|
return (
|
||||||
|
<ContentLoader
|
||||||
|
speed={1.5}
|
||||||
|
width={100}
|
||||||
|
height={40}
|
||||||
|
viewBox="0 0 100 40"
|
||||||
|
backgroundColor="#434c5e"
|
||||||
|
foregroundColor="#4c566a"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<rect x="6" y="6" rx="0" ry="0" width="100" height="24" />
|
||||||
|
</ContentLoader>
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,17 +1,16 @@
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
|
import Sidebar from './UI/Sidebar';
|
||||||
|
|
||||||
export default function Root(props) {
|
export default function Root(props) {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
if (props.user) {
|
if (props.user) {
|
||||||
return (
|
return (
|
||||||
<div id="root-container">
|
<Sidebar />
|
||||||
<h1>Welcome, { props.user.username }</h1>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<div id="root-container">
|
<div id="login-message-container">
|
||||||
<h1>Welcome, - nevermind, you aren't logged in</h1>
|
<h1>Welcome, - nevermind, you aren't logged in</h1>
|
||||||
<button onClick={ () => { history.push('/login') } }>Log in</button>
|
<button onClick={ () => { history.push('/login') } }>Log in</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
9
bfrontend/src/Components/UI/Sidebar.js
Normal file
9
bfrontend/src/Components/UI/Sidebar.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import CategoryList from '../Categories/CategoryList';
|
||||||
|
|
||||||
|
export default function Sidebar() {
|
||||||
|
return (
|
||||||
|
<div className="card main-card category-list-container">
|
||||||
|
<CategoryList />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -110,4 +110,6 @@ const getCreateCategoryError = (json) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = { getLoginMessageFromError, getSignupMessageFromError, getCreatePostError, getCreateCategoryError }
|
const couldNotReach = "Whoops! We couldn't reach Brainlet."
|
||||||
|
|
||||||
|
module.exports = { couldNotReach, getLoginMessageFromError, getSignupMessageFromError, getCreatePostError, getCreateCategoryError }
|
BIN
bfrontend/src/Images/defaultprofile_256px-256px.png
Normal file
BIN
bfrontend/src/Images/defaultprofile_256px-256px.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 645 B |
159
bfrontend/src/Styles/App.scss
Normal file
159
bfrontend/src/Styles/App.scss
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
@import "../../node_modules/nord/src/sass/nord.scss";
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--background-color: #{$nord0};
|
||||||
|
|
||||||
|
--default-main-card-color: #{$nord1};
|
||||||
|
--card-box-shadow-color:rgba(0, 0, 0, 0.25);
|
||||||
|
|
||||||
|
--default-text-color: #{$nord5};
|
||||||
|
|
||||||
|
--accent-color-dark: #{$nord2};
|
||||||
|
--accent-color-light: #{$nord3};
|
||||||
|
|
||||||
|
--default-transition-duration: 200ms;
|
||||||
|
--default-border-radius: 0px;
|
||||||
|
--default-button-border-radius: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 0px;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: var(--accent-color-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: var(--default-main-card-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin card {
|
||||||
|
padding: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
background-color: var(--default-main-card-color);
|
||||||
|
border-radius: var(--default-border-radius);
|
||||||
|
box-shadow: 0px 3px 5px var(--card-box-shadow-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin fancy-scrollbar-firefox {
|
||||||
|
scrollbar-width: none;
|
||||||
|
scrollbar-color: var(--default-main-card-color) var(--accent-color-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
|
||||||
|
color: var(--default-text-color);
|
||||||
|
font-family: Noto Sans,-apple-system,BlinkMacSystemFont,sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-display {
|
||||||
|
padding: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
display: flex;
|
||||||
|
background-color: var(--background-color);
|
||||||
|
min-height: 100vh;
|
||||||
|
max-height: 100vh;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
@include card;
|
||||||
|
|
||||||
|
&.bar-card {
|
||||||
|
background-color: var(--accent-color-dark);
|
||||||
|
min-height: 40px;
|
||||||
|
|
||||||
|
border-radius: var(--default-button-border-radius) var(--default-button-border-radius) 0px 0px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: left;
|
||||||
|
|
||||||
|
font-size: large;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bar-card-bottom {
|
||||||
|
background-color: var(--accent-color-dark);
|
||||||
|
min-height: 30px;
|
||||||
|
|
||||||
|
border-radius: 0px 0px var(--default-button-border-radius) var(--default-button-border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.message-list-card {
|
||||||
|
border-radius: 0px;
|
||||||
|
flex-grow: 1;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-card {
|
||||||
|
@include card;
|
||||||
|
|
||||||
|
margin: 12px;
|
||||||
|
|
||||||
|
&.main-content-card {
|
||||||
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
@include card;
|
||||||
|
|
||||||
|
padding: 5px;
|
||||||
|
margin: 5px;
|
||||||
|
border: 0px;
|
||||||
|
background-color: var(--accent-color-dark);
|
||||||
|
color: var(--default-text-color);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color, var(--default-transition-duration);
|
||||||
|
border-radius: var(--default-button-border-radius);
|
||||||
|
min-height: 25px;
|
||||||
|
|
||||||
|
&.category-button {
|
||||||
|
min-width: 100px;
|
||||||
|
max-width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.pressed {
|
||||||
|
background-color: var(--accent-color-light);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:hover {
|
||||||
|
background-color: var(--accent-color-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-list-container {
|
||||||
|
@include fancy-scrollbar-firefox;
|
||||||
|
|
||||||
|
overflow: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
|
||||||
|
min-width: 110px;
|
||||||
|
max-width: 110px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 600px) {
|
||||||
|
.button.category-button {
|
||||||
|
min-width: 50px;
|
||||||
|
max-width: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-list-container {
|
||||||
|
min-width: 60px;
|
||||||
|
max-width: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-card {
|
||||||
|
margin: 6px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
import store from './store';
|
import store from './store';
|
||||||
import './index.css';
|
|
||||||
import App from './Components/App';
|
import App from './Components/App';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
|
@ -9,6 +9,13 @@ const reducer = (state, payload) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'categories/updatecategorylist': {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
categories: payload.categories
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue