Fields. Timezone context
This commit is contained in:
		@@ -89,7 +89,7 @@ export const fetchUserInfo = () => ({
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const patchUserInfo = () => ({
 | 
			
		||||
    mutationFn: (user: UserInfo) => axios.patch(`/dashboard/api/user`, user),
 | 
			
		||||
    mutationFn: (timezone: string) => axios.patch(`/dashboard/api/user`, { timezone }),
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const fetchUserGuilds = () => ({
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								src/components/App/TimezoneProvider.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/components/App/TimezoneProvider.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
import { createContext } from "preact";
 | 
			
		||||
import { useContext } from "preact/compat";
 | 
			
		||||
import { useState } from "preact/hooks";
 | 
			
		||||
import { SystemZone } from "luxon";
 | 
			
		||||
 | 
			
		||||
type TTimezoneContext = [string, (tz: string) => void];
 | 
			
		||||
 | 
			
		||||
const TimezoneContext = createContext(["UTC", () => {}] as TTimezoneContext);
 | 
			
		||||
 | 
			
		||||
export const TimezoneProvider = ({ children }) => {
 | 
			
		||||
    const [timezone, setTimezone] = useState(SystemZone.name);
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <TimezoneContext.Provider value={[timezone, setTimezone]}>
 | 
			
		||||
            {children}
 | 
			
		||||
        </TimezoneContext.Provider>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const useTimezone = () => useContext(TimezoneContext);
 | 
			
		||||
@@ -4,27 +4,30 @@ import { Route, Router, Switch } from "wouter";
 | 
			
		||||
import { Welcome } from "../Welcome";
 | 
			
		||||
import { Guild } from "../Guild";
 | 
			
		||||
import { FlashProvider } from "./FlashProvider";
 | 
			
		||||
import { TimezoneProvider } from "./TimezoneProvider";
 | 
			
		||||
 | 
			
		||||
export function App() {
 | 
			
		||||
    const queryClient = new QueryClient();
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <FlashProvider>
 | 
			
		||||
            <QueryClientProvider client={queryClient}>
 | 
			
		||||
                <Router base={"/dashboard"}>
 | 
			
		||||
                    <div class="columns is-gapless dashboard-frame">
 | 
			
		||||
                        <Sidebar />
 | 
			
		||||
                        <div class="column is-main-content">
 | 
			
		||||
                            <Switch>
 | 
			
		||||
                                <Route path={"/:guild/reminders"} component={Guild}></Route>
 | 
			
		||||
                                <Route>
 | 
			
		||||
                                    <Welcome />
 | 
			
		||||
                                </Route>
 | 
			
		||||
                            </Switch>
 | 
			
		||||
        <TimezoneProvider>
 | 
			
		||||
            <FlashProvider>
 | 
			
		||||
                <QueryClientProvider client={queryClient}>
 | 
			
		||||
                    <Router base={"/dashboard"}>
 | 
			
		||||
                        <div class="columns is-gapless dashboard-frame">
 | 
			
		||||
                            <Sidebar />
 | 
			
		||||
                            <div class="column is-main-content">
 | 
			
		||||
                                <Switch>
 | 
			
		||||
                                    <Route path={"/:guild/reminders"} component={Guild}></Route>
 | 
			
		||||
                                    <Route>
 | 
			
		||||
                                        <Welcome />
 | 
			
		||||
                                    </Route>
 | 
			
		||||
                                </Switch>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </Router>
 | 
			
		||||
            </QueryClientProvider>
 | 
			
		||||
        </FlashProvider>
 | 
			
		||||
                    </Router>
 | 
			
		||||
                </QueryClientProvider>
 | 
			
		||||
            </FlashProvider>
 | 
			
		||||
        </TimezoneProvider>
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										55
									
								
								src/components/Reminder/Embed/Fields/Field.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/components/Reminder/Embed/Fields/Field.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
export const Field = ({ title, value, inlined, index, onUpdate }) => {
 | 
			
		||||
    return (
 | 
			
		||||
        <div data-inlined={inlined ? "1" : "0"} class="embed-field-box" key={index}>
 | 
			
		||||
            <label class="is-sr-only" for="embedFieldTitle">
 | 
			
		||||
                Field Title
 | 
			
		||||
            </label>
 | 
			
		||||
            <div class="is-flex">
 | 
			
		||||
                <textarea
 | 
			
		||||
                    class="discord-field-title field-input message-input autoresize"
 | 
			
		||||
                    placeholder="Field Title..."
 | 
			
		||||
                    rows={1}
 | 
			
		||||
                    maxlength={256}
 | 
			
		||||
                    name="embed_field_title[]"
 | 
			
		||||
                    value={title}
 | 
			
		||||
                    onInput={(ev) =>
 | 
			
		||||
                        onUpdate({
 | 
			
		||||
                            index,
 | 
			
		||||
                            title: ev.currentTarget.value,
 | 
			
		||||
                        })
 | 
			
		||||
                    }
 | 
			
		||||
                ></textarea>
 | 
			
		||||
                <button
 | 
			
		||||
                    class="button is-small inline-btn"
 | 
			
		||||
                    onClick={() => {
 | 
			
		||||
                        onUpdate({
 | 
			
		||||
                            index,
 | 
			
		||||
                            inlined: !inlined,
 | 
			
		||||
                        });
 | 
			
		||||
                    }}
 | 
			
		||||
                >
 | 
			
		||||
                    <span class="is-sr-only">Toggle field inline</span>
 | 
			
		||||
                    <i class="fas fa-arrows-h"></i>
 | 
			
		||||
                </button>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <label class="is-sr-only" for="embedFieldValue">
 | 
			
		||||
                Field Value
 | 
			
		||||
            </label>
 | 
			
		||||
            <textarea
 | 
			
		||||
                class="discord-field-value field-input message-input autoresize "
 | 
			
		||||
                placeholder="Field Value..."
 | 
			
		||||
                maxlength={1024}
 | 
			
		||||
                name="embed_field_value[]"
 | 
			
		||||
                rows={1}
 | 
			
		||||
                value={value}
 | 
			
		||||
                onInput={(ev) =>
 | 
			
		||||
                    onUpdate({
 | 
			
		||||
                        index,
 | 
			
		||||
                        value: ev.currentTarget.value,
 | 
			
		||||
                    })
 | 
			
		||||
                }
 | 
			
		||||
            ></textarea>
 | 
			
		||||
        </div>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										37
									
								
								src/components/Reminder/Embed/Fields/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/components/Reminder/Embed/Fields/index.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
import { useReminder } from "../../ReminderContext";
 | 
			
		||||
import { Field } from "./Field";
 | 
			
		||||
 | 
			
		||||
export const Fields = () => {
 | 
			
		||||
    const [{ embed_fields }, setReminder] = useReminder();
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <div class={"embed-multifield-box"}>
 | 
			
		||||
            {[...embed_fields, { value: "", title: "", inlined: true }].map((field, index) => (
 | 
			
		||||
                <Field
 | 
			
		||||
                    {...field}
 | 
			
		||||
                    index={index}
 | 
			
		||||
                    onUpdate={({ index, ...props }) => {
 | 
			
		||||
                        setReminder((reminder) => ({
 | 
			
		||||
                            ...reminder,
 | 
			
		||||
                            embed_fields: [
 | 
			
		||||
                                ...reminder.embed_fields,
 | 
			
		||||
                                { value: "", title: "", inlined: true },
 | 
			
		||||
                            ]
 | 
			
		||||
                                .map((f, i) => {
 | 
			
		||||
                                    if (i === index) {
 | 
			
		||||
                                        return {
 | 
			
		||||
                                            ...f,
 | 
			
		||||
                                            ...props,
 | 
			
		||||
                                        };
 | 
			
		||||
                                    } else {
 | 
			
		||||
                                        return f;
 | 
			
		||||
                                    }
 | 
			
		||||
                                })
 | 
			
		||||
                                .filter((f) => f.value || f.title),
 | 
			
		||||
                        }));
 | 
			
		||||
                    }}
 | 
			
		||||
                ></Field>
 | 
			
		||||
            ))}
 | 
			
		||||
        </div>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
@@ -3,6 +3,7 @@ import { Title } from "./Title";
 | 
			
		||||
import { Description } from "./Description";
 | 
			
		||||
import { Footer } from "./Footer";
 | 
			
		||||
import { Color } from "./Color";
 | 
			
		||||
import { Fields } from "./Fields";
 | 
			
		||||
import { Reminder } from "../../../api";
 | 
			
		||||
import { ImagePicker } from "../ImagePicker";
 | 
			
		||||
import { useReminder } from "../ReminderContext";
 | 
			
		||||
@@ -55,37 +56,7 @@ export const Embed = () => {
 | 
			
		||||
                    ></Description>
 | 
			
		||||
                    <br></br>
 | 
			
		||||
 | 
			
		||||
                    <div class="embed-multifield-box">
 | 
			
		||||
                        <div data-inlined="1" class="embed-field-box">
 | 
			
		||||
                            <label class="is-sr-only" for="embedFieldTitle">
 | 
			
		||||
                                Field Title
 | 
			
		||||
                            </label>
 | 
			
		||||
                            <div class="is-flex">
 | 
			
		||||
                                <textarea
 | 
			
		||||
                                    class="discord-field-title field-input message-input autoresize"
 | 
			
		||||
                                    placeholder="Field Title..."
 | 
			
		||||
                                    rows={1}
 | 
			
		||||
                                    maxlength={256}
 | 
			
		||||
                                    name="embed_field_title[]"
 | 
			
		||||
                                ></textarea>
 | 
			
		||||
                                <button class="button is-small inline-btn">
 | 
			
		||||
                                    <span class="is-sr-only">Toggle field inline</span>
 | 
			
		||||
                                    <i class="fas fa-arrows-h"></i>
 | 
			
		||||
                                </button>
 | 
			
		||||
                            </div>
 | 
			
		||||
 | 
			
		||||
                            <label class="is-sr-only" for="embedFieldValue">
 | 
			
		||||
                                Field Value
 | 
			
		||||
                            </label>
 | 
			
		||||
                            <textarea
 | 
			
		||||
                                class="discord-field-value field-input message-input autoresize "
 | 
			
		||||
                                placeholder="Field Value..."
 | 
			
		||||
                                maxlength={1024}
 | 
			
		||||
                                name="embed_field_value[]"
 | 
			
		||||
                                rows={1}
 | 
			
		||||
                            ></textarea>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <Fields />
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                <div class="b">
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,9 @@
 | 
			
		||||
import { DateTime } from "luxon";
 | 
			
		||||
import { useQuery } from "react-query";
 | 
			
		||||
import { fetchUserInfo } from "../../api";
 | 
			
		||||
import { DateTime, SystemZone } from "luxon";
 | 
			
		||||
import { useMutation, useQuery, useQueryClient } from "react-query";
 | 
			
		||||
import { fetchUserInfo, patchUserInfo } from "../../api";
 | 
			
		||||
import { Modal } from "../Modal";
 | 
			
		||||
import { useState } from "preact/hooks";
 | 
			
		||||
import { useTimezone } from "../App/TimezoneProvider";
 | 
			
		||||
 | 
			
		||||
type DisplayProps = {
 | 
			
		||||
    timezone: string;
 | 
			
		||||
@@ -51,15 +52,23 @@ export const TimezonePicker = () => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const TimezoneModal = ({ setModalOpen }) => {
 | 
			
		||||
    const browserTimezone = DateTime.now().zone.name;
 | 
			
		||||
    const browserTimezone = SystemZone.name;
 | 
			
		||||
    const [selectedZone, setSelectedZone] = useTimezone();
 | 
			
		||||
 | 
			
		||||
    const queryClient = useQueryClient();
 | 
			
		||||
    const { isLoading, isError, data } = useQuery(fetchUserInfo());
 | 
			
		||||
    const userInfoMutation = useMutation({
 | 
			
		||||
        ...patchUserInfo(),
 | 
			
		||||
        onSuccess: () => {
 | 
			
		||||
            queryClient.invalidateQueries(["USER_INFO"]);
 | 
			
		||||
        },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <Modal title={"Timezone"} setModalOpen={setModalOpen}>
 | 
			
		||||
            <p>
 | 
			
		||||
                Your configured timezone is:{" "}
 | 
			
		||||
                <TimezoneDisplay timezone={browserTimezone}></TimezoneDisplay>
 | 
			
		||||
                <TimezoneDisplay timezone={selectedZone}></TimezoneDisplay>
 | 
			
		||||
                <br></br>
 | 
			
		||||
                <br></br>
 | 
			
		||||
                Your browser timezone is:{" "}
 | 
			
		||||
@@ -78,19 +87,37 @@ const TimezoneModal = ({ setModalOpen }) => {
 | 
			
		||||
            </p>
 | 
			
		||||
            <br></br>
 | 
			
		||||
            <div class="has-text-centered">
 | 
			
		||||
                <button class="button is-success close-modal" id="set-browser-timezone">
 | 
			
		||||
                <button
 | 
			
		||||
                    class="button is-success"
 | 
			
		||||
                    id="set-browser-timezone"
 | 
			
		||||
                    onClick={() => {
 | 
			
		||||
                        setSelectedZone(browserTimezone);
 | 
			
		||||
                    }}
 | 
			
		||||
                >
 | 
			
		||||
                    <span>Use Browser Timezone</span>{" "}
 | 
			
		||||
                    <span class="icon">
 | 
			
		||||
                        <i class="fab fa-firefox-browser"></i>
 | 
			
		||||
                    </span>
 | 
			
		||||
                </button>
 | 
			
		||||
                <button class="button is-link close-modal" id="set-bot-timezone">
 | 
			
		||||
                <button
 | 
			
		||||
                    class="button is-success"
 | 
			
		||||
                    id="set-bot-timezone"
 | 
			
		||||
                    onClick={() => {
 | 
			
		||||
                        setSelectedZone(data.timezone);
 | 
			
		||||
                    }}
 | 
			
		||||
                >
 | 
			
		||||
                    <span>Use Bot Timezone</span>{" "}
 | 
			
		||||
                    <span class="icon">
 | 
			
		||||
                        <i class="fab fa-discord"></i>
 | 
			
		||||
                    </span>
 | 
			
		||||
                </button>
 | 
			
		||||
                <button class="button is-warning close-modal" id="update-bot-timezone">
 | 
			
		||||
                <button
 | 
			
		||||
                    class="button is-warning"
 | 
			
		||||
                    id="update-bot-timezone"
 | 
			
		||||
                    onClick={() => {
 | 
			
		||||
                        userInfoMutation.mutate(browserTimezone);
 | 
			
		||||
                    }}
 | 
			
		||||
                >
 | 
			
		||||
                    Set Bot Timezone
 | 
			
		||||
                </button>
 | 
			
		||||
            </div>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user