feat(channels): allow assigning category when creating channel
All checks were successful
Deploy Waveform to VPS / deploy (push) Successful in 59s
All checks were successful
Deploy Waveform to VPS / deploy (push) Successful in 59s
This commit is contained in:
parent
2321551518
commit
0f5f7c75f2
3 changed files with 43 additions and 38 deletions
|
|
@ -5,18 +5,11 @@
|
||||||
|
|
||||||
import { auth } from "@/auth";
|
import { auth } from "@/auth";
|
||||||
import { db } from "@/db";
|
import { db } from "@/db";
|
||||||
import { channels, members } from "@/db/schema";
|
import { categories, channels, members } from "@/db/schema";
|
||||||
import { and, eq } from "drizzle-orm";
|
import { and, eq } from "drizzle-orm";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
/**
|
/** Handles the POST request to create a new channel within a specific server. */
|
||||||
* Handles the POST request to create a new channel within a specific server.
|
|
||||||
*
|
|
||||||
* @async
|
|
||||||
* @function POST
|
|
||||||
* @param {Request} req - The incoming HTTP request containing JSON payload with `name` and `serverId`.
|
|
||||||
* @returns {Promise<NextResponse>} The created channel object with status 201, or an error response (401, 400, 403, 500).
|
|
||||||
*/
|
|
||||||
export async function POST(req: Request) {
|
export async function POST(req: Request) {
|
||||||
try {
|
try {
|
||||||
const session = await auth();
|
const session = await auth();
|
||||||
|
|
@ -25,7 +18,7 @@ export async function POST(req: Request) {
|
||||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { name, serverId } = await req.json();
|
const { name, serverId, categoryId } = await req.json();
|
||||||
|
|
||||||
if (!name || !serverId) {
|
if (!name || !serverId) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
|
|
@ -61,12 +54,31 @@ export async function POST(req: Request) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate category existence and server association if provided
|
||||||
|
if (categoryId) {
|
||||||
|
const [category] = await db
|
||||||
|
.select()
|
||||||
|
.from(categories)
|
||||||
|
.where(
|
||||||
|
and(eq(categories.id, categoryId), eq(categories.serverId, serverId)),
|
||||||
|
)
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (!category) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Invalid category provided for this server" },
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create the channel in the database
|
// Create the channel in the database
|
||||||
const [newChannel] = await db
|
const [newChannel] = await db
|
||||||
.insert(channels)
|
.insert(channels)
|
||||||
.values({
|
.values({
|
||||||
name: name.trim().toLowerCase().replace(/\s+/g, "-"),
|
name: name.trim().toLowerCase().replace(/\s+/g, "-"),
|
||||||
serverId,
|
serverId,
|
||||||
|
categoryId: categoryId || null,
|
||||||
})
|
})
|
||||||
.returning();
|
.returning();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,59 +7,47 @@
|
||||||
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { X, Loader2 } from "lucide-react";
|
import { X } from "lucide-react";
|
||||||
import { useActiveServer } from "@/lib/context/ServerContext";
|
import { useActiveServer } from "@/lib/context/ServerContext";
|
||||||
import { ActionButton } from "../ui/ActionButton";
|
import { ActionButton } from "../ui/ActionButton";
|
||||||
|
|
||||||
/**
|
/** Properties for the CreateChannelModal component. */
|
||||||
* Properties for the CreateChannelModal component.
|
|
||||||
*
|
|
||||||
* @interface CreateChannelModalProps
|
|
||||||
* @property {boolean} isOpen - Determines whether the modal is visible.
|
|
||||||
* @property {() => void} onClose - Callback function executed to close the modal.
|
|
||||||
* @property {string} serverId - The unique identifier of the target server where the channel is created.
|
|
||||||
*/
|
|
||||||
interface CreateChannelModalProps {
|
interface CreateChannelModalProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
serverId: string;
|
serverId: string;
|
||||||
|
defaultCategoryId?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Renders a modal dialog allowing users to input a name and create a new server channel. */
|
||||||
* Renders a modal dialog allowing users to input a name and create a new server channel.
|
|
||||||
*
|
|
||||||
* @param {CreateChannelModalProps} props - The component props.
|
|
||||||
* @param {boolean} props.isOpen - Determines whether the modal is visible.
|
|
||||||
* @param {() => void} props.onClose - Callback function executed to close the modal.
|
|
||||||
* @param {string} props.serverId - The unique identifier of the target server where the channel is created.
|
|
||||||
* @returns {JSX.Element | null} The rendered modal component or null if closed.
|
|
||||||
*/
|
|
||||||
export function CreateChannelModal({
|
export function CreateChannelModal({
|
||||||
isOpen,
|
isOpen,
|
||||||
onClose,
|
onClose,
|
||||||
serverId,
|
serverId,
|
||||||
|
defaultCategoryId = null,
|
||||||
}: CreateChannelModalProps) {
|
}: CreateChannelModalProps) {
|
||||||
const [name, setName] = useState("");
|
const [name, setName] = useState("");
|
||||||
|
const [categoryId, setCategoryId] = useState<string | null>(
|
||||||
|
defaultCategoryId,
|
||||||
|
);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { addChannel } = useActiveServer();
|
const { addChannel } = useActiveServer();
|
||||||
|
|
||||||
|
// Update categoryId if the defaultCategoryId changes when the page opens
|
||||||
|
useEffect(() => {
|
||||||
|
setCategoryId(defaultCategoryId);
|
||||||
|
}, [defaultCategoryId, isOpen]);
|
||||||
|
|
||||||
if (!isOpen) return null;
|
if (!isOpen) return null;
|
||||||
|
|
||||||
const isValid = name.trim().length != 0;
|
const isValid = name.trim().length != 0;
|
||||||
const canSave = isValid && !isLoading;
|
const canSave = isValid && !isLoading;
|
||||||
|
|
||||||
/**
|
/** Handles form submission to create a new channel via the API. */
|
||||||
* Handles form submission to create a new channel via the API.
|
const handleSubmit = async (e: React.SubmitEvent) => {
|
||||||
*
|
|
||||||
* @async
|
|
||||||
* @function handleSubmit
|
|
||||||
* @param {React.FormEvent} e - The form submission event.
|
|
||||||
* @returns {Promise<void>} Resolves when the channel creation request completes.
|
|
||||||
*/
|
|
||||||
const handleSubmit = async (e: React.FormEvent) => {
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!name.trim() || isLoading) return;
|
if (!name.trim() || isLoading) return;
|
||||||
|
|
||||||
|
|
@ -70,7 +58,11 @@ export function CreateChannelModal({
|
||||||
const response = await fetch("/api/channels", {
|
const response = await fetch("/api/channels", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({ name, serverId }),
|
body: JSON.stringify({
|
||||||
|
name,
|
||||||
|
serverId,
|
||||||
|
categoryId: categoryId || null,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
|
|
||||||
|
|
@ -209,6 +209,7 @@ export function ChannelSidebar() {
|
||||||
isOpen={isCreateModalOpen}
|
isOpen={isCreateModalOpen}
|
||||||
onClose={() => setIsCreateModalOpen(false)}
|
onClose={() => setIsCreateModalOpen(false)}
|
||||||
serverId={activeServer.id}
|
serverId={activeServer.id}
|
||||||
|
defaultCategoryId={selectedCategoryId}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<EditChannelModal
|
<EditChannelModal
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue