Add modal for image picker
This commit is contained in:
parent
b83f1f2f31
commit
5dc7ceb8aa
31
src/api.ts
31
src/api.ts
@ -52,6 +52,11 @@ type ChannelInfo = {
|
||||
name: string;
|
||||
};
|
||||
|
||||
type RoleInfo = {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
type Template = {
|
||||
id: number;
|
||||
name: string;
|
||||
@ -72,15 +77,16 @@ type Template = {
|
||||
embed_fields: EmbedField[] | null;
|
||||
};
|
||||
|
||||
export function fetchUserInfo(): Promise<UserInfo> {
|
||||
return axios.get("/dashboard/api/user").then((resp) => resp.data) as Promise<UserInfo>;
|
||||
}
|
||||
export const fetchUserInfo = () => ({
|
||||
queryKey: ["USER_INFO"],
|
||||
queryFn: () => axios.get("/dashboard/api/user").then((resp) => resp.data) as Promise<UserInfo>,
|
||||
});
|
||||
|
||||
export function fetchUserGuilds(): Promise<GuildInfo[]> {
|
||||
return axios.get("/dashboard/api/user/guilds").then((resp) => resp.data) as Promise<
|
||||
GuildInfo[]
|
||||
>;
|
||||
}
|
||||
export const fetchUserGuilds = () => ({
|
||||
queryKey: ["USER_GUILDS"],
|
||||
queryFn: () =>
|
||||
axios.get("/dashboard/api/user/guilds").then((resp) => resp.data) as Promise<GuildInfo[]>,
|
||||
});
|
||||
|
||||
export const fetchGuildReminders = (guild: string) => ({
|
||||
queryKey: ["GUILD_REMINDERS", guild],
|
||||
@ -106,6 +112,15 @@ export const fetchGuildChannels = (guild: string) => ({
|
||||
staleTime: 300,
|
||||
});
|
||||
|
||||
export const fetchGuildRoles = (guild: string) => ({
|
||||
queryKey: ["GUILD_ROLES", guild],
|
||||
queryFn: () =>
|
||||
axios.get(`/dashboard/api/guild/${guild}/roles`).then((resp) => resp.data) as Promise<
|
||||
RoleInfo[]
|
||||
>,
|
||||
staleTime: 300,
|
||||
});
|
||||
|
||||
export const guildTemplatesQuery = (guild: string) => ({
|
||||
queryKey: ["GUILD_TEMPLATES", guild],
|
||||
queryFn: () =>
|
||||
|
@ -4,7 +4,7 @@ type Props = {
|
||||
setModalOpen: (open: boolean) => never;
|
||||
title: string;
|
||||
onSubmitText?: string;
|
||||
onSubmit?: () => never;
|
||||
onSubmit?: () => void;
|
||||
children: string | JSX.Element | JSX.Element[] | (() => JSX.Element);
|
||||
};
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { useParams } from "wouter";
|
||||
import { useState } from "preact/hooks";
|
||||
import { useQueries } from "react-query";
|
||||
import { QueryKeys } from "../../consts";
|
||||
import { fetchGuildChannels, fetchUserInfo, Reminder } from "../../api";
|
||||
import { useQuery } from "react-query";
|
||||
import { fetchUserInfo, Reminder } from "../../api";
|
||||
import { Name } from "./Name";
|
||||
import { Username } from "./Username";
|
||||
import { Content } from "./Content";
|
||||
@ -11,6 +10,7 @@ import { ChannelSelector } from "./ChannelSelector";
|
||||
import { DateTime } from "luxon";
|
||||
import { IntervalSelector } from "./IntervalSelector";
|
||||
import { LoadTemplate } from "./LoadTemplate";
|
||||
import { ImagePicker } from "./ImagePicker";
|
||||
|
||||
function defaultReminder(): Reminder {
|
||||
return {
|
||||
@ -47,21 +47,11 @@ export const CreateReminder = () => {
|
||||
const { guild } = useParams();
|
||||
const [reminder, setReminder] = useState(defaultReminder);
|
||||
|
||||
const [
|
||||
{ isSuccess: channelsFetched, data: guildChannels },
|
||||
{ isSuccess: userFetched, data: userInfo },
|
||||
] = useQueries([
|
||||
fetchGuildChannels(guild),
|
||||
{
|
||||
queryKey: [QueryKeys.USER_DATA],
|
||||
queryFn: fetchUserInfo,
|
||||
staleTime: Infinity,
|
||||
},
|
||||
]);
|
||||
const { isSuccess: userFetched, data: userInfo } = useQuery(fetchUserInfo());
|
||||
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
|
||||
if (!channelsFetched || !userFetched) {
|
||||
if (!userFetched) {
|
||||
// todo
|
||||
return <></>;
|
||||
}
|
||||
@ -87,13 +77,11 @@ export const CreateReminder = () => {
|
||||
<article class="media">
|
||||
<figure class="media-left">
|
||||
<p class="image is-32x32 customizable">
|
||||
<a>
|
||||
<img
|
||||
<ImagePicker
|
||||
class="is-rounded avatar"
|
||||
src="/static/img/bg.webp"
|
||||
alt="Image for discord avatar"
|
||||
></img>
|
||||
</a>
|
||||
setImage={() => {}}
|
||||
></ImagePicker>
|
||||
</p>
|
||||
</figure>
|
||||
<div class="media-content">
|
||||
|
@ -22,14 +22,7 @@ export const EditReminder = ({ reminder: initialReminder }: Props) => {
|
||||
const [
|
||||
{ isSuccess: channelsFetched, data: guildChannels },
|
||||
{ isSuccess: userFetched, data: userInfo },
|
||||
] = useQueries([
|
||||
fetchGuildChannels(guild),
|
||||
{
|
||||
queryKey: [QueryKeys.USER_DATA],
|
||||
queryFn: fetchUserInfo,
|
||||
staleTime: Infinity,
|
||||
},
|
||||
]);
|
||||
] = useQueries([fetchGuildChannels(guild), fetchUserInfo()]);
|
||||
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
|
||||
|
@ -1,15 +1,16 @@
|
||||
import { ImagePicker } from "../ImagePicker";
|
||||
|
||||
export const Author = ({ name, icon }) => {
|
||||
return (
|
||||
<div class="embed-author-box">
|
||||
<div class="a">
|
||||
<p class="image is-24x24 customizable">
|
||||
<a>
|
||||
<img
|
||||
<ImagePicker
|
||||
class="is-rounded embed_author_url"
|
||||
src={icon || "/static/img/bg.webp"}
|
||||
url={icon}
|
||||
alt="Image for embed author"
|
||||
></img>
|
||||
</a>
|
||||
setImage={() => {}}
|
||||
></ImagePicker>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
@ -4,11 +4,7 @@ import { Description } from "./Description";
|
||||
import { Footer } from "./Footer";
|
||||
import { Color } from "./Color";
|
||||
import { Reminder } from "../../../api";
|
||||
|
||||
type Props = {
|
||||
reminder: Reminder;
|
||||
setReminder: (reminder: Reminder) => {};
|
||||
};
|
||||
import { ImagePicker } from "../ImagePicker";
|
||||
|
||||
function colorToInt(hex: string) {
|
||||
return parseInt(hex.substring(1), 16);
|
||||
@ -85,25 +81,21 @@ export const Embed = ({ reminder, setReminder }) => {
|
||||
|
||||
<div class="b">
|
||||
<p class="image thumbnail customizable">
|
||||
<a>
|
||||
<img
|
||||
<ImagePicker
|
||||
class="embed_thumbnail_url"
|
||||
src="/static/img/bg.webp"
|
||||
alt="Square thumbnail embedded image"
|
||||
></img>
|
||||
</a>
|
||||
setImage={() => {}}
|
||||
></ImagePicker>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="image is-400x300 customizable">
|
||||
<a>
|
||||
<img
|
||||
<ImagePicker
|
||||
class="embed_image_url"
|
||||
src="/static/img/bg.webp"
|
||||
alt="Large embedded image"
|
||||
></img>
|
||||
</a>
|
||||
setImage={() => {}}
|
||||
></ImagePicker>
|
||||
</p>
|
||||
|
||||
<Footer footer={reminder.embed_footer} icon={reminder.embed_footer_url}></Footer>
|
||||
|
49
src/components/Reminder/ImagePicker.tsx
Normal file
49
src/components/Reminder/ImagePicker.tsx
Normal file
@ -0,0 +1,49 @@
|
||||
import { Modal } from "../Modal";
|
||||
import { useState } from "preact/hooks";
|
||||
|
||||
export const ImagePicker = ({ alt, url, setImage, ...props }) => {
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<a
|
||||
onClick={() => {
|
||||
setModalOpen(true);
|
||||
}}
|
||||
role={"button"}
|
||||
>
|
||||
<img {...props} src={url || "/static/img/bg.webp"} alt={alt}></img>
|
||||
</a>
|
||||
{modalOpen && (
|
||||
<ImagePickerModal
|
||||
setModalOpen={setModalOpen}
|
||||
setImage={setImage}
|
||||
></ImagePickerModal>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const ImagePickerModal = ({ setModalOpen, setImage }) => {
|
||||
const [value, setValue] = useState("");
|
||||
|
||||
return (
|
||||
<Modal
|
||||
setModalOpen={setModalOpen}
|
||||
title={"Enter Image URL"}
|
||||
onSubmit={() => {
|
||||
setImage(value);
|
||||
}}
|
||||
onSubmitText={"Save"}
|
||||
>
|
||||
<input
|
||||
class="input"
|
||||
id="urlInput"
|
||||
placeholder="Image URL..."
|
||||
onChange={(ev) => {
|
||||
setValue(ev.currentTarget.value);
|
||||
}}
|
||||
></input>
|
||||
</Modal>
|
||||
);
|
||||
};
|
@ -1,5 +1,4 @@
|
||||
export enum QueryKeys {
|
||||
USER_DATA = "userData",
|
||||
USER_GUILDS = "userGuilds",
|
||||
GUILD_REMINDERS = "guildReminders",
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user