diff --git a/reminder-dashboard/src/api.ts b/reminder-dashboard/src/api.ts index defe690..850ba2b 100644 --- a/reminder-dashboard/src/api.ts +++ b/reminder-dashboard/src/api.ts @@ -1,10 +1,27 @@ import axios from "axios"; +enum ColorScheme { + System = "system", + Dark = "dark", + Light = "light", +} + type UserInfo = { name: string; patreon: boolean; - timezone: string | null; - reset_inputs_on_create: boolean; + preferences: { + timezone: string | null; + reset_inputs_on_create: boolean; + dashboard_color_scheme: ColorScheme; + use_browser_timezone: boolean; + }; +}; + +type UpdateUserInfo = { + timezone?: string; + reset_inputs_on_create?: boolean; + dashboard_color_scheme?: ColorScheme; + use_browser_timezone?: boolean; }; export type GuildInfo = { @@ -110,7 +127,7 @@ export const fetchUserInfo = () => ({ }); export const patchUserInfo = () => ({ - mutationFn: (timezone: string) => axios.patch(`/dashboard/api/user`, { timezone }), + mutationFn: (userInfo: UpdateUserInfo) => axios.patch(`/dashboard/api/user`, userInfo), }); export const fetchUserGuilds = () => ({ diff --git a/reminder-dashboard/src/components/App/TimezoneProvider.tsx b/reminder-dashboard/src/components/App/TimezoneProvider.tsx index a67c77a..4e6b219 100644 --- a/reminder-dashboard/src/components/App/TimezoneProvider.tsx +++ b/reminder-dashboard/src/components/App/TimezoneProvider.tsx @@ -1,15 +1,27 @@ import { createContext } from "preact"; import { useContext } from "preact/compat"; -import { useState } from "preact/hooks"; +import { useEffect, useState } from "preact/hooks"; import { DateTime } from "luxon"; +import { fetchUserInfo } from "../../api"; +import { useQuery } from "react-query"; type TTimezoneContext = [string, (tz: string) => void]; const TimezoneContext = createContext(["UTC", () => {}] as TTimezoneContext); export const TimezoneProvider = ({ children }) => { + const { data } = useQuery({ ...fetchUserInfo() }); + const [timezone, setTimezone] = useState(DateTime.now().zoneName); + useEffect(() => { + setTimezone( + data === undefined || data.preferences.use_browser_timezone + ? DateTime.now().zoneName + : data.preferences.timezone, + ); + }, [data]); + return ( {children} diff --git a/reminder-dashboard/src/components/App/index.tsx b/reminder-dashboard/src/components/App/index.tsx index 8dfe394..240c06f 100644 --- a/reminder-dashboard/src/components/App/index.tsx +++ b/reminder-dashboard/src/components/App/index.tsx @@ -13,14 +13,14 @@ export function App() { const queryClient = new QueryClient(); let scheme = "light"; - if (window.matchMedia("(prefers-color-scheme: dark)").matches) { - scheme = "dark"; - } + // if (window.matchMedia("(prefers-color-scheme: dark)").matches) { + // scheme = "dark"; + // } return ( - - - + + +
@@ -52,8 +52,8 @@ export function App() {
-
-
-
+ + + ); } diff --git a/reminder-dashboard/src/components/Reminder/Settings.tsx b/reminder-dashboard/src/components/Reminder/Settings.tsx index 463c300..d85a6ee 100644 --- a/reminder-dashboard/src/components/Reminder/Settings.tsx +++ b/reminder-dashboard/src/components/Reminder/Settings.tsx @@ -11,7 +11,7 @@ import { useGuild } from "../App/useGuild"; export const Settings = () => { const guild = useGuild(); - const { isSuccess: userFetched, data: userInfo } = useQuery(fetchUserInfo()); + const { isSuccess: userFetched, data: userInfo } = useQuery({ ...fetchUserInfo() }); const [reminder, setReminder] = useReminder(); diff --git a/reminder-dashboard/src/components/Reminder/styles.scss b/reminder-dashboard/src/components/Reminder/styles.scss index 5c5e051..ed3ccc4 100644 --- a/reminder-dashboard/src/components/Reminder/styles.scss +++ b/reminder-dashboard/src/components/Reminder/styles.scss @@ -26,3 +26,10 @@ textarea.autoresize { resize: vertical !important; } + +div.reminderContent { + margin-top: 10px; + margin-bottom: 10px; + padding: 14px; + border-radius: 8px; +} diff --git a/reminder-dashboard/src/components/Sidebar/index.tsx b/reminder-dashboard/src/components/Sidebar/index.tsx index acfa4e1..63a9ca5 100644 --- a/reminder-dashboard/src/components/Sidebar/index.tsx +++ b/reminder-dashboard/src/components/Sidebar/index.tsx @@ -44,7 +44,6 @@ const SidebarContent = ({ guilds }: ContentProps) => { style={{ position: "sticky", bottom: "0px", - backgroundColor: "rgb(54, 54, 54)", }} > diff --git a/reminder-dashboard/src/components/TimezonePicker/index.tsx b/reminder-dashboard/src/components/TimezonePicker/index.tsx index 5c60f37..09ff942 100644 --- a/reminder-dashboard/src/components/TimezonePicker/index.tsx +++ b/reminder-dashboard/src/components/TimezonePicker/index.tsx @@ -53,10 +53,10 @@ export const TimezonePicker = () => { const TimezoneModal = ({ setModalOpen }) => { const browserTimezone = DateTime.now().zoneName; - const [selectedZone] = useTimezone(); + const [selectedZone, setTimezone] = useTimezone(); const queryClient = useQueryClient(); - const { isLoading, isError, data } = useQuery(fetchUserInfo()); + const { isLoading, isError, data } = useQuery({ ...fetchUserInfo() }); const userInfoMutation = useMutation({ ...patchUserInfo(), onSuccess: () => { @@ -79,7 +79,7 @@ const TimezoneModal = ({ setModalOpen }) => { {isLoading ? ( ) : ( - + )} )} @@ -93,10 +93,29 @@ const TimezoneModal = ({ setModalOpen }) => { margin: "2px", }} onClick={() => { - userInfoMutation.mutate(browserTimezone); + userInfoMutation.mutate({ timezone: browserTimezone }); }} > - Set Bot Timezone + Set bot timezone + + diff --git a/reminder-dashboard/src/styles.scss b/reminder-dashboard/src/styles.scss index 20417d1..35ba604 100644 --- a/reminder-dashboard/src/styles.scss +++ b/reminder-dashboard/src/styles.scss @@ -1,3 +1,5 @@ +@import "vars"; + /* override styles for when the div is collapsed */ div.reminderContent.is-collapsed .column.discord-frame { display: none; @@ -47,3 +49,41 @@ div.reminderContent.is-collapsed .hide-box { div.reminderContent.is-collapsed .hide-box i { transform: rotate(90deg); } + +#app { + > .scheme-dark { + background-color: $primary-background-dark; + color: $primary-text-dark; + + .dashboard-sidebar { + background-color: $contrast-background-dark; + color: $contrast-text-dark; + } + + .reminderContent { + background-color: $secondary-background-dark; + } + + label, strong, p, .subtitle, .title { + color: $primary-text-dark; + } + } + + > .scheme-light { + background-color: $primary-background-light; + color: $primary-text-light; + + .dashboard-sidebar { + background-color: $contrast-background-light; + color: $contrast-text-light; + } + + .reminderContent { + background-color: $secondary-background-light; + } + + label, strong, p, .subtitle, .title { + color: $primary-text-light; + } + } +} diff --git a/reminder-dashboard/src/vars.scss b/reminder-dashboard/src/vars.scss new file mode 100644 index 0000000..04d90b5 --- /dev/null +++ b/reminder-dashboard/src/vars.scss @@ -0,0 +1,13 @@ +$primary-background-light: #ffffff; +$secondary-background-light: #f5f5f5; +$contrast-background-light: #363636; +$primary-text-light: #4a4a4a; +$secondary-text-light: #4a4a4a; +$contrast-text-light: #ffffff; + +$primary-background-dark: #363636; +$secondary-background-dark: #424242; +$contrast-background-dark: #242424; +$primary-text-dark: #ffffff; +$secondary-text-dark: #ffffff; +$contrast-text-dark: #ffffff; diff --git a/src/commands/todo/user/add.rs b/src/commands/todo/user/add.rs index fc61e66..43bd907 100644 --- a/src/commands/todo/user/add.rs +++ b/src/commands/todo/user/add.rs @@ -17,10 +17,7 @@ impl Recordable for Options { sqlx::query!( " INSERT INTO todos (user_id, value) - VALUES ( - (SELECT id FROM users WHERE user = ?), - ? - ) + VALUES (?, ?) ", ctx.author().id.get(), self.task diff --git a/src/commands/todo/user/view.rs b/src/commands/todo/user/view.rs index ecb61ab..eef80e5 100644 --- a/src/commands/todo/user/view.rs +++ b/src/commands/todo/user/view.rs @@ -14,8 +14,7 @@ impl Recordable for Options { let values = sqlx::query!( " SELECT todos.id, value FROM todos - INNER JOIN users ON todos.user_id = users.id - WHERE users.user = ? + WHERE user_id = ? ", ctx.author().id.get(), ) diff --git a/src/component_models/mod.rs b/src/component_models/mod.rs index 2c3235c..dab6e8b 100644 --- a/src/component_models/mod.rs +++ b/src/component_models/mod.rs @@ -191,8 +191,7 @@ impl ComponentDataModel { sqlx::query!( " SELECT todos.id, value FROM todos - INNER JOIN users ON todos.user_id = users.id - WHERE users.user = ? + WHERE user_id = ? ", uid, ) @@ -285,10 +284,9 @@ impl ComponentDataModel { let values = if let Some(uid) = selector.user_id { sqlx::query!( " - SELECT todos.id, value FROM todos - INNER JOIN users ON todos.user_id = users.id - WHERE users.user = ? - ", + SELECT todos.id, value FROM todos + WHERE user_id = ? + ", uid, ) .fetch_all(&data.database) diff --git a/src/models/reminder/mod.rs b/src/models/reminder/mod.rs index f36b881..d1cf9e0 100644 --- a/src/models/reminder/mod.rs +++ b/src/models/reminder/mod.rs @@ -85,17 +85,13 @@ impl Reminder { reminders.enabled, reminders.content, reminders.embed_description, - users.user AS set_by + reminders.set_by FROM reminders INNER JOIN channels ON reminders.channel_id = channels.id - LEFT JOIN - users - ON - reminders.set_by = users.id WHERE reminders.uid = ? ", @@ -122,17 +118,13 @@ impl Reminder { reminders.enabled, reminders.content, reminders.embed_description, - users.user AS set_by + reminders.set_by FROM reminders INNER JOIN channels ON reminders.channel_id = channels.id - LEFT JOIN - users - ON - reminders.set_by = users.id WHERE reminders.id = ? ", @@ -166,17 +158,13 @@ impl Reminder { reminders.enabled, reminders.content, reminders.embed_description, - users.user AS set_by + reminders.set_by FROM reminders INNER JOIN channels ON reminders.channel_id = channels.id - LEFT JOIN - users - ON - reminders.set_by = users.id WHERE `status` = 'pending' AND channels.channel = ? AND @@ -230,17 +218,13 @@ impl Reminder { reminders.enabled, reminders.content, reminders.embed_description, - users.user AS set_by + reminders.set_by FROM reminders LEFT JOIN channels ON channels.id = reminders.channel_id - LEFT JOIN - users - ON - reminders.set_by = users.id WHERE `status` = 'pending' AND FIND_IN_SET(channels.channel, ?) @@ -266,17 +250,13 @@ impl Reminder { reminders.enabled, reminders.content, reminders.embed_description, - users.user AS set_by + reminders.set_by FROM reminders LEFT JOIN channels ON channels.id = reminders.channel_id - LEFT JOIN - users - ON - reminders.set_by = users.id WHERE `status` = 'pending' AND channels.guild_id = (SELECT id FROM guilds WHERE guild = ?) @@ -303,20 +283,16 @@ impl Reminder { reminders.enabled, reminders.content, reminders.embed_description, - users.user AS set_by + reminders.set_by FROM reminders INNER JOIN channels ON channels.id = reminders.channel_id - LEFT JOIN - users - ON - reminders.set_by = users.id WHERE `status` = 'pending' AND - channels.id = (SELECT dm_channel FROM users WHERE user = ?) + channels.id = (SELECT dm_channel FROM users WHERE id = ?) ", user.get() ) diff --git a/src/web/routes/dashboard/api/user/mod.rs b/src/web/routes/dashboard/api/user/mod.rs index 749711d..5de3ada 100644 --- a/src/web/routes/dashboard/api/user/mod.rs +++ b/src/web/routes/dashboard/api/user/mod.rs @@ -6,6 +6,7 @@ use std::env; use chrono_tz::Tz; pub use guilds::*; +use log::warn; pub use reminders::*; use rocket::{ get, @@ -57,7 +58,7 @@ pub async fn get_user_info( patreon: true, preferences: UserPreferences { timezone: "UTC".to_string(), - use_browser_timezone: false, + use_browser_timezone: true, dashboard_color_scheme: "system".to_string(), reset_inputs_on_create: false, } @@ -70,10 +71,10 @@ pub async fn get_user_info( .member(&ctx.inner(), user_id) .await; - let prefs = sqlx::query!( + let preferences = sqlx::query!( " SELECT - IFNULL(timezone, 'UTC') AS timezone, + timezone, use_browser_timezone, dashboard_color_scheme, reset_inputs_on_create @@ -84,7 +85,20 @@ pub async fn get_user_info( ) .fetch_one(pool.inner()) .await - .map_or(None, |q| Some(q.timezone)); + .map_or( + UserPreferences { + timezone: "UTC".to_string(), + use_browser_timezone: false, + dashboard_color_scheme: "system".to_string(), + reset_inputs_on_create: false, + }, + |q| UserPreferences { + timezone: q.timezone, + use_browser_timezone: q.use_browser_timezone != 0, + dashboard_color_scheme: q.dashboard_color_scheme, + reset_inputs_on_create: q.reset_inputs_on_create != 0, + }, + ); let user_info = UserInfo { name: cookies @@ -95,12 +109,7 @@ pub async fn get_user_info( .roles .contains(&RoleId::new(env::var("PATREON_ROLE_ID").unwrap().parse().unwrap())) }), - preferences: UserPreferences { - timezone: prefs.timezone, - use_browser_timezone: prefs.use_browser_timezone, - dashboard_color_scheme: prefs.dashboard_color_scheme, - reset_inputs_on_create: prefs.reset_inputs_on_create, - }, + preferences, }; json!(user_info) @@ -154,10 +163,42 @@ pub async fn update_user_info( } } - // todo handle other two options + if let Some(reset_inputs_on_create) = &preferences.reset_inputs_on_create { + let _ = sqlx::query!( + " + UPDATE users + SET reset_inputs_on_create = ? + WHERE id = ? + ", + reset_inputs_on_create, + user_id, + ) + .execute(transaction.executor()) + .await; + } - transaction.commit().await; - json!({}) + if let Some(use_browser_timezone) = &preferences.use_browser_timezone { + let _ = sqlx::query!( + " + UPDATE users + SET use_browser_timezone = ? + WHERE id = ? + ", + use_browser_timezone, + user_id, + ) + .execute(transaction.executor()) + .await; + } + + match transaction.commit().await { + Ok(_) => json!({}), + Err(e) => { + warn!("Error updating user preferences for {}: {:?}", user_id, e); + + json!({"error": "Couldn't update preferences"}) + } + } } else { json!({"error": "Not authorized"}) } diff --git a/static/css/style.css b/static/css/style.css index 13dbca1..ccb0115 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -100,14 +100,6 @@ div.split-controls { flex-basis: 50%; } -div.reminderContent { - margin-top: 10px; - margin-bottom: 10px; - padding: 14px; - background-color: #f5f5f5; - border-radius: 8px; -} - .left-pad { padding-left: 1rem; padding-right: 0.2rem; @@ -733,27 +725,3 @@ a.switch-pane.is-active ~ .guild-submenu { .is-locked .field:last-of-type { display: none; } - -.stat-row { - display: flex; - flex-direction: row; -} - -.stat-box { - flex-grow: 1; - border-radius: 6px; - background-color: #fcfcfc; - border-color: #efefef; - border-style: solid; - border-width: 1px; - margin: 4px; - padding: 4px; -} - -.figure { - text-align: center; -} - -.figure-num { - font-size: 2rem; -}