mirror of
https://github.com/pawelmalak/flame.git
synced 2025-04-23 13:27:21 -04:00
update to latest react version and update client dependencies (#23)
This commit is contained in:
parent
edc3e6c330
commit
9e19af7d4c
30 changed files with 650 additions and 459 deletions
724
client/package-lock.json
generated
724
client/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -3,34 +3,34 @@
|
|||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@mdi/js": "^6.4.95",
|
||||
"@mdi/react": "^1.5.0",
|
||||
"@testing-library/jest-dom": "^5.15.0",
|
||||
"@testing-library/react": "^12.1.2",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"@types/jest": "^27.0.2",
|
||||
"@types/node": "^16.11.6",
|
||||
"@types/react": "^17.0.34",
|
||||
"@types/react-beautiful-dnd": "^13.1.2",
|
||||
"@types/react-dom": "^17.0.11",
|
||||
"@types/react-redux": "^7.1.20",
|
||||
"@types/react-router-dom": "^5.1.7",
|
||||
"axios": "^0.24.0",
|
||||
"external-svg-loader": "^1.3.4",
|
||||
"http-proxy-middleware": "^2.0.1",
|
||||
"@mdi/js": "^7.2.96",
|
||||
"@mdi/react": "^1.6.1",
|
||||
"@testing-library/jest-dom": "^5.17.0",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@testing-library/user-event": "^14.4.3",
|
||||
"@types/jest": "^29.5.3",
|
||||
"@types/node": "^20.4.6",
|
||||
"@types/react": "^18.2.18",
|
||||
"@types/react-beautiful-dnd": "^13.1.4",
|
||||
"@types/react-dom": "^18.2.7",
|
||||
"@types/react-redux": "^7.1.25",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"axios": "^1.4.0",
|
||||
"external-svg-loader": "^1.6.8",
|
||||
"http-proxy-middleware": "^2.0.6",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"react": "^17.0.2",
|
||||
"react-beautiful-dnd": "^13.1.0",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-redux": "^7.2.6",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"redux": "^4.1.2",
|
||||
"react": "^18.2.0",
|
||||
"react-beautiful-dnd": "^13.1.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-redux": "^8.1.2",
|
||||
"react-router-dom": "^6.14.2",
|
||||
"react-scripts": "^5.0.1",
|
||||
"redux": "^4.2.1",
|
||||
"redux-devtools-extension": "^2.13.9",
|
||||
"redux-thunk": "^2.4.0",
|
||||
"skycons-ts": "^0.2.0",
|
||||
"typescript": "^4.4.4",
|
||||
"web-vitals": "^2.1.2"
|
||||
"redux-thunk": "^2.4.2",
|
||||
"skycons-ts": "^1.0.0",
|
||||
"typescript": "^4.9.5",
|
||||
"web-vitals": "^3.4.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
|
@ -57,6 +57,6 @@
|
|||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^2.4.1"
|
||||
"prettier": "^3.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import 'external-svg-loader';
|
|||
|
||||
import { useEffect } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { BrowserRouter, Route, Switch } from 'react-router-dom';
|
||||
import { BrowserRouter, Route, Routes } from 'react-router-dom';
|
||||
import { bindActionCreators } from 'redux';
|
||||
|
||||
import { Apps } from './components/Apps/Apps';
|
||||
|
@ -73,18 +73,18 @@ export const App = (): JSX.Element => {
|
|||
if (!loading && !localStorage.theme) {
|
||||
setTheme(parsePABToTheme(config.defaultTheme), false);
|
||||
}
|
||||
}, [loading]);
|
||||
}, [config.defaultTheme, loading, setTheme]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<BrowserRouter>
|
||||
<Switch>
|
||||
<Route exact path="/" component={Home} />
|
||||
<Route path="/settings" component={Settings} />
|
||||
<Route path="/applications" component={Apps} />
|
||||
<Route path="/bookmarks" component={Bookmarks} />
|
||||
<Route component={NotFound} />
|
||||
</Switch>
|
||||
<Routes>
|
||||
<Route path="/" element={<Home/>} />
|
||||
<Route path="/settings/*" element={<Settings/>} />
|
||||
<Route path="/applications" element={<Apps searching={false}/>} />
|
||||
<Route path="/bookmarks" element={<Bookmarks searching={false}/>} />
|
||||
<Route element={<NotFound/>} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
<NotificationCenter />
|
||||
</>
|
||||
|
|
|
@ -17,10 +17,8 @@ interface Props {
|
|||
export const AppCard = (props: Props): JSX.Element => {
|
||||
const { category, fromHomepage = false } = props;
|
||||
|
||||
const {
|
||||
config: { config },
|
||||
auth: { isAuthenticated },
|
||||
} = useSelector((state: State) => state);
|
||||
const config = useSelector((state: State) => state.config.config);
|
||||
const isAuthenticated = useSelector((state: State) => state.auth.isAuthenticated);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const { setEditCategory } = bindActionCreators(actionCreators, dispatch);
|
||||
|
|
|
@ -22,9 +22,7 @@ export const AppGrid = (props: Props): JSX.Element => {
|
|||
fromHomepage = false,
|
||||
} = props;
|
||||
|
||||
const {
|
||||
config: { config }
|
||||
} = useSelector((state: State) => state);
|
||||
const config = useSelector((state: State) => state.config.config);
|
||||
|
||||
const shouldBeShown = (category: Category) => {
|
||||
return !config.hideEmptyCategories || category.apps.length > 0 || !fromHomepage
|
||||
|
|
|
@ -18,10 +18,8 @@ interface Props {
|
|||
}
|
||||
|
||||
export const AppsTable = ({ openFormForUpdating }: Props): JSX.Element => {
|
||||
const {
|
||||
apps: { categoryInEdit },
|
||||
config: { config },
|
||||
} = useSelector((state: State) => state);
|
||||
const categoryInEdit = useSelector((state: State) => state.apps.categoryInEdit);
|
||||
const config = useSelector((state: State) => state.config.config);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const {
|
||||
|
|
|
@ -23,10 +23,10 @@ export enum ContentType {
|
|||
|
||||
export const Apps = (props: Props): JSX.Element => {
|
||||
// Get Redux state
|
||||
const {
|
||||
apps: { loading, categories, categoryInEdit },
|
||||
auth: { isAuthenticated },
|
||||
} = useSelector((state: State) => state);
|
||||
const categories = useSelector((state: State) => state.apps.categories);
|
||||
const loading = useSelector((state: State) => state.apps.loading);
|
||||
const categoryInEdit = useSelector((state: State) => state.apps.categoryInEdit);
|
||||
const isAuthenticated = useSelector((state: State) => state.auth.isAuthenticated);
|
||||
|
||||
// Get Redux action creators
|
||||
const dispatch = useDispatch();
|
||||
|
|
|
@ -26,7 +26,7 @@ export const AppsForm = ({
|
|||
const { categories } = useSelector((state: State) => state.apps);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const { addApp, updateApp, setEditApp, createNotification } =
|
||||
const { addApp, updateApp, createNotification } =
|
||||
bindActionCreators(actionCreators, dispatch);
|
||||
|
||||
const [useCustomIcon, toggleUseCustomIcon] = useState<boolean>(false);
|
||||
|
|
|
@ -18,10 +18,8 @@ interface Props {
|
|||
}
|
||||
|
||||
export const AppsTable = ({ openFormForUpdating }: Props): JSX.Element => {
|
||||
const {
|
||||
apps: { categoryInEdit },
|
||||
config: { config },
|
||||
} = useSelector((state: State) => state);
|
||||
const categoryInEdit = useSelector((state: State) => state.apps.categoryInEdit);
|
||||
const config = useSelector((state: State) => state.config.config);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const {
|
||||
|
|
|
@ -18,10 +18,8 @@ interface Props {
|
|||
}
|
||||
|
||||
export const CategoryTable = ({ openFormForUpdating }: Props): JSX.Element => {
|
||||
const {
|
||||
config: { config },
|
||||
apps: { categories },
|
||||
} = useSelector((state: State) => state);
|
||||
const categories = useSelector((state: State) => state.apps.categories);
|
||||
const config = useSelector((state: State) => state.config.config);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const {
|
||||
|
|
|
@ -16,11 +16,8 @@ interface Props {
|
|||
|
||||
export const BookmarkCard = (props: Props): JSX.Element => {
|
||||
const { category, fromHomepage = false } = props;
|
||||
|
||||
const {
|
||||
config: { config },
|
||||
auth: { isAuthenticated },
|
||||
} = useSelector((state: State) => state);
|
||||
const config = useSelector((state: State) => state.config.config);
|
||||
const isAuthenticated = useSelector((state: State) => state.auth.isAuthenticated);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const { setEditCategory } = bindActionCreators(actionCreators, dispatch);
|
||||
|
|
|
@ -22,9 +22,7 @@ export const BookmarkGrid = (props: Props): JSX.Element => {
|
|||
fromHomepage = false,
|
||||
} = props;
|
||||
|
||||
const {
|
||||
config: { config }
|
||||
} = useSelector((state: State) => state);
|
||||
const config = useSelector((state: State) => state.config.config);
|
||||
|
||||
const shouldBeShown = (category: Category) => {
|
||||
return !config.hideEmptyCategories || category.bookmarks.length > 0 || !fromHomepage
|
||||
|
|
|
@ -23,10 +23,10 @@ export enum ContentType {
|
|||
|
||||
export const Bookmarks = (props: Props): JSX.Element => {
|
||||
// Get Redux state
|
||||
const {
|
||||
bookmarks: { loading, categories, categoryInEdit },
|
||||
auth: { isAuthenticated },
|
||||
} = useSelector((state: State) => state);
|
||||
const categories = useSelector((state: State) => state.bookmarks.categories);
|
||||
const loading = useSelector((state: State) => state.bookmarks.loading);
|
||||
const categoryInEdit = useSelector((state: State) => state.bookmarks.categoryInEdit);
|
||||
const isAuthenticated = useSelector((state: State) => state.auth.isAuthenticated);
|
||||
|
||||
// Get Redux action creators
|
||||
const dispatch = useDispatch();
|
||||
|
|
|
@ -18,10 +18,8 @@ interface Props {
|
|||
}
|
||||
|
||||
export const BookmarksTable = ({ openFormForUpdating }: Props): JSX.Element => {
|
||||
const {
|
||||
bookmarks: { categoryInEdit },
|
||||
config: { config },
|
||||
} = useSelector((state: State) => state);
|
||||
const categoryInEdit = useSelector((state: State) => state.bookmarks.categoryInEdit);
|
||||
const config = useSelector((state: State) => state.config.config);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const {
|
||||
|
|
|
@ -18,10 +18,8 @@ interface Props {
|
|||
}
|
||||
|
||||
export const CategoryTable = ({ openFormForUpdating }: Props): JSX.Element => {
|
||||
const {
|
||||
config: { config },
|
||||
bookmarks: { categories },
|
||||
} = useSelector((state: State) => state);
|
||||
const categories = useSelector((state: State) => state.bookmarks.categories);
|
||||
const config = useSelector((state: State) => state.config.config);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const {
|
||||
|
|
|
@ -16,12 +16,12 @@ import { Header } from './Header/Header';
|
|||
import classes from './Home.module.css';
|
||||
|
||||
export const Home = (): JSX.Element => {
|
||||
const {
|
||||
apps: { categories: appCategories, loading: appsLoading },
|
||||
bookmarks: { categories: bookmarkCategories, loading: bookmarksLoading },
|
||||
config: { config },
|
||||
auth: { isAuthenticated },
|
||||
} = useSelector((state: State) => state);
|
||||
const appCategories = useSelector((state: State) => state.apps.categories);
|
||||
const appsLoading = useSelector((state: State) => state.apps.loading);
|
||||
const bookmarkCategories = useSelector((state: State) => state.bookmarks.categories);
|
||||
const bookmarksLoading = useSelector((state: State) => state.bookmarks.loading);
|
||||
const config = useSelector((state: State) => state.config.config);
|
||||
const isAuthenticated = useSelector((state: State) => state.auth.isAuthenticated);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const { getCategories } = bindActionCreators(
|
||||
|
@ -41,7 +41,7 @@ export const Home = (): JSX.Element => {
|
|||
if (!appCategories.length && !bookmarkCategories.length) {
|
||||
getCategories();
|
||||
}
|
||||
}, []);
|
||||
}, [appCategories.length, bookmarkCategories.length]);
|
||||
|
||||
useEffect(() => {
|
||||
if (localSearch) {
|
||||
|
@ -81,7 +81,7 @@ export const Home = (): JSX.Element => {
|
|||
setAppSearchResult(null);
|
||||
setBookmarkSearchResult(null);
|
||||
}
|
||||
}, [localSearch]);
|
||||
}, [appCategories, bookmarkCategories, localSearch]);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
import { useSelector } from 'react-redux';
|
||||
import { Redirect, Route, RouteProps } from 'react-router';
|
||||
import { Navigate } from 'react-router';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
|
||||
import { State } from '../../store/reducers';
|
||||
|
||||
export const ProtectedRoute = ({ ...rest }: RouteProps) => {
|
||||
export const ProtectedRoute = () => {
|
||||
const { isAuthenticated } = useSelector((state: State) => state.auth);
|
||||
|
||||
|
||||
if (isAuthenticated) {
|
||||
return <Route {...rest} />;
|
||||
return <Outlet />;
|
||||
} else {
|
||||
return <Redirect to="/settings/app" />;
|
||||
return <Navigate to="/settings/app" />;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -11,11 +11,9 @@ import { Button, InputGroup, SettingsHeadline } from '../../UI';
|
|||
import { CustomQueries } from './CustomQueries/CustomQueries';
|
||||
|
||||
export const GeneralSettings = (): JSX.Element => {
|
||||
const {
|
||||
config: { loading, customQueries, config },
|
||||
apps: { categories: appCategories },
|
||||
bookmarks: { categories: bookmarkCategories },
|
||||
} = useSelector((state: State) => state);
|
||||
const config = useSelector((state: State) => state.config);
|
||||
const appCategories = useSelector((state: State) => state.apps.categories);
|
||||
const bookmarkCategories = useSelector((state: State) => state.bookmarks.categories);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const { updateConfig, sortApps, sortCategories, sortBookmarks } =
|
||||
|
@ -29,9 +27,9 @@ export const GeneralSettings = (): JSX.Element => {
|
|||
// Get config
|
||||
useEffect(() => {
|
||||
setFormData({
|
||||
...config,
|
||||
...config.config,
|
||||
});
|
||||
}, [loading]);
|
||||
}, [config]);
|
||||
|
||||
// Form handler
|
||||
const formSubmitHandler = async (e: FormEvent) => {
|
||||
|
@ -41,7 +39,7 @@ export const GeneralSettings = (): JSX.Element => {
|
|||
await updateConfig(formData);
|
||||
|
||||
// Sort entities with new settings
|
||||
if (formData.useOrdering !== config.useOrdering) {
|
||||
if (formData.useOrdering !== config.config.useOrdering) {
|
||||
sortCategories();
|
||||
|
||||
for (let { id } of appCategories) {
|
||||
|
@ -166,7 +164,7 @@ export const GeneralSettings = (): JSX.Element => {
|
|||
value={formData.defaultSearchProvider}
|
||||
onChange={(e) => inputChangeHandler(e)}
|
||||
>
|
||||
{[...searchQueries.queries, ...customQueries].map((query: Query, idx) => {
|
||||
{[...searchQueries.queries, ...config.customQueries].map((query: Query, idx) => {
|
||||
const isCustom = idx >= searchQueries.queries.length;
|
||||
|
||||
return (
|
||||
|
@ -189,7 +187,7 @@ export const GeneralSettings = (): JSX.Element => {
|
|||
value={formData.secondarySearchProvider}
|
||||
onChange={(e) => inputChangeHandler(e)}
|
||||
>
|
||||
{[...searchQueries.queries, ...customQueries].map((query: Query, idx) => {
|
||||
{[...searchQueries.queries, ...config.customQueries].map((query: Query, idx) => {
|
||||
const isCustom = idx >= searchQueries.queries.length;
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { useSelector } from 'react-redux';
|
||||
import { Link, NavLink, Route, Switch } from 'react-router-dom';
|
||||
import { Link, NavLink, Route, Routes } from 'react-router-dom';
|
||||
|
||||
import { Route as SettingsRoute } from '../../interfaces';
|
||||
import { State } from '../../store/reducers';
|
||||
|
@ -22,6 +22,7 @@ import { WeatherSettings } from './WeatherSettings/WeatherSettings';
|
|||
// UI
|
||||
// Data
|
||||
export const Settings = (): JSX.Element => {
|
||||
|
||||
const { isAuthenticated } = useSelector((state: State) => state.auth);
|
||||
|
||||
const tabs = isAuthenticated ? settings.routes : settings.routes.filter((r) => !r.authRequired);
|
||||
|
@ -34,9 +35,13 @@ export const Settings = (): JSX.Element => {
|
|||
<nav className={classes.SettingsNav}>
|
||||
{tabs.map(({ name, dest }: SettingsRoute, idx) => (
|
||||
<NavLink
|
||||
className={classes.SettingsNavLink}
|
||||
activeClassName={classes.SettingsNavLinkActive}
|
||||
exact
|
||||
className={({ isActive }) => {
|
||||
const linkClasses = [classes.SettingsNavLink];
|
||||
if (isActive) linkClasses.push(classes.SettingsNavLinkActive);
|
||||
|
||||
return linkClasses.join(" ");
|
||||
}}
|
||||
end
|
||||
to={dest}
|
||||
key={idx}
|
||||
>
|
||||
|
@ -47,24 +52,25 @@ export const Settings = (): JSX.Element => {
|
|||
|
||||
{/* ROUTES */}
|
||||
<section className={classes.SettingsContent}>
|
||||
<Switch>
|
||||
<Route exact path="/settings" component={Themer} />
|
||||
<ProtectedRoute
|
||||
path="/settings/weather"
|
||||
component={WeatherSettings}
|
||||
/>
|
||||
<ProtectedRoute
|
||||
path="/settings/general"
|
||||
component={GeneralSettings}
|
||||
/>
|
||||
<ProtectedRoute path="/settings/interface" component={UISettings} />
|
||||
<ProtectedRoute
|
||||
path="/settings/docker"
|
||||
component={DockerSettings}
|
||||
/>
|
||||
<ProtectedRoute path="/settings/css" component={StyleSettings} />
|
||||
<Route path="/settings/app" component={AppDetails} />
|
||||
</Switch>
|
||||
<Routes>
|
||||
<Route path="" element={<Themer/>} />
|
||||
<Route path="weather" element={<ProtectedRoute/>}>
|
||||
<Route path="" element={<WeatherSettings/>}/>
|
||||
</Route>
|
||||
<Route path="general" element={<ProtectedRoute/>}>
|
||||
<Route path="" element={<GeneralSettings/>}/>
|
||||
</Route>
|
||||
<Route path="interface" element={<ProtectedRoute/>}>
|
||||
<Route path="" element={<UISettings/>}/>
|
||||
</Route>
|
||||
<Route path="docker" element={<ProtectedRoute/>}>
|
||||
<Route path="" element={<DockerSettings/>}/>
|
||||
</Route>
|
||||
<Route path="css" element={<ProtectedRoute/>}>
|
||||
<Route path="" element={<StyleSettings/>}/>
|
||||
</Route>
|
||||
<Route path="app" element={<AppDetails/>} />
|
||||
</Routes>
|
||||
</section>
|
||||
</div>
|
||||
</Container>
|
||||
|
|
|
@ -1,30 +1,27 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
|
||||
// Redux
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
|
||||
import { Theme } from '../../../../interfaces';
|
||||
import { actionCreators } from '../../../../store';
|
||||
import { State } from '../../../../store/reducers';
|
||||
|
||||
// Other
|
||||
import { Theme } from '../../../../interfaces';
|
||||
|
||||
// UI
|
||||
import { Button, Modal } from '../../../UI';
|
||||
import { ThemeGrid } from '../ThemeGrid/ThemeGrid';
|
||||
import classes from './ThemeBuilder.module.css';
|
||||
import { ThemeCreator } from './ThemeCreator';
|
||||
import { ThemeEditor } from './ThemeEditor';
|
||||
|
||||
// Redux
|
||||
// Other
|
||||
// UI
|
||||
interface Props {
|
||||
themes: Theme[];
|
||||
}
|
||||
|
||||
export const ThemeBuilder = ({ themes }: Props): JSX.Element => {
|
||||
const {
|
||||
auth: { isAuthenticated },
|
||||
theme: { themeInEdit, userThemes },
|
||||
} = useSelector((state: State) => state);
|
||||
const themeInEdit = useSelector((state: State) => state.theme.themeInEdit);
|
||||
const userThemes = useSelector((state: State) => state.theme.userThemes);
|
||||
const isAuthenticated = useSelector((state: State) => state.auth.isAuthenticated);
|
||||
|
||||
const { editTheme } = bindActionCreators(actionCreators, useDispatch());
|
||||
|
||||
|
@ -43,7 +40,7 @@ export const ThemeBuilder = ({ themes }: Props): JSX.Element => {
|
|||
toggleIsInEdit(false);
|
||||
toggleShowModal(false);
|
||||
}
|
||||
}, [userThemes]);
|
||||
}, [isInEdit, userThemes]);
|
||||
|
||||
return (
|
||||
<div className={classes.ThemeBuilder}>
|
||||
|
|
|
@ -1,26 +1,24 @@
|
|||
import { ChangeEvent, FormEvent, useState, useEffect } from 'react';
|
||||
|
||||
// Redux
|
||||
import { ChangeEvent, FormEvent, useEffect, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
|
||||
import { Theme } from '../../../../interfaces';
|
||||
import { actionCreators } from '../../../../store';
|
||||
import { State } from '../../../../store/reducers';
|
||||
|
||||
// UI
|
||||
import { Button, InputGroup, ModalForm } from '../../../UI';
|
||||
import classes from './ThemeCreator.module.css';
|
||||
|
||||
// Redux
|
||||
// UI
|
||||
// Other
|
||||
import { Theme } from '../../../../interfaces';
|
||||
|
||||
interface Props {
|
||||
modalHandler: () => void;
|
||||
}
|
||||
|
||||
export const ThemeCreator = ({ modalHandler }: Props): JSX.Element => {
|
||||
const {
|
||||
theme: { activeTheme, themeInEdit },
|
||||
} = useSelector((state: State) => state);
|
||||
activeTheme, themeInEdit
|
||||
} = useSelector((state: State) => state.theme);
|
||||
|
||||
const { addTheme, updateTheme, editTheme } = bindActionCreators(
|
||||
actionCreators,
|
||||
|
@ -39,7 +37,7 @@ export const ThemeCreator = ({ modalHandler }: Props): JSX.Element => {
|
|||
|
||||
useEffect(() => {
|
||||
setFormData({ ...formData, colors: activeTheme.colors });
|
||||
}, [activeTheme]);
|
||||
}, [activeTheme.colors]);
|
||||
|
||||
useEffect(() => {
|
||||
if (themeInEdit) {
|
||||
|
|
|
@ -1,23 +1,20 @@
|
|||
import { Fragment } from 'react';
|
||||
|
||||
// Redux
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
|
||||
import { Theme } from '../../../../interfaces';
|
||||
import { actionCreators } from '../../../../store';
|
||||
import { State } from '../../../../store/reducers';
|
||||
|
||||
// Other
|
||||
import { ActionIcons, CompactTable, Icon, ModalForm } from '../../../UI';
|
||||
|
||||
// Redux
|
||||
// Other
|
||||
interface Props {
|
||||
modalHandler: () => void;
|
||||
}
|
||||
|
||||
export const ThemeEditor = (props: Props): JSX.Element => {
|
||||
const {
|
||||
theme: { userThemes },
|
||||
} = useSelector((state: State) => state);
|
||||
const userThemes = useSelector((state: State) => state.theme.userThemes);
|
||||
|
||||
const { deleteTheme, editTheme } = bindActionCreators(
|
||||
actionCreators,
|
||||
|
|
|
@ -1,32 +1,25 @@
|
|||
import { ChangeEvent, FormEvent, Fragment, useEffect, useState } from 'react';
|
||||
|
||||
// Redux
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
|
||||
import { Theme, ThemeSettingsForm } from '../../../interfaces';
|
||||
import { actionCreators } from '../../../store';
|
||||
import { State } from '../../../store/reducers';
|
||||
|
||||
// Typescript
|
||||
import { Theme, ThemeSettingsForm } from '../../../interfaces';
|
||||
|
||||
// Components
|
||||
import { inputHandler, parseThemeToPAB, themeSettingsTemplate } from '../../../utility';
|
||||
import { Button, InputGroup, SettingsHeadline, Spinner } from '../../UI';
|
||||
import { ThemeBuilder } from './ThemeBuilder/ThemeBuilder';
|
||||
import { ThemeGrid } from './ThemeGrid/ThemeGrid';
|
||||
|
||||
// Redux
|
||||
// Typescript
|
||||
// Components
|
||||
// Other
|
||||
import {
|
||||
inputHandler,
|
||||
parseThemeToPAB,
|
||||
themeSettingsTemplate,
|
||||
} from '../../../utility';
|
||||
|
||||
export const Themer = (): JSX.Element => {
|
||||
const {
|
||||
auth: { isAuthenticated },
|
||||
config: { loading, config },
|
||||
theme: { themes, userThemes },
|
||||
} = useSelector((state: State) => state);
|
||||
export const Themer = (): JSX.Element => {
|
||||
const themes = useSelector((state: State) => state.theme.themes);
|
||||
const userThemes = useSelector((state: State) => state.theme.userThemes);
|
||||
const config = useSelector((state: State) => state.config.config);
|
||||
const loading = useSelector((state: State) => state.config.loading);
|
||||
const isAuthenticated = useSelector((state: State) => state.auth.isAuthenticated);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const { updateConfig } = bindActionCreators(actionCreators, dispatch);
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
import { useState, ChangeEvent, useEffect, FormEvent } from 'react';
|
||||
import axios from 'axios';
|
||||
|
||||
// Redux
|
||||
import { ChangeEvent, FormEvent, useEffect, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
|
||||
import { ApiResponse, Weather, WeatherForm } from '../../../interfaces';
|
||||
import { actionCreators } from '../../../store';
|
||||
import { State } from '../../../store/reducers';
|
||||
|
||||
// Typescript
|
||||
import { ApiResponse, Weather, WeatherForm } from '../../../interfaces';
|
||||
|
||||
// UI
|
||||
import { InputGroup, Button, SettingsHeadline } from '../../UI';
|
||||
|
||||
// Utils
|
||||
import { inputHandler, weatherSettingsTemplate } from '../../../utility';
|
||||
import { Button, InputGroup, SettingsHeadline } from '../../UI';
|
||||
|
||||
// Redux
|
||||
// Typescript
|
||||
// UI
|
||||
// Utils
|
||||
export const WeatherSettings = (): JSX.Element => {
|
||||
const { loading, config } = useSelector((state: State) => state.config);
|
||||
|
||||
|
|
|
@ -1,20 +1,17 @@
|
|||
import { useState, useEffect, Fragment } from 'react';
|
||||
import axios from 'axios';
|
||||
|
||||
// Redux
|
||||
import { Fragment, useEffect, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
// Typescript
|
||||
import { Weather, ApiResponse } from '../../../interfaces';
|
||||
|
||||
// CSS
|
||||
import classes from './WeatherWidget.module.css';
|
||||
|
||||
// UI
|
||||
import { WeatherIcon } from '../../UI';
|
||||
import { ApiResponse, Weather } from '../../../interfaces';
|
||||
import { State } from '../../../store/reducers';
|
||||
import { weatherTemplate } from '../../../utility/templateObjects/weatherTemplate';
|
||||
import { WeatherIcon } from '../../UI';
|
||||
import classes from './WeatherWidget.module.css';
|
||||
|
||||
// Redux
|
||||
// Typescript
|
||||
// CSS
|
||||
// UI
|
||||
export const WeatherWidget = (): JSX.Element => {
|
||||
const { loading: configLoading, config } = useSelector(
|
||||
(state: State) => state.config
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import './index.css';
|
||||
|
||||
import React from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { Provider } from 'react-redux';
|
||||
import { store } from './store/store';
|
||||
|
||||
import { App } from './App';
|
||||
import { store } from './store/store';
|
||||
|
||||
ReactDOM.render(
|
||||
const container = document.getElementById('root');
|
||||
const root = createRoot(container!); // createRoot(container!) if you use TypeScript
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<Provider store={store}>
|
||||
<App />
|
||||
</Provider>
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
</React.StrictMode>);
|
|
@ -61,7 +61,7 @@ export const autoLogin = () => async (dispatch: Dispatch<AutoLoginAction>) => {
|
|||
export const authError =
|
||||
(error: unknown, showNotification: boolean) =>
|
||||
(dispatch: Dispatch<AuthErrorAction>) => {
|
||||
const apiError = error as AxiosError;
|
||||
const apiError = error as AxiosError<any, any>;
|
||||
|
||||
if (showNotification) {
|
||||
dispatch<any>({
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import axios from 'axios';
|
||||
import { store } from '../store/store';
|
||||
|
||||
import { createNotification } from '../store/action-creators';
|
||||
import { store } from '../store/store';
|
||||
|
||||
export const checkVersion = async (isForced: boolean = false) => {
|
||||
try {
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
* https://stackoverflow.com/a/30851002/16957052
|
||||
*/
|
||||
export const escapeRegex = (exp: string) => {
|
||||
return exp.replace(/[-[\]{}()*+!<=:?.\/\\^$|#\s,]/g, '\\$&');
|
||||
return exp.replace(/[-[\]{}()*+!<=:?./\\^$|#\s,]/g, '\\$&');
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export const isUrlOrIp = (data: string): boolean => {
|
||||
const regex =
|
||||
/^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?|^((http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/i;
|
||||
/^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([-.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?|^((http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/i;
|
||||
|
||||
return regex.test(data);
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue