Skip to content

Commit

Permalink
Chat header and Conversation
Browse files Browse the repository at this point in the history
  • Loading branch information
rohannrk committed Sep 23, 2023
1 parent a98a006 commit 2e66a35
Show file tree
Hide file tree
Showing 6 changed files with 431 additions and 12 deletions.
100 changes: 94 additions & 6 deletions app/(main)/(routes)/servers/[serverId]/channels/[channelId]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,97 @@
const ChannelIdPage = () => {
return (
<div>
Channel ID Page!
</div>
);
import { redirectToSignIn } from "@clerk/nextjs";
import { redirect } from "next/navigation";
import { ChannelType } from "@prisma/client";

import { currentProfile } from "@/lib/current-profile";
import { ChatHeader } from "@/components/chat/chat-header";
// import { ChatInput } from "@/components/chat/chat-input";
// import { ChatMessages } from "@/components/chat/chat-messages";
// import { MediaRoom } from "@/components/media-room";
import { db } from "@/lib/db";

interface ChannelIdPageProps {
params: {
serverId: string;
channelId: string;
}
}

const ChannelIdPage = async ({
params
}: ChannelIdPageProps) => {
const profile = await currentProfile();

if (!profile) {
return redirectToSignIn();
}

const channel = await db.channel.findUnique({
where: {
id: params.channelId,
},
});

const member = await db.member.findFirst({
where: {
serverId: params.serverId,
profileId: profile.id,
}
});

if (!channel || !member) {
redirect("/");
}

return (
<div className="bg-white dark:bg-[#313338] flex flex-col h-full">
<ChatHeader
name={channel.name}
serverId={channel.serverId}
type="channel"
/>
{/* {channel.type === ChannelType.TEXT && (
<>
<ChatMessages
member={member}
name={channel.name}
chatId={channel.id}
type="channel"
apiUrl="/api/messages"
socketUrl="/api/socket/messages"
socketQuery={{
channelId: channel.id,
serverId: channel.serverId,
}}
paramKey="channelId"
paramValue={channel.id}
/>
<ChatInput
name={channel.name}
type="channel"
apiUrl="/api/socket/messages"
query={{
channelId: channel.id,
serverId: channel.serverId,
}}
/>
</>
)}
{channel.type === ChannelType.AUDIO && (
<MediaRoom
chatId={channel.id}
video={false}
audio={true}
/>
)}
{channel.type === ChannelType.VIDEO && (
<MediaRoom
chatId={channel.id}
video={true}
audio={true}
/>
)} */}
</div>
);
}

export default ChannelIdPage;
Original file line number Diff line number Diff line change
@@ -1,9 +1,65 @@
const MemberIdPage = () => {
return (
<div>
Member ID Page!
</div>
);
import { redirectToSignIn } from "@clerk/nextjs";
import { redirect } from "next/navigation";

import { db } from "@/lib/db";
import { getOrCreateConversation } from "@/lib/conversation";
import { currentProfile } from "@/lib/current-profile";
import { ChatHeader } from "@/components/chat/chat-header";

interface MemberIdPageProps {
params: {
memberId: string;
serverId: string;
},
searchParams: {
video?: boolean;
}
}

const MemberIdPage = async ({
params,
searchParams,
}: MemberIdPageProps) => {
const profile = await currentProfile();

if (!profile) {
return redirectToSignIn();
}

const currentMember = await db.member.findFirst({
where: {
serverId: params.serverId,
profileId: profile.id,
},
include: {
profile: true,
},
});

if (!currentMember) {
return redirect("/");
}

const conversation = await getOrCreateConversation(currentMember.id, params.memberId);

if (!conversation) {
return redirect(`/servers/${params.serverId}`);
}

const { memberOne, memberTwo } = conversation;

const otherMember = memberOne.profileId === profile.id ? memberTwo : memberOne;

return (
<div className="bg-white dark:bg-[#313338] flex flex-col h-full">
<ChatHeader
imageUrl={otherMember.profile.imageUrl}
name={otherMember.profile.name}
serverId={params.serverId}
type="conversation"
/>
</div>
);
}

export default MemberIdPage;
36 changes: 36 additions & 0 deletions components/chat/chat-header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Hash } from "lucide-react";

import { UserAvatar } from "@/components/user-avatar";
import { MobileToggle } from "../mobile-toggle";

interface ChatHeaderProps {
serverId: string;
name: string;
type: "channel" | "conversation";
imageUrl?: string;
}

export const ChatHeader = ({
serverId,
name,
type,
imageUrl
}: ChatHeaderProps) => {
return (
<div className="text-md font-semibold px-3 flex items-center h-12 border-neutral-200 dark:border-neutral-800 border-b-2">
<MobileToggle serverId={serverId}/>
{type === "channel" && (
<Hash className="w-5 h-5 text-zinc-500 dark:text-zinc-400 mr-2" />
)}
{type === "conversation" && (
<UserAvatar
src={imageUrl}
className="h-8 w-8 md:h-8 md:w-8 mr-2"
/>
)}
<p className="font-semibold text-md text-black dark:text-white">
{name}
</p>
</div>
)
}
32 changes: 32 additions & 0 deletions components/mobile-toggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Menu } from "lucide-react"

