The weeb for the next gen discord boat - Wamellow wamellow.com
bot discord
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

add reddit notifications

Luna 789ec485 0478fa2e

+131 -15
+103
app/dashboard/[guildId]/notifications/create-reddit.component.tsx
··· 1 + "use client"; 2 + 3 + import { useState } from "react"; 4 + 5 + import { guildStore } from "@/common/guilds"; 6 + import DumbTextInput from "@/components/inputs/dumb-text-input"; 7 + import SelectMenu from "@/components/inputs/select-menu"; 8 + import Modal from "@/components/modal"; 9 + import { type ApiV1GuildsModulesNotificationsGetResponse, NotificationType } from "@/typings"; 10 + import { createSelectableItems } from "@/utils/create-selectable-items"; 11 + 12 + const URL_CHANNEL_REGEX = /^https?:\/\/((www|m|old|oauth)\.)?reddit\.com\/r\/(?=.{3,21}$)[A-Za-z][A-Za-z0-9_]*\/?$/; 13 + const CHANNE_HANDLE = /^((\/)?r\/)?(?=.{3,21}$)[A-Za-z][A-Za-z0-9_]*$/; 14 + 15 + function validateAccount(input: string) { 16 + if (URL_CHANNEL_REGEX.exec(input)) return input.split("/r/")[1].replace(/\/$/, ""); 17 + if (CHANNE_HANDLE.exec(input)) return input.replace(/^(\/)?r\//, ""); 18 + return null; 19 + } 20 + 21 + interface Props { 22 + add: (notification: ApiV1GuildsModulesNotificationsGetResponse) => void; 23 + set: (id: string) => void; 24 + 25 + isOpen: boolean; 26 + onClose: () => void; 27 + } 28 + 29 + export function RedditNotificationModal({ 30 + add, 31 + set, 32 + 33 + isOpen, 34 + onClose 35 + }: Props) { 36 + const guildId = guildStore((g) => g?.id); 37 + const channels = guildStore((g) => g?.channels); 38 + 39 + const [name, setName] = useState(""); 40 + const [channelId, setChannelId] = useState<string | null>(null); 41 + 42 + return (<> 43 + <Modal<ApiV1GuildsModulesNotificationsGetResponse> 44 + title="Create new notification" 45 + isOpen={isOpen} 46 + onClose={onClose} 47 + onSubmit={() => { 48 + const validated = validateAccount(name); 49 + if (!validated && name.startsWith("https://")) return new Error("Invalid subreddit url"); 50 + if (!validated) return new Error("Invalid subreddit name"); 51 + 52 + return fetch(`${process.env.NEXT_PUBLIC_API}/guilds/${guildId}/modules/notifications`, { 53 + method: "POST", 54 + credentials: "include", 55 + headers: { 56 + "Content-Type": "application/json" 57 + }, 58 + body: JSON.stringify({ 59 + type: NotificationType.Reddit, 60 + channelId, 61 + creatorHandle: validated 62 + }) 63 + }); 64 + }} 65 + onSuccess={(tag) => { 66 + add(tag); 67 + set(tag.id); 68 + 69 + setName(""); 70 + setChannelId(null); 71 + }} 72 + > 73 + <DumbTextInput 74 + name="Subreddit" 75 + placeholder="r/wamellow" 76 + value={name} 77 + setValue={setName} 78 + /> 79 + 80 + <SelectMenu 81 + name="Channel" 82 + dataName="channelId" 83 + items={createSelectableItems(channels)} 84 + description="Select a channel where notifications should be send into." 85 + onSave={(o) => { 86 + setChannelId(o.value as string); 87 + }} 88 + /> 89 + 90 + <div className="mt-4"> 91 + <span className="text-lg dark:text-neutral-300 text-neutral-700 font-medium">How to get a subreddits&apos; name</span> 92 + <br /> 93 + 94 + The subreddit name is the string with the leading <code className="break-all">r/</code>, such as <code>r/wamellow</code>. 95 + <br /> 96 + <br /> 97 + 98 + Though, you can also use the link of the subreddit. 99 + </div> 100 + 101 + </Modal> 102 + </>); 103 + }
+20 -12
app/dashboard/[guildId]/notifications/page.tsx
··· 98 98 size="sm" 99 99 placement="bottom-left" 100 100 > 101 - <Image 102 - alt={`${item.creator.username}'s avatar`} 103 - className="rounded-full" 104 - src={item.creator.avatarUrl} 105 - width={46} 106 - height={46} 107 - /> 101 + {item.creator.avatarUrl 102 + ? <Image 103 + alt={`${item.creator.username}'s avatar`} 104 + className="rounded-full" 105 + src={item.creator.avatarUrl} 106 + width={46} 107 + height={46} 108 + /> 109 + : <div className="size-[46px] flex items-center justify-center bg-wamellow rounded-full select-none font-medium text-lg text-neutral-200"> 110 + {item.creator.username.slice(0, 2)} 111 + </div> 112 + } 108 113 </ClientBadge> 109 114 110 115 <div className="flex flex-col items-start"> ··· 138 143 href="/notifications" 139 144 docs="/notifications" 140 145 141 - avatar={ 142 - <Image 143 - alt={`${item?.creator.username}'s avatar`} 144 - className="rounded-full size-5.5" 145 - src={item?.creator.avatarUrl || ""} 146 + avatar={item.creator.avatarUrl 147 + ? <Image 148 + alt={`${item.creator.username}'s avatar`} 149 + className="rounded-full" 150 + src={item.creator.avatarUrl} 146 151 width={24} 147 152 height={24} 148 153 /> 154 + : <div className="size-[24px] flex items-center justify-center bg-wamellow rounded-full select-none font-medium text-sm text-neutral-200"> 155 + {item.creator.username.slice(0, 2)} 156 + </div> 149 157 } 150 158 name={item.creator.username} 151 159 icon={<Icon type={item.type} className="text-white size-3" />}
+6 -2
app/dashboard/[guildId]/notifications/select.component.tsx
··· 1 1 import { PopoverClose } from "@radix-ui/react-popover"; 2 2 import React, { useState } from "react"; 3 - import { BsTwitch, BsYoutube } from "react-icons/bs"; 3 + import { BsReddit, BsTwitch, BsYoutube } from "react-icons/bs"; 4 4 import { FaBluesky } from "react-icons/fa6"; 5 5 6 6 import { badgeVariants } from "@/components/ui/badge"; ··· 10 10 import { cn } from "@/utils/cn"; 11 11 12 12 import { BlueskyNotificationModal } from "./create-bluesky.component"; 13 + import { RedditNotificationModal } from "./create-reddit.component"; 13 14 import { TwitchNotificationModal } from "./create-twitch.component"; 14 15 import { YoutubeNotificationModal } from "./create-youtube.component"; 15 16 ··· 21 22 const Platform = { 22 23 YouTube: 0, 23 24 Twitch: 1, 24 - Bluesky: 2 25 + Bluesky: 2, 26 + Reddit: 3 25 27 } as const; 26 28 27 29 interface Props { ··· 63 65 <YoutubeNotificationModal add={add} set={set} isOpen={platform === Platform.YouTube} onClose={() => setPlatform(null)} /> 64 66 <TwitchNotificationModal add={add} set={set} isOpen={platform === Platform.Twitch} onClose={() => setPlatform(null)} /> 65 67 <BlueskyNotificationModal add={add} set={set} isOpen={platform === Platform.Bluesky} onClose={() => setPlatform(null)} /> 68 + <RedditNotificationModal add={add} set={set} isOpen={platform === Platform.Reddit} onClose={() => setPlatform(null)} /> 66 69 </>); 67 70 } 68 71 ··· 112 115 case NotificationType.YouTube: return <BsYoutube className={cn("text-red-500", className)} />; 113 116 case NotificationType.Twitch: return <BsTwitch className={cn("text-violet-500", className)} />; 114 117 case NotificationType.Bluesky: return <FaBluesky className={cn("text-blue-500", className)} />; 118 + case NotificationType.Reddit: return <BsReddit className={cn("text-orange-500", className)} />; 115 119 } 116 120 }
+2 -1
typings.ts
··· 391 391 YouTube = 0, 392 392 Twitch = 1, 393 393 Bluesky = 2, 394 + Reddit = 3 394 395 } 395 396 396 397 export enum NotificationFlags { ··· 423 424 id: string; 424 425 username: string; 425 426 customUrl: string; 426 - avatarUrl: string; 427 + avatarUrl: string | null; 427 428 }; 428 429 } 429 430