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;
 | 
					    name: string;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type RoleInfo = {
 | 
				
			||||||
 | 
					    id: string;
 | 
				
			||||||
 | 
					    name: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Template = {
 | 
					type Template = {
 | 
				
			||||||
    id: number;
 | 
					    id: number;
 | 
				
			||||||
    name: string;
 | 
					    name: string;
 | 
				
			||||||
@@ -72,15 +77,16 @@ type Template = {
 | 
				
			|||||||
    embed_fields: EmbedField[] | null;
 | 
					    embed_fields: EmbedField[] | null;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function fetchUserInfo(): Promise<UserInfo> {
 | 
					export const fetchUserInfo = () => ({
 | 
				
			||||||
    return axios.get("/dashboard/api/user").then((resp) => resp.data) as Promise<UserInfo>;
 | 
					    queryKey: ["USER_INFO"],
 | 
				
			||||||
}
 | 
					    queryFn: () => axios.get("/dashboard/api/user").then((resp) => resp.data) as Promise<UserInfo>,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function fetchUserGuilds(): Promise<GuildInfo[]> {
 | 
					export const fetchUserGuilds = () => ({
 | 
				
			||||||
    return axios.get("/dashboard/api/user/guilds").then((resp) => resp.data) as Promise<
 | 
					    queryKey: ["USER_GUILDS"],
 | 
				
			||||||
        GuildInfo[]
 | 
					    queryFn: () =>
 | 
				
			||||||
    >;
 | 
					        axios.get("/dashboard/api/user/guilds").then((resp) => resp.data) as Promise<GuildInfo[]>,
 | 
				
			||||||
}
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const fetchGuildReminders = (guild: string) => ({
 | 
					export const fetchGuildReminders = (guild: string) => ({
 | 
				
			||||||
    queryKey: ["GUILD_REMINDERS", guild],
 | 
					    queryKey: ["GUILD_REMINDERS", guild],
 | 
				
			||||||
@@ -106,6 +112,15 @@ export const fetchGuildChannels = (guild: string) => ({
 | 
				
			|||||||
    staleTime: 300,
 | 
					    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) => ({
 | 
					export const guildTemplatesQuery = (guild: string) => ({
 | 
				
			||||||
    queryKey: ["GUILD_TEMPLATES", guild],
 | 
					    queryKey: ["GUILD_TEMPLATES", guild],
 | 
				
			||||||
    queryFn: () =>
 | 
					    queryFn: () =>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@ type Props = {
 | 
				
			|||||||
    setModalOpen: (open: boolean) => never;
 | 
					    setModalOpen: (open: boolean) => never;
 | 
				
			||||||
    title: string;
 | 
					    title: string;
 | 
				
			||||||
    onSubmitText?: string;
 | 
					    onSubmitText?: string;
 | 
				
			||||||
    onSubmit?: () => never;
 | 
					    onSubmit?: () => void;
 | 
				
			||||||
    children: string | JSX.Element | JSX.Element[] | (() => JSX.Element);
 | 
					    children: string | JSX.Element | JSX.Element[] | (() => JSX.Element);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,7 @@
 | 
				
			|||||||
import { useParams } from "wouter";
 | 
					import { useParams } from "wouter";
 | 
				
			||||||
import { useState } from "preact/hooks";
 | 
					import { useState } from "preact/hooks";
 | 
				
			||||||
import { useQueries } from "react-query";
 | 
					import { useQuery } from "react-query";
 | 
				
			||||||
import { QueryKeys } from "../../consts";
 | 
					import { fetchUserInfo, Reminder } 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 { Content } from "./Content";
 | 
					import { Content } from "./Content";
 | 
				
			||||||
@@ -11,6 +10,7 @@ import { ChannelSelector } from "./ChannelSelector";
 | 
				
			|||||||
import { DateTime } from "luxon";
 | 
					import { DateTime } from "luxon";
 | 
				
			||||||
import { IntervalSelector } from "./IntervalSelector";
 | 
					import { IntervalSelector } from "./IntervalSelector";
 | 
				
			||||||
import { LoadTemplate } from "./LoadTemplate";
 | 
					import { LoadTemplate } from "./LoadTemplate";
 | 
				
			||||||
 | 
					import { ImagePicker } from "./ImagePicker";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function defaultReminder(): Reminder {
 | 
					function defaultReminder(): Reminder {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
@@ -47,21 +47,11 @@ export const CreateReminder = () => {
 | 
				
			|||||||
    const { guild } = useParams();
 | 
					    const { guild } = useParams();
 | 
				
			||||||
    const [reminder, setReminder] = useState(defaultReminder);
 | 
					    const [reminder, setReminder] = useState(defaultReminder);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const [
 | 
					    const { isSuccess: userFetched, data: userInfo } = useQuery(fetchUserInfo());
 | 
				
			||||||
        { isSuccess: channelsFetched, data: guildChannels },
 | 
					 | 
				
			||||||
        { isSuccess: userFetched, data: userInfo },
 | 
					 | 
				
			||||||
    ] = useQueries([
 | 
					 | 
				
			||||||
        fetchGuildChannels(guild),
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            queryKey: [QueryKeys.USER_DATA],
 | 
					 | 
				
			||||||
            queryFn: fetchUserInfo,
 | 
					 | 
				
			||||||
            staleTime: Infinity,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    ]);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const [collapsed, setCollapsed] = useState(false);
 | 
					    const [collapsed, setCollapsed] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!channelsFetched || !userFetched) {
 | 
					    if (!userFetched) {
 | 
				
			||||||
        // todo
 | 
					        // todo
 | 
				
			||||||
        return <></>;
 | 
					        return <></>;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -87,13 +77,11 @@ export const CreateReminder = () => {
 | 
				
			|||||||
                    <article class="media">
 | 
					                    <article class="media">
 | 
				
			||||||
                        <figure class="media-left">
 | 
					                        <figure class="media-left">
 | 
				
			||||||
                            <p class="image is-32x32 customizable">
 | 
					                            <p class="image is-32x32 customizable">
 | 
				
			||||||
                                <a>
 | 
					                                <ImagePicker
 | 
				
			||||||
                                    <img
 | 
					                                    class="is-rounded avatar"
 | 
				
			||||||
                                        class="is-rounded avatar"
 | 
					                                    alt="Image for discord avatar"
 | 
				
			||||||
                                        src="/static/img/bg.webp"
 | 
					                                    setImage={() => {}}
 | 
				
			||||||
                                        alt="Image for discord avatar"
 | 
					                                ></ImagePicker>
 | 
				
			||||||
                                    ></img>
 | 
					 | 
				
			||||||
                                </a>
 | 
					 | 
				
			||||||
                            </p>
 | 
					                            </p>
 | 
				
			||||||
                        </figure>
 | 
					                        </figure>
 | 
				
			||||||
                        <div class="media-content">
 | 
					                        <div class="media-content">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,14 +22,7 @@ export const EditReminder = ({ reminder: initialReminder }: Props) => {
 | 
				
			|||||||
    const [
 | 
					    const [
 | 
				
			||||||
        { isSuccess: channelsFetched, data: guildChannels },
 | 
					        { isSuccess: channelsFetched, data: guildChannels },
 | 
				
			||||||
        { isSuccess: userFetched, data: userInfo },
 | 
					        { isSuccess: userFetched, data: userInfo },
 | 
				
			||||||
    ] = useQueries([
 | 
					    ] = useQueries([fetchGuildChannels(guild), fetchUserInfo()]);
 | 
				
			||||||
        fetchGuildChannels(guild),
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            queryKey: [QueryKeys.USER_DATA],
 | 
					 | 
				
			||||||
            queryFn: fetchUserInfo,
 | 
					 | 
				
			||||||
            staleTime: Infinity,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    ]);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const [collapsed, setCollapsed] = useState(false);
 | 
					    const [collapsed, setCollapsed] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,15 +1,16 @@
 | 
				
			|||||||
 | 
					import { ImagePicker } from "../ImagePicker";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Author = ({ name, icon }) => {
 | 
					export const Author = ({ name, icon }) => {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <div class="embed-author-box">
 | 
					        <div class="embed-author-box">
 | 
				
			||||||
            <div class="a">
 | 
					            <div class="a">
 | 
				
			||||||
                <p class="image is-24x24 customizable">
 | 
					                <p class="image is-24x24 customizable">
 | 
				
			||||||
                    <a>
 | 
					                    <ImagePicker
 | 
				
			||||||
                        <img
 | 
					                        class="is-rounded embed_author_url"
 | 
				
			||||||
                            class="is-rounded embed_author_url"
 | 
					                        url={icon}
 | 
				
			||||||
                            src={icon || "/static/img/bg.webp"}
 | 
					                        alt="Image for embed author"
 | 
				
			||||||
                            alt="Image for embed author"
 | 
					                        setImage={() => {}}
 | 
				
			||||||
                        ></img>
 | 
					                    ></ImagePicker>
 | 
				
			||||||
                    </a>
 | 
					 | 
				
			||||||
                </p>
 | 
					                </p>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,11 +4,7 @@ import { Description } from "./Description";
 | 
				
			|||||||
import { Footer } from "./Footer";
 | 
					import { Footer } from "./Footer";
 | 
				
			||||||
import { Color } from "./Color";
 | 
					import { Color } from "./Color";
 | 
				
			||||||
import { Reminder } from "../../../api";
 | 
					import { Reminder } from "../../../api";
 | 
				
			||||||
 | 
					import { ImagePicker } from "../ImagePicker";
 | 
				
			||||||
type Props = {
 | 
					 | 
				
			||||||
    reminder: Reminder;
 | 
					 | 
				
			||||||
    setReminder: (reminder: Reminder) => {};
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
function colorToInt(hex: string) {
 | 
					function colorToInt(hex: string) {
 | 
				
			||||||
    return parseInt(hex.substring(1), 16);
 | 
					    return parseInt(hex.substring(1), 16);
 | 
				
			||||||
@@ -85,25 +81,21 @@ export const Embed = ({ reminder, setReminder }) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                <div class="b">
 | 
					                <div class="b">
 | 
				
			||||||
                    <p class="image thumbnail customizable">
 | 
					                    <p class="image thumbnail customizable">
 | 
				
			||||||
                        <a>
 | 
					                        <ImagePicker
 | 
				
			||||||
                            <img
 | 
					                            class="embed_thumbnail_url"
 | 
				
			||||||
                                class="embed_thumbnail_url"
 | 
					                            alt="Square thumbnail embedded image"
 | 
				
			||||||
                                src="/static/img/bg.webp"
 | 
					                            setImage={() => {}}
 | 
				
			||||||
                                alt="Square thumbnail embedded image"
 | 
					                        ></ImagePicker>
 | 
				
			||||||
                            ></img>
 | 
					 | 
				
			||||||
                        </a>
 | 
					 | 
				
			||||||
                    </p>
 | 
					                    </p>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <p class="image is-400x300 customizable">
 | 
					            <p class="image is-400x300 customizable">
 | 
				
			||||||
                <a>
 | 
					                <ImagePicker
 | 
				
			||||||
                    <img
 | 
					                    class="embed_image_url"
 | 
				
			||||||
                        class="embed_image_url"
 | 
					                    alt="Large embedded image"
 | 
				
			||||||
                        src="/static/img/bg.webp"
 | 
					                    setImage={() => {}}
 | 
				
			||||||
                        alt="Large embedded image"
 | 
					                ></ImagePicker>
 | 
				
			||||||
                    ></img>
 | 
					 | 
				
			||||||
                </a>
 | 
					 | 
				
			||||||
            </p>
 | 
					            </p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <Footer footer={reminder.embed_footer} icon={reminder.embed_footer_url}></Footer>
 | 
					            <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 {
 | 
					export enum QueryKeys {
 | 
				
			||||||
    USER_DATA = "userData",
 | 
					 | 
				
			||||||
    USER_GUILDS = "userGuilds",
 | 
					    USER_GUILDS = "userGuilds",
 | 
				
			||||||
    GUILD_REMINDERS = "guildReminders",
 | 
					    GUILD_REMINDERS = "guildReminders",
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user