Add ability for admins to contact creators

This commit is contained in:
Jared Schoeny 2026-05-29 13:38:29 -06:00
parent e122a182d7
commit ac81e2eebb
3 changed files with 35 additions and 15 deletions

View File

@ -43,6 +43,7 @@ export interface HackMetadata {
username: string | null;
avatar_url: string | null;
verified: boolean;
email: string | null;
} | null;
otherHacks: {
slug: string;
@ -104,10 +105,17 @@ export async function getHackMetadata(slug: string): Promise<HackMetadata | null
// Fetch profile
const { data: profile } = await supabase
.from("profiles")
.select("username,avatar_url,verified")
.select("id,username,avatar_url,verified")
.eq("id", hack.created_by as string)
.maybeSingle();
// Meant to only be available to admins (gated in server-side page rendering)
let userEmail: string | null = null;
if (profile) {
const { data: userData } = await supabase.auth.admin.getUserById(profile.id);
userEmail = userData?.user?.email || null;
}
// Get other approved hacks by the same author (non-archive hacks only)
let otherHacks: {
slug: string;
@ -160,6 +168,7 @@ export async function getHackMetadata(slug: string): Promise<HackMetadata | null
username: profile.username,
avatar_url: profile.avatar_url,
verified: profile.verified,
email: userEmail,
} : null,
otherHacks,
patch,

View File

@ -7,7 +7,7 @@ import HackActions from "@/components/Hack/HackActions";
import Markdown from "@/components/Markdown/Markdown";
import Image from "next/image";
import { FaDiscord, FaTwitter, FaGithub, FaTriangleExclamation, FaArrowUpRightFromSquare } from "react-icons/fa6";
import { FiAlertTriangle, FiInfo } from "react-icons/fi";
import { FiAlertTriangle, FiInfo, FiMail } from "react-icons/fi";
import PokeCommunityIcon from "@/components/Icons/PokeCommunityIcon";
import { createClient, createServiceClient } from "@/utils/supabase/server";
import HackOptionsMenu from "@/components/Hack/HackOptionsMenu";
@ -134,18 +134,15 @@ export default async function HackDetail({ params }: HackDetailProps) {
canEdit: canUploadPatch,
} = await checkPatchEditPermission(hack, user?.id as string, supabase);
// isAdmin always needs to be checked for archive hacks
let isAdmin = false;
if (!hack.approved || isArchive) {
const { data: admin } = await supabase.rpc("is_admin");
if (admin) {
isAdmin = true;
} else if (!hack.approved) {
if (isArchive && !canEditAsArchiver) {
return notFound();
} else if (!canEdit) {
return notFound();
}
const { data: admin } = await supabase.rpc("is_admin");
if (admin) {
isAdmin = true;
} else if (!hack.approved || isArchive) {
if (isArchive && !canEditAsArchiver) {
return notFound();
} else if (!canEdit) {
return notFound();
}
}
@ -452,6 +449,16 @@ export default async function HackDetail({ params }: HackDetailProps) {
Approve
</MenuItem>
)}
{isAdmin && profile?.email && (
<MenuItem
as="a"
href={`mailto:${profile.email}`}
className="block w-full px-3 py-2 text-left text-sm text-foreground/80 font-medium data-focus:bg-black/5 dark:data-focus:bg-white/10"
>
<FiMail className="mr-2 inline-block align-middle mb-0.5 text-foreground/80" size={12} />
Contact creator
</MenuItem>
)}
</HackOptionsMenu>
</div>
</div>

View File

@ -1,6 +1,6 @@
"use client";
import React, { useState } from "react";
import React, { useMemo, useState } from "react";
import { FiMoreVertical, FiEdit2, FiBarChart2 } from "react-icons/fi";
import { TbVersions } from "react-icons/tb";
import { Menu, MenuButton, MenuItem, MenuItems, MenuSeparator } from "@headlessui/react";
@ -21,6 +21,10 @@ export default function HackOptionsMenu({
}: HackOptionsMenuProps) {
const [showReportModal, setShowReportModal] = useState(false);
const hasRenderableChildren = useMemo(() => {
return React.Children.toArray(children).some(Boolean);
}, [children]);
return (
<>
<Menu as="div" className="relative">
@ -91,7 +95,7 @@ export default function HackOptionsMenu({
Manage versions
</MenuItem>
)}
{children && <>
{hasRenderableChildren && <>
<MenuSeparator className="my-1 h-px bg-[var(--border)]" />
{children}
</>}