Browse Source

Case-insensitive sorting. App version checking

unknown 4 years ago
parent
commit
9a1ec76ffd

+ 0 - 0
._env


+ 2 - 0
.env

@@ -0,0 +1,2 @@
+PORT=5005
+NODE_ENV=development

+ 1 - 2
.gitignore

@@ -1,3 +1,2 @@
 node_modules/
-data/
-.env
+data/

+ 1 - 0
client/.env

@@ -0,0 +1 @@
+REACT_APP_VERSION=1.3.2

+ 8 - 0
client/src/App.tsx

@@ -5,6 +5,10 @@ import { getConfig, setTheme } from './store/actions';
 import { store } from './store/store';
 import { Provider } from 'react-redux';
 
+// Utils
+import { checkVersion } from './utility';
+
+// Routes
 import Home from './components/Home/Home';
 import Apps from './components/Apps/Apps';
 import Settings from './components/Settings/Settings';
@@ -14,10 +18,14 @@ import NotificationCenter from './components/NotificationCenter/NotificationCent
 // Get config pairs from database
 store.dispatch<any>(getConfig());
 
+// Set theme
 if (localStorage.theme) {
   store.dispatch<any>(setTheme(localStorage.theme));
 }
 
+// Check for updates
+checkVersion();
+
 const App = (): JSX.Element => {
   return (
     <Provider store={store}>

+ 8 - 0
client/src/components/Settings/AppDetails/AppDetails.module.css

@@ -0,0 +1,8 @@
+.AppVersion {
+  color: var(--color-primary);
+  margin-bottom: 15px;
+}
+
+.AppVersion a {
+  color: var(--color-accent);
+}

+ 25 - 0
client/src/components/Settings/AppDetails/AppDetails.tsx

@@ -0,0 +1,25 @@
+import { Fragment } from 'react';
+
+import classes from './AppDetails.module.css';
+import Button from '../../UI/Buttons/Button/Button';
+import { checkVersion } from '../../../utility';
+
+const AppDetails = (): JSX.Element => {
+  return (
+    <Fragment>
+      <p className={classes.AppVersion}>
+        <a
+          href='https://github.com/pawelmalak/flame'
+          target='_blank'
+          rel='noreferrer'>
+          Flame
+        </a>
+        {' '}
+        version {process.env.REACT_APP_VERSION}
+      </p>
+      <Button click={() => checkVersion(true)}>Check for updates</Button>
+    </Fragment>
+  )
+}
+
+export default AppDetails;

+ 12 - 2
client/src/components/Settings/Settings.tsx

@@ -1,12 +1,14 @@
-import { NavLink, Link, Switch, Route, withRouter } from 'react-router-dom';
+import { NavLink, Link, Switch, Route } from 'react-router-dom';
 
 import classes from './Settings.module.css';
 
 import { Container } from '../UI/Layout/Layout';
 import Headline from '../UI/Headlines/Headline/Headline';
+
 import Themer from '../Themer/Themer';
 import WeatherSettings from './WeatherSettings/WeatherSettings';
 import OtherSettings from './OtherSettings/OtherSettings';
+import AppDetails from './AppDetails/AppDetails';
 
 const Settings = (): JSX.Element => {
   return (
@@ -38,12 +40,20 @@ const Settings = (): JSX.Element => {
             to='/settings/other'>
             Other
           </NavLink>
+          <NavLink
+            className={classes.SettingsNavLink}
+            activeClassName={classes.SettingsNavLinkActive}
+            exact
+            to='/settings/app'>
+            App
+          </NavLink>
         </nav>
         <section className={classes.SettingsContent}>
           <Switch>
             <Route exact path='/settings' component={Themer} />
             <Route path='/settings/weather' component={WeatherSettings} />
             <Route path='/settings/other' component={OtherSettings} />
+            <Route path='/settings/app' component={AppDetails} />
           </Switch>
         </section>
       </div>
@@ -51,4 +61,4 @@ const Settings = (): JSX.Element => {
   )
 }
 
-export default withRouter(Settings);
+export default Settings;

+ 1 - 2
client/src/components/UI/Buttons/Button/Button.module.css

@@ -6,8 +6,7 @@
   border-radius: 4px;
 }
 
-.Button:hover,
-.Button:focus {
+.Button:hover {
   cursor: pointer;
   background-color: var(--color-accent);
   color: var(--color-background);

+ 11 - 1
client/src/components/UI/Buttons/Button/Button.tsx

@@ -2,10 +2,20 @@ import classes from './Button.module.css';
 
 interface ComponentProps {
   children: string;
+  click?: any;
 }
 
 const Button = (props: ComponentProps): JSX.Element => {
-  return <button className={classes.Button}>{props.children}</button>
+  const {
+    children,
+    click
+  } = props;
+
+  return (
+    <button className={classes.Button} onClick={click ? click : () => {}} >
+      {children}
+    </button>
+  )
 }
 
 export default Button;

+ 27 - 0
client/src/utility/checkVersion.ts

@@ -0,0 +1,27 @@
+import axios from 'axios';
+import { store } from '../store/store';
+import { createNotification } from '../store/actions';
+
+export const checkVersion = async (isForced: boolean = false) => {
+  try {
+    const res = await axios.get<string>('https://raw.githubusercontent.com/pawelmalak/flame/master/client/.env');
+
+    const githubVersion = res.data
+      .split('\n')
+      .map(pair => pair.split('='))[0][1];
+
+    if (githubVersion !== process.env.REACT_APP_VERSION) {
+      store.dispatch<any>(createNotification({
+        title: 'Info',
+        message: 'New version is available!'
+      }))
+    } else if (isForced) {
+      store.dispatch<any>(createNotification({
+        title: 'Info',
+        message: 'You are using the latest version!'
+      }))
+    }
+  } catch (err) {
+    console.log(err);
+  }
+}

+ 2 - 1
client/src/utility/index.ts

@@ -1,3 +1,4 @@
 export * from './iconParser';
 export * from './urlParser';
-export * from './searchConfig';
+export * from './searchConfig';
+export * from './checkVersion';

+ 2 - 1
controllers/apps.js

@@ -2,6 +2,7 @@ const asyncWrapper = require('../middleware/asyncWrapper');
 const ErrorResponse = require('../utils/ErrorResponse');
 const App = require('../models/App');
 const Config = require('../models/Config');
+const { Sequelize } = require('sequelize');
 
 // @desc      Create new app
 // @route     POST /api/apps
@@ -36,7 +37,7 @@ exports.createApp = asyncWrapper(async (req, res, next) => {
 // @access    Public
 exports.getApps = asyncWrapper(async (req, res, next) => {
   const apps = await App.findAll({
-    order: [['name', 'ASC']]
+    order: [[ Sequelize.fn('lower', Sequelize.col('name')), 'ASC' ]]
   });
 
   res.status(200).json({

+ 2 - 1
controllers/bookmark.js

@@ -1,6 +1,7 @@
 const asyncWrapper = require('../middleware/asyncWrapper');
 const ErrorResponse = require('../utils/ErrorResponse');
 const Bookmark = require('../models/Bookmark');
+const { Sequelize } = require('sequelize');
 
 // @desc      Create new bookmark
 // @route     POST /api/bookmarks
@@ -19,7 +20,7 @@ exports.createBookmark = asyncWrapper(async (req, res, next) => {
 // @access    Public
 exports.getBookmarks = asyncWrapper(async (req, res, next) => {
   const bookmarks = await Bookmark.findAll({
-    order: [['name', 'ASC']]
+    order: [[ Sequelize.fn('lower', Sequelize.col('name')), 'ASC' ]]
   });
 
   res.status(200).json({

+ 2 - 1
controllers/category.js

@@ -3,6 +3,7 @@ const ErrorResponse = require('../utils/ErrorResponse');
 const Category = require('../models/Category');
 const Bookmark = require('../models/Bookmark');
 const Config = require('../models/Config');
+const { Sequelize } = require('sequelize')
 
 // @desc      Create new category
 // @route     POST /api/categories
@@ -41,7 +42,7 @@ exports.getCategories = asyncWrapper(async (req, res, next) => {
       model: Bookmark,
       as: 'bookmarks'
     }],
-    order: [['name', 'ASC']]
+    order: [[ Sequelize.fn('lower', Sequelize.col('Category.name')), 'ASC' ]]
   });
 
   res.status(200).json({