import {
Sheet,
SheetContent,
SheetTrigger,
} from "@/components/ui/sheet";
import { Button } from "@/components/ui/button";
import { NavigationSidebar } from "@/components/navigation/navigation-sidebar";
import { ServerSidebar } from "@/components/server/server-sidebar";

export const MobileToggle = ({
serverId
}: {
serverId: string;
}) => {
return (
<Sheet>
<SheetTrigger asChild>
<Button variant="ghost" size="icon" className="md:hidden">
<Menu />
</Button>
</SheetTrigger>
<SheetContent side="left" className="p-0 flex gap-0">
<div className="w-[72px]">
<NavigationSidebar />
</div>
<ServerSidebar serverId={serverId} />
</SheetContent>
</Sheet>
)
}
144 changes: 144 additions & 0 deletions components/ui/sheet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
"use client"

import * as React from "react"
import * as SheetPrimitive from "@radix-ui/react-dialog"
import { cva, type VariantProps } from "class-variance-authority"
import { X } from "lucide-react"

import { cn } from "@/lib/utils"

const Sheet = SheetPrimitive.Root

const SheetTrigger = SheetPrimitive.Trigger

const SheetClose = SheetPrimitive.Close

const SheetPortal = ({
className,
...props
}: SheetPrimitive.DialogPortalProps) => (
<SheetPrimitive.Portal className={cn(className)} {...props} />
)
SheetPortal.displayName = SheetPrimitive.Portal.displayName

const SheetOverlay = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Overlay
className={cn(
"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className
)}
{...props}
ref={ref}
/>
))
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName

const sheetVariants = cva(
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
{
variants: {
side: {
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
bottom:
"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
right:
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
},
},
defaultVariants: {
side: "right",
},
}
)

interface SheetContentProps
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
VariantProps<typeof sheetVariants> {}

const SheetContent = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Content>,
SheetContentProps
>(({ side = "right", className, children, ...props }, ref) => (
<SheetPortal>
<SheetOverlay />
<SheetPrimitive.Content
ref={ref}
className={cn(sheetVariants({ side }), className)}
{...props}
>
{children}
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
</SheetPrimitive.Content>
</SheetPortal>
))
SheetContent.displayName = SheetPrimitive.Content.displayName

const SheetHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className
)}
{...props}
/>
)
SheetHeader.displayName = "SheetHeader"

const SheetFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className
)}
{...props}
/>
)
SheetFooter.displayName = "SheetFooter"

const SheetTitle = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Title
ref={ref}
className={cn("text-lg font-semibold text-foreground", className)}
{...props}
/>
))
SheetTitle.displayName = SheetPrimitive.Title.displayName

const SheetDescription = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
SheetDescription.displayName = SheetPrimitive.Description.displayName

export {
Sheet,
SheetTrigger,
SheetClose,
SheetContent,
SheetHeader,
SheetFooter,
SheetTitle,
SheetDescription,
}
Loading

0 comments on commit 2e66a35

Please sign in to comment.