Add modal for image picker
This commit is contained in:
		
							
								
								
									
										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
 | 
			
		||||
                                        class="is-rounded avatar"
 | 
			
		||||
                                        src="/static/img/bg.webp"
 | 
			
		||||
                                        alt="Image for discord avatar"
 | 
			
		||||
                                    ></img>
 | 
			
		||||
                                </a>
 | 
			
		||||
                                <ImagePicker
 | 
			
		||||
                                    class="is-rounded avatar"
 | 
			
		||||
                                    alt="Image for discord avatar"
 | 
			
		||||
                                    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
 | 
			
		||||
                            class="is-rounded embed_author_url"
 | 
			
		||||
                            src={icon || "/static/img/bg.webp"}
 | 
			
		||||
                            alt="Image for embed author"
 | 
			
		||||
                        ></img>
 | 
			
		||||
                    </a>
 | 
			
		||||
                    <ImagePicker
 | 
			
		||||
                        class="is-rounded embed_author_url"
 | 
			
		||||
                        url={icon}
 | 
			
		||||
                        alt="Image for embed author"
 | 
			
		||||
                        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
 | 
			
		||||
                                class="embed_thumbnail_url"
 | 
			
		||||
                                src="/static/img/bg.webp"
 | 
			
		||||
                                alt="Square thumbnail embedded image"
 | 
			
		||||
                            ></img>
 | 
			
		||||
                        </a>
 | 
			
		||||
                        <ImagePicker
 | 
			
		||||
                            class="embed_thumbnail_url"
 | 
			
		||||
                            alt="Square thumbnail embedded image"
 | 
			
		||||
                            setImage={() => {}}
 | 
			
		||||
                        ></ImagePicker>
 | 
			
		||||
                    </p>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <p class="image is-400x300 customizable">
 | 
			
		||||
                <a>
 | 
			
		||||
                    <img
 | 
			
		||||
                        class="embed_image_url"
 | 
			
		||||
                        src="/static/img/bg.webp"
 | 
			
		||||
                        alt="Large embedded image"
 | 
			
		||||
                    ></img>
 | 
			
		||||
                </a>
 | 
			
		||||
                <ImagePicker
 | 
			
		||||
                    class="embed_image_url"
 | 
			
		||||
                    alt="Large embedded image"
 | 
			
		||||
                    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",
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user