Working on template loader
This commit is contained in:
parent
e36d2610da
commit
b83f1f2f31
67
src/api.ts
67
src/api.ts
@ -52,6 +52,26 @@ type ChannelInfo = {
|
|||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type Template = {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
attachment: string | null;
|
||||||
|
attachment_name: string | null;
|
||||||
|
avatar: string | null;
|
||||||
|
channel: string;
|
||||||
|
content: string;
|
||||||
|
embed_author: string;
|
||||||
|
embed_author_url: string | null;
|
||||||
|
embed_color: number;
|
||||||
|
embed_description: string;
|
||||||
|
embed_footer: string;
|
||||||
|
embed_footer_url: string | null;
|
||||||
|
embed_image_url: string | null;
|
||||||
|
embed_thumbnail_url: string | null;
|
||||||
|
embed_title: string;
|
||||||
|
embed_fields: EmbedField[] | null;
|
||||||
|
};
|
||||||
|
|
||||||
export function fetchUserInfo(): Promise<UserInfo> {
|
export function fetchUserInfo(): Promise<UserInfo> {
|
||||||
return axios.get("/dashboard/api/user").then((resp) => resp.data) as Promise<UserInfo>;
|
return axios.get("/dashboard/api/user").then((resp) => resp.data) as Promise<UserInfo>;
|
||||||
}
|
}
|
||||||
@ -62,21 +82,34 @@ export function fetchUserGuilds(): Promise<GuildInfo[]> {
|
|||||||
>;
|
>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchGuildReminders(guild: string): Promise<Reminder[]> {
|
export const fetchGuildReminders = (guild: string) => ({
|
||||||
return axios
|
queryKey: ["GUILD_REMINDERS", guild],
|
||||||
.get(`/dashboard/api/guild/${guild}/reminders`)
|
queryFn: () =>
|
||||||
.then((resp) => resp.data)
|
axios
|
||||||
.then((value) =>
|
.get(`/dashboard/api/guild/${guild}/reminders`)
|
||||||
value.map((reminder) => ({
|
.then((resp) => resp.data)
|
||||||
...reminder,
|
.then((value) =>
|
||||||
utc_time: DateTime.fromISO(reminder.utc_time),
|
value.map((reminder) => ({
|
||||||
expires: reminder.expires === null ? null : DateTime.fromISO(reminder.expires),
|
...reminder,
|
||||||
})),
|
utc_time: DateTime.fromISO(reminder.utc_time),
|
||||||
) as Promise<Reminder[]>;
|
expires: reminder.expires === null ? null : DateTime.fromISO(reminder.expires),
|
||||||
}
|
})),
|
||||||
|
) as Promise<Reminder[]>,
|
||||||
|
});
|
||||||
|
|
||||||
export function fetchGuildChannels(guild: string): Promise<ChannelInfo[]> {
|
export const fetchGuildChannels = (guild: string) => ({
|
||||||
return axios.get(`/dashboard/api/guild/${guild}/channels`).then((resp) => resp.data) as Promise<
|
queryKey: ["GUILD_CHANNELS", guild],
|
||||||
ChannelInfo[]
|
queryFn: () =>
|
||||||
>;
|
axios.get(`/dashboard/api/guild/${guild}/channels`).then((resp) => resp.data) as Promise<
|
||||||
}
|
ChannelInfo[]
|
||||||
|
>,
|
||||||
|
staleTime: 300,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const guildTemplatesQuery = (guild: string) => ({
|
||||||
|
queryKey: ["GUILD_TEMPLATES", guild],
|
||||||
|
queryFn: () =>
|
||||||
|
axios.get(`/dashboard/api/guild/${guild}/channels`).then((resp) => resp.data) as Promise<
|
||||||
|
Template[]
|
||||||
|
>,
|
||||||
|
});
|
||||||
|
@ -8,10 +8,7 @@ import { CreateReminder } from "../Reminder/CreateReminder";
|
|||||||
export const GuildReminders = () => {
|
export const GuildReminders = () => {
|
||||||
const { guild } = useParams();
|
const { guild } = useParams();
|
||||||
|
|
||||||
const { isSuccess, data } = useQuery({
|
const { isSuccess, data } = useQuery(fetchGuildReminders(guild));
|
||||||
queryKey: [QueryKeys.GUILD_REMINDERS, guild],
|
|
||||||
queryFn: () => fetchGuildReminders(guild),
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ margin: "0 12px 12px 12px" }}>
|
<div style={{ margin: "0 12px 12px 12px" }}>
|
||||||
|
57
src/components/Modal/index.tsx
Normal file
57
src/components/Modal/index.tsx
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { JSX } from "preact";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
setModalOpen: (open: boolean) => never;
|
||||||
|
title: string;
|
||||||
|
onSubmitText?: string;
|
||||||
|
onSubmit?: () => never;
|
||||||
|
children: string | JSX.Element | JSX.Element[] | (() => JSX.Element);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Modal = ({ setModalOpen, title, onSubmit, onSubmitText, children }: Props) => {
|
||||||
|
return (
|
||||||
|
<div class="modal is-active">
|
||||||
|
<div
|
||||||
|
class="modal-background"
|
||||||
|
onClick={() => {
|
||||||
|
setModalOpen(false);
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
<div class="modal-card">
|
||||||
|
<header class="modal-card-head">
|
||||||
|
<label class="modal-card-title">{title}</label>
|
||||||
|
<button
|
||||||
|
class="delete close-modal"
|
||||||
|
aria-label="close"
|
||||||
|
onClick={() => {
|
||||||
|
setModalOpen(false);
|
||||||
|
}}
|
||||||
|
></button>
|
||||||
|
</header>
|
||||||
|
<section class="modal-card-body">{children}</section>
|
||||||
|
{onSubmit && (
|
||||||
|
<footer class="modal-card-foot">
|
||||||
|
<button class="button is-success" onChange={onSubmit}>
|
||||||
|
{onSubmitText || "Save"}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="button close-modal"
|
||||||
|
onClick={() => {
|
||||||
|
setModalOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</footer>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="modal-close is-large close-modal"
|
||||||
|
aria-label="close"
|
||||||
|
onClick={() => {
|
||||||
|
setModalOpen(false);
|
||||||
|
}}
|
||||||
|
></button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -6,11 +6,7 @@ import { fetchGuildChannels } from "../../api";
|
|||||||
export const ChannelSelector = ({ channel }) => {
|
export const ChannelSelector = ({ channel }) => {
|
||||||
const { guild } = useParams();
|
const { guild } = useParams();
|
||||||
|
|
||||||
const { isSuccess, data } = useQuery({
|
const { isSuccess, data } = useQuery(fetchGuildChannels(guild));
|
||||||
queryKey: [QueryKeys.GUILD_CHANNELS, guild],
|
|
||||||
queryFn: () => fetchGuildChannels(guild),
|
|
||||||
staleTime: 300,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="control has-icons-left">
|
<div class="control has-icons-left">
|
||||||
|
@ -2,29 +2,56 @@ import { useParams } from "wouter";
|
|||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { useQueries } from "react-query";
|
import { useQueries } from "react-query";
|
||||||
import { QueryKeys } from "../../consts";
|
import { QueryKeys } from "../../consts";
|
||||||
import { fetchGuildChannels, fetchUserInfo } from "../../api";
|
import { fetchGuildChannels, fetchUserInfo, Reminder } from "../../api";
|
||||||
import { Name } from "./Name";
|
import { Name } from "./Name";
|
||||||
import { Username } from "./Username";
|
import { Username } from "./Username";
|
||||||
import React from "react";
|
|
||||||
import { Content } from "./Content";
|
import { Content } from "./Content";
|
||||||
import { Embed } from "./Embed";
|
import { Embed } from "./Embed";
|
||||||
import { ChannelSelector } from "./ChannelSelector";
|
import { ChannelSelector } from "./ChannelSelector";
|
||||||
import { DateTime } from "luxon";
|
import { DateTime } from "luxon";
|
||||||
import { IntervalSelector } from "./IntervalSelector";
|
import { IntervalSelector } from "./IntervalSelector";
|
||||||
|
import { LoadTemplate } from "./LoadTemplate";
|
||||||
|
|
||||||
|
function defaultReminder(): Reminder {
|
||||||
|
return {
|
||||||
|
attachment: "",
|
||||||
|
attachment_name: "",
|
||||||
|
avatar: "",
|
||||||
|
channel: "",
|
||||||
|
content: "",
|
||||||
|
embed_author: "",
|
||||||
|
embed_author_url: "",
|
||||||
|
embed_color: 0,
|
||||||
|
embed_description: "",
|
||||||
|
embed_fields: [],
|
||||||
|
embed_footer: "",
|
||||||
|
embed_footer_url: "",
|
||||||
|
embed_image_url: "",
|
||||||
|
embed_thumbnail_url: "",
|
||||||
|
embed_title: "",
|
||||||
|
enabled: true,
|
||||||
|
expires: null,
|
||||||
|
interval_days: null,
|
||||||
|
interval_months: null,
|
||||||
|
interval_seconds: null,
|
||||||
|
name: "",
|
||||||
|
restartable: false,
|
||||||
|
tts: false,
|
||||||
|
uid: "",
|
||||||
|
username: "",
|
||||||
|
utc_time: DateTime.now(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export const CreateReminder = () => {
|
export const CreateReminder = () => {
|
||||||
const { guild } = useParams();
|
const { guild } = useParams();
|
||||||
const [reminder, setReminder] = useState({});
|
const [reminder, setReminder] = useState(defaultReminder);
|
||||||
|
|
||||||
const [
|
const [
|
||||||
{ isSuccess: channelsFetched, data: guildChannels },
|
{ isSuccess: channelsFetched, data: guildChannels },
|
||||||
{ isSuccess: userFetched, data: userInfo },
|
{ isSuccess: userFetched, data: userInfo },
|
||||||
] = useQueries([
|
] = useQueries([
|
||||||
{
|
fetchGuildChannels(guild),
|
||||||
queryKey: [QueryKeys.GUILD_CHANNELS, guild],
|
|
||||||
queryFn: () => fetchGuildChannels(guild),
|
|
||||||
staleTime: 300,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
queryKey: [QueryKeys.USER_DATA],
|
queryKey: [QueryKeys.USER_DATA],
|
||||||
queryFn: fetchUserInfo,
|
queryFn: fetchUserInfo,
|
||||||
@ -101,7 +128,7 @@ export const CreateReminder = () => {
|
|||||||
Channel*
|
Channel*
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<ChannelSelector channel={null}></ChannelSelector>
|
<ChannelSelector channel={reminder.channel}></ChannelSelector>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
@ -220,9 +247,7 @@ export const CreateReminder = () => {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button class="button is-outlined show-modal is-pulled-right">
|
<LoadTemplate setReminder={setReminder}></LoadTemplate>
|
||||||
Load Template
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -23,11 +23,7 @@ export const EditReminder = ({ reminder: initialReminder }: Props) => {
|
|||||||
{ isSuccess: channelsFetched, data: guildChannels },
|
{ isSuccess: channelsFetched, data: guildChannels },
|
||||||
{ isSuccess: userFetched, data: userInfo },
|
{ isSuccess: userFetched, data: userInfo },
|
||||||
] = useQueries([
|
] = useQueries([
|
||||||
{
|
fetchGuildChannels(guild),
|
||||||
queryKey: [QueryKeys.GUILD_CHANNELS, guild],
|
|
||||||
queryFn: () => fetchGuildChannels(guild),
|
|
||||||
staleTime: 300,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
queryKey: [QueryKeys.USER_DATA],
|
queryKey: [QueryKeys.USER_DATA],
|
||||||
queryFn: fetchUserInfo,
|
queryFn: fetchUserInfo,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { HexColorPicker } from "react-colorful";
|
import { HexColorPicker } from "react-colorful";
|
||||||
|
import { Modal } from "../../Modal";
|
||||||
|
|
||||||
export const Color = ({ color: colorProp, onChange }) => {
|
export const Color = ({ color: colorProp, onChange }) => {
|
||||||
const [modalOpen, setModalOpen] = useState(false);
|
const [modalOpen, setModalOpen] = useState(false);
|
||||||
@ -31,61 +32,19 @@ const ColorModal = ({ setModalOpen, color: colorProp, onSave }) => {
|
|||||||
const [color, setColor] = useState(colorProp);
|
const [color, setColor] = useState(colorProp);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="modal is-active" id="pickColorModal">
|
<Modal setModalOpen={setModalOpen} title={"Select Color"} onSubmit={onSave}>
|
||||||
<div
|
<div class="colorpicker-container">
|
||||||
class="modal-background"
|
<HexColorPicker color={color} onChange={setColor}></HexColorPicker>
|
||||||
onClick={() => {
|
|
||||||
setModalOpen(false);
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
<div class="modal-card">
|
|
||||||
<header class="modal-card-head">
|
|
||||||
<label class="modal-card-title" for="colorInput">
|
|
||||||
Select Color
|
|
||||||
</label>
|
|
||||||
<button
|
|
||||||
class="delete close-modal"
|
|
||||||
aria-label="close"
|
|
||||||
onClick={() => {
|
|
||||||
setModalOpen(false);
|
|
||||||
}}
|
|
||||||
></button>
|
|
||||||
</header>
|
|
||||||
<section class="modal-card-body">
|
|
||||||
<div class="colorpicker-container">
|
|
||||||
<HexColorPicker color={color} onChange={setColor}></HexColorPicker>
|
|
||||||
</div>
|
|
||||||
<br></br>
|
|
||||||
<input
|
|
||||||
class="input"
|
|
||||||
id="colorInput"
|
|
||||||
value={color}
|
|
||||||
onChange={(ev) => {
|
|
||||||
setColor(ev.currentTarget.value);
|
|
||||||
}}
|
|
||||||
></input>
|
|
||||||
</section>
|
|
||||||
<footer class="modal-card-foot">
|
|
||||||
<button class="button is-success" onChange={onSave}>
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="button close-modal"
|
|
||||||
onClick={() => {
|
|
||||||
setModalOpen(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</footer>
|
|
||||||
</div>
|
</div>
|
||||||
<button
|
<br></br>
|
||||||
class="modal-close is-large close-modal"
|
<input
|
||||||
aria-label="close"
|
class="input"
|
||||||
onClick={() => {
|
id="colorInput"
|
||||||
setModalOpen(false);
|
value={color}
|
||||||
|
onChange={(ev) => {
|
||||||
|
setColor(ev.currentTarget.value);
|
||||||
}}
|
}}
|
||||||
></button>
|
></input>
|
||||||
</div>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
54
src/components/Reminder/LoadTemplate.tsx
Normal file
54
src/components/Reminder/LoadTemplate.tsx
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { useState } from "preact/hooks";
|
||||||
|
import { Modal } from "../Modal";
|
||||||
|
import { useQuery } from "react-query";
|
||||||
|
import { guildTemplatesQuery } from "../../api";
|
||||||
|
import { useParams } from "wouter";
|
||||||
|
|
||||||
|
export const LoadTemplate = ({ setReminder }) => {
|
||||||
|
const [modalOpen, setModalOpen] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
class="button is-outlined show-modal is-pulled-right"
|
||||||
|
onClick={() => {
|
||||||
|
setModalOpen(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Load Template
|
||||||
|
</button>
|
||||||
|
{modalOpen && <LoadTemplateModal setModalOpen={setModalOpen}></LoadTemplateModal>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const LoadTemplateModal = ({ setModalOpen }) => {
|
||||||
|
const { guild } = useParams();
|
||||||
|
const { status, data: templates } = useQuery(guildTemplatesQuery(guild));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal setModalOpen={setModalOpen} title={"Load Template"}>
|
||||||
|
<div class="control has-icons-left">
|
||||||
|
<div class="select is-fullwidth">
|
||||||
|
<select id="templateSelect">
|
||||||
|
{templates.map((template) => (
|
||||||
|
<option value={template.id}>{template.name}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="icon is-small is-left">
|
||||||
|
<i class="fas fa-file-spreadsheet"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br></br>
|
||||||
|
<div class="has-text-centered">
|
||||||
|
<button class="button is-success close-modal" id="load-template">
|
||||||
|
Load Template
|
||||||
|
</button>
|
||||||
|
<button class="button is-danger" id="delete-template">
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
@ -2,5 +2,4 @@ export enum QueryKeys {
|
|||||||
USER_DATA = "userData",
|
USER_DATA = "userData",
|
||||||
USER_GUILDS = "userGuilds",
|
USER_GUILDS = "userGuilds",
|
||||||
GUILD_REMINDERS = "guildReminders",
|
GUILD_REMINDERS = "guildReminders",
|
||||||
GUILD_CHANNELS = "guildChannels",
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user