aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlonkaars <l.leblansch@gmail.com>2021-03-11 14:28:30 +0100
committerlonkaars <l.leblansch@gmail.com>2021-03-11 14:28:30 +0100
commit709bd2fddcea033d162f61a076ec82ce34969887 (patch)
treee73a1f9d5addde981c4608482e59b67235eb9ff8
parent0cb860559dce5299272b87e5e03e0a9347df27e6 (diff)
moved preferencesContext to seperate file + updatePreferences api endpoint
-rw-r--r--api/user/updatePreferences.py32
-rw-r--r--components/preferencesContext.tsx62
-rw-r--r--components/ui.tsx36
-rw-r--r--pages/_app.tsx45
-rw-r--r--pages/settings.tsx9
5 files changed, 121 insertions, 63 deletions
diff --git a/api/user/updatePreferences.py b/api/user/updatePreferences.py
new file mode 100644
index 0000000..2eb6512
--- /dev/null
+++ b/api/user/updatePreferences.py
@@ -0,0 +1,32 @@
+from flask import Blueprint, request
+from db import cursor, connection
+from auth.login_token import token_login
+import json
+
+def format_preferences(preferences): #TODO: remove excess properties (create preferences class?)
+ return json.dumps(preferences) or ""
+
+updatePreferences = Blueprint('updatePreferences', __name__)
+
+@updatePreferences.route('/updatePreferences', methods = ['POST'])
+def index():
+ data = request.get_json()
+
+ new_preferences = data.get("newPreferences") or ""
+ token = request.cookies.get("token") or ""
+
+ if not token: return "", 401
+ login = token_login(token) or ""
+
+ if not login: return "", 403
+
+ formatted_json = format_preferences(new_preferences)
+ if not formatted_json: return "", 400
+
+ cursor.execute("update users set preferences = ? where user_id = ?", [formatted_json, login])
+ connection.commit()
+
+ return "", 200
+
+dynamic_route = ["/user", updatePreferences]
+
diff --git a/components/preferencesContext.tsx b/components/preferencesContext.tsx
new file mode 100644
index 0000000..f7bc409
--- /dev/null
+++ b/components/preferencesContext.tsx
@@ -0,0 +1,62 @@
+import { useState, useEffect, createContext, ReactNode } from 'react';
+import axios from 'axios';
+
+import { userPreferences } from '../api/api';
+
+function applyPreferences(preferences: userPreferences) {
+ if(typeof preferences === "undefined") return;
+ if(typeof preferences.darkMode !== "undefined")
+ document.getElementsByTagName("html")[0].classList[preferences.darkMode ? "add" : "remove"]("dark");
+}
+
+var PreferencesContext = createContext<{ preferences?: userPreferences; updatePreference?: (newPreference: userPreferences) => void }>({});
+
+export function PreferencesContextWrapper(props: { children?: ReactNode }) {
+ var [gotData, setGotData] = useState(false);
+ var [preferences, setPreferences] = useState<userPreferences>();
+
+ useEffect(() => {(async() => {
+ if (gotData) return;
+ if (typeof window === "undefined") return;
+ if (!document.cookie.includes("token")) return;
+
+ var local_prefs = window.localStorage.getItem("preferences");
+ if (local_prefs) {
+ var local_prefs_json = JSON.parse(local_prefs) as userPreferences;
+ setPreferences(local_prefs_json);
+ applyPreferences(local_prefs_json);
+ }
+
+ var preferencesReq = await axios.request<{ preferences: userPreferences; }>({
+ method: "get",
+ url: `/api/user/preferences`,
+ headers: {"content-type": "application/json"}
+ });
+
+ window.localStorage.setItem("preferences", JSON.stringify(preferencesReq.data.preferences));
+ setPreferences(preferencesReq.data.preferences);
+
+ setGotData(true);
+ })()});
+
+ useEffect(() => applyPreferences(preferences), [preferences]);
+
+ function updatePreference(newPreference: userPreferences) {
+ var prefs: userPreferences = Object.assign(preferences, newPreference);
+ setPreferences(prefs);
+ applyPreferences(prefs);
+ axios.request({
+ method: "post",
+ url: `/api/user/updatePreferences`,
+ headers: {"content-type": "application/json"},
+ data: { "newPreferences": prefs }
+ });
+ }
+
+ return <PreferencesContext.Provider value={{ preferences, updatePreference }}>
+ {props.children}
+ </PreferencesContext.Provider>
+}
+
+export default PreferencesContext;
+
diff --git a/components/ui.tsx b/components/ui.tsx
index e2d7f41..f17ae5d 100644
--- a/components/ui.tsx
+++ b/components/ui.tsx
@@ -1,4 +1,4 @@
-import { Component, CSSProperties, ReactNode } from "react";
+import { Component, CSSProperties, ReactNode, useState } from "react";
import SearchIcon from '@material-ui/icons/Search';
import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';
@@ -160,31 +160,29 @@ export function SearchBar(props: { label?: string }) {
</div>
}
-export class CheckBox extends Component<{
+export function CheckBox(props: {
state?: boolean;
style?: CSSProperties;
id?: string;
onclick?: (state: boolean) => void;
-}> {
- state = { on: this.props.state || false }
- public toggle = () => {
- this.setState({ on: !this.state.on });
- this.props.onclick && this.props.onclick(!this.state.on);
+}) {
+ var [on, setOn] = useState(props.state || false);
+ var toggle = () => {
+ setOn(!on);
+ props.onclick && props.onclick(!on);
}
- render() {
- return <div onClick={this.toggle} id={this.props.id} className={this.state.on ? "on" : "off"} style={{
- ...this.props.style,
- display: "inline-block",
- cursor: "pointer"
- }}>
- {
- this.state.on ?
- <CheckBoxIcon/> :
- <CheckBoxOutlineBlankIcon/>
- }
- </div>;
+ return <div onClick={toggle} id={props.id} className={on ? "on" : "off"} style={{
+ ...props.style,
+ display: "inline-block",
+ cursor: "pointer"
+ }}>
+ {
+ on ?
+ <CheckBoxIcon/> :
+ <CheckBoxOutlineBlankIcon/>
}
+ </div>
}
export class ColorPicker extends Component<{
diff --git a/pages/_app.tsx b/pages/_app.tsx
index 08338d0..3c238b9 100644
--- a/pages/_app.tsx
+++ b/pages/_app.tsx
@@ -1,56 +1,19 @@
import Head from 'next/head';
-import axios from 'axios';
-import { useState, useEffect } from 'react';
-
-import { userPreferences } from '../api/api';
+import { PreferencesContextWrapper } from '../components/preferencesContext';
import '../styles/global.css';
import '../styles/dark.css';
import '../styles/disk.css';
-function applyPreferences(preferences: userPreferences) {
- if(typeof preferences === "undefined") return;
- if(typeof preferences.darkMode !== "undefined")
- document.getElementsByTagName("html")[0].classList[preferences.darkMode ? "add" : "remove"]("dark");
-}
-
export default function VierOpEenRijWebsite({ Component, pageProps }) {
- var [gotData, setGotData] = useState(false);
- var [preferences, setPreferences] = useState<userPreferences>();
-
- useEffect(() => {(async() => {
- if (gotData) return;
- if (typeof window === "undefined") return;
- if (!document.cookie.includes("token")) return;
-
- var local_prefs = window.localStorage.getItem("preferences");
- if (local_prefs) {
- var local_prefs_json = JSON.parse(local_prefs) as userPreferences;
- console.log(typeof local_prefs_json);
- setPreferences(local_prefs_json);
- applyPreferences(local_prefs_json);
- }
-
- var preferencesReq = await axios.request<{ preferences: userPreferences; }>({
- method: "get",
- url: `/api/user/preferences`,
- headers: {"content-type": "application/json"}
- });
-
- window.localStorage.setItem("preferences", JSON.stringify(preferencesReq.data.preferences));
- setPreferences(preferencesReq.data.preferences);
-
- setGotData(true);
- })()})
-
- useEffect(() => applyPreferences(preferences), [preferences]);
-
return <div>
<Head>
<title>4 op een rij</title>
<link rel="stylesheet" href="/font/stylesheet.css"/>
</Head>
- <Component {...pageProps}/>
+ <PreferencesContextWrapper>
+ <Component {...pageProps}/>
+ </PreferencesContextWrapper>
</div>
}
diff --git a/pages/settings.tsx b/pages/settings.tsx
index 5034bd7..a713a5a 100644
--- a/pages/settings.tsx
+++ b/pages/settings.tsx
@@ -1,4 +1,4 @@
-import { CSSProperties } from 'react';
+import { CSSProperties, useContext } from 'react';
import * as cookies from 'react-cookies';
import { NavBar } from '../components/navbar';
@@ -6,6 +6,7 @@ import { CenteredPage, PageTitle } from '../components/page';
import { Vierkant, IconLabelButton, CheckBox, ColorPicker } from '../components/ui';
import { AccountAvatar } from '../components/account';
import { CurrentGameSettings } from '../components/gameSettings';
+import PreferencesContext from '../components/preferencesContext';
import EditOutlinedIcon from '@material-ui/icons/EditOutlined';
import VisibilityOutlinedIcon from '@material-ui/icons/VisibilityOutlined';
@@ -17,6 +18,8 @@ var SettingsSubsectionStyle: CSSProperties = {
};
export default function SettingsPage() {
+ var { preferences, updatePreference } = useContext(PreferencesContext);
+
return (
<div>
<NavBar/>
@@ -67,8 +70,8 @@ export default function SettingsPage() {
</div>
<div style={SettingsSubsectionStyle}>
<div style={{ float: "right" }}>
- <CheckBox state={typeof window !== "undefined" && document.getElementsByTagName("html")[0].classList.contains("dark")} onclick={
- (state) => document.getElementsByTagName("html")[0].classList[state ? "add" : "remove"]("dark")
+ <CheckBox state={preferences?.darkMode} onclick={
+ state => updatePreference({"darkMode": state})
}/>
</div>
<h3>Donkere modus</h3>