Support switching timezone preference to use bot/browser timezone
This commit is contained in:
parent
3dd2bb8d95
commit
329e356bbc
@ -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 = () => ({
|
||||
|
@ -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 (
|
||||
<TimezoneContext.Provider value={[timezone, setTimezone]}>
|
||||
{children}
|
||||
|
@ -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 (
|
||||
<TimezoneProvider>
|
||||
<FlashProvider>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<TimezoneProvider>
|
||||
<FlashProvider>
|
||||
<Router base={"/dashboard"}>
|
||||
<div class={`columns is-gapless dashboard-frame scheme-${scheme}`}>
|
||||
<Sidebar />
|
||||
@ -52,8 +52,8 @@ export function App() {
|
||||
</div>
|
||||
</div>
|
||||
</Router>
|
||||
</QueryClientProvider>
|
||||
</FlashProvider>
|
||||
</TimezoneProvider>
|
||||
</FlashProvider>
|
||||
</TimezoneProvider>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -26,3 +26,10 @@
|
||||
textarea.autoresize {
|
||||
resize: vertical !important;
|
||||
}
|
||||
|
||||
div.reminderContent {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
padding: 14px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
@ -44,7 +44,6 @@ const SidebarContent = ({ guilds }: ContentProps) => {
|
||||
style={{
|
||||
position: "sticky",
|
||||
bottom: "0px",
|
||||
backgroundColor: "rgb(54, 54, 54)",
|
||||
}}
|
||||
>
|
||||
<p class="menu-label">Options</p>
|
||||
|
@ -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 ? (
|
||||
<i className="fas fa-cog fa-spin"></i>
|
||||
) : (
|
||||
<TimezoneDisplay timezone={data.timezone || "UTC"}></TimezoneDisplay>
|
||||
<TimezoneDisplay timezone={data.preferences.timezone || "UTC"} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
@ -93,10 +93,29 @@ const TimezoneModal = ({ setModalOpen }) => {
|
||||
margin: "2px",
|
||||
}}
|
||||
onClick={() => {
|
||||
userInfoMutation.mutate(browserTimezone);
|
||||
userInfoMutation.mutate({ timezone: browserTimezone });
|
||||
}}
|
||||
>
|
||||
Set Bot Timezone
|
||||
Set bot timezone
|
||||
</button>
|
||||
<button
|
||||
class="button is-success is-outlined"
|
||||
id="update-bot-timezone"
|
||||
style={{
|
||||
margin: "2px",
|
||||
}}
|
||||
onClick={() => {
|
||||
userInfoMutation.mutate({
|
||||
use_browser_timezone: !data.preferences.use_browser_timezone,
|
||||
});
|
||||
setTimezone(
|
||||
data.preferences.use_browser_timezone
|
||||
? data.preferences.timezone
|
||||
: DateTime.now().zoneName,
|
||||
);
|
||||
}}
|
||||
>
|
||||
Use {data.preferences.use_browser_timezone ? "bot" : "browser"} timezone
|
||||
</button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
13
reminder-dashboard/src/vars.scss
Normal file
13
reminder-dashboard/src/vars.scss
Normal file
@ -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;
|
@ -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
|
||||
|
@ -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(),
|
||||
)
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
)
|
||||
|
@ -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"})
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user