Skip to content

Commit

Permalink
message screen, seen by, images showing - done
Browse files Browse the repository at this point in the history
  • Loading branch information
17coincooker committed Sep 16, 2023
1 parent bcd486e commit 4e1285f
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 3 deletions.
66 changes: 66 additions & 0 deletions app/api/conversations/[conversationId]/seen/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import getCurrentUser from '@/app/actions/getCurrentUser';
import { NextResponse } from 'next/server';
import prisma from '@/app/libs/prismadb';

interface IParams {
conversationId?: string;
}

export async function POST(request: Request, { params }: { params: IParams }) {
try {
const currentUser = await getCurrentUser();
const { conversationId } = params;

if (!currentUser?.id || !currentUser?.email) {
return new NextResponse('Unauthorized', { status: 401 });
}
// find the existing conversation
const conversation = await prisma.conversation.findUnique({
where: {
id: conversationId,
},
include: {
messages: {
include: {
seen: true,
},
},
users: true,
},
});

if (!conversation) {
return new NextResponse('Invalid ID', { status: 400 });
}

// find the last message that was sent by the other user
const lastMessage = conversation.messages[conversation.messages.length - 1];

if (!lastMessage) {
return NextResponse.json(conversation);
}

// Update the seen status of the last message
const updatedMessage = await prisma.message.update({
where: {
id: lastMessage.id,
},
include: {
seen: true,
sender: true,
},
data: {
seen: {
connect: {
id: currentUser.id,
},
},
},
});

return NextResponse.json(updatedMessage);
} catch (error: any) {
console.log(error, 'ERROR_MESSAGES_SEEN');
return new NextResponse('Internal Server Error', { status: 500 });
}
}
35 changes: 33 additions & 2 deletions app/conversations/[conversationId]/components/Body.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,37 @@
'use client';

const Body = () => {
return <div className="flex-1 overflow-y-auto">Body</div>;
import { useState, useRef, useEffect } from 'react';
import { FullMessageTypes } from '@/app/types';
import useConversation from '@/app/hooks/useConversation';
import MessageBox from './MessageBox';
import axios from 'axios';

interface BodyProps {
initialMessages: FullMessageTypes[];
}

const Body: React.FC<BodyProps> = ({ initialMessages }) => {
const [messages, setMessages] = useState(initialMessages);
const bottomRef = useRef<HTMLDivElement>(null);

const { conversationId } = useConversation();

useEffect(() => {
axios.post(`/api/conversations/${conversationId}/seen`);
}, [conversationId]);

return (
<div className="flex-1 overflow-y-auto">
{messages.map((message, i) => (
<MessageBox
isLast={i === messages.length - 1}
key={message.id}
data={message}
/>
))}

<div ref={bottomRef} className="pt-24" />
</div>
);
};
export default Body;
76 changes: 76 additions & 0 deletions app/conversations/[conversationId]/components/MessageBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
'use client';

import Avatar from '@/app/components/Avatar';
import { FullMessageTypes } from '@/app/types';
import clsx from 'clsx';
import { useSession } from 'next-auth/react';
import { format } from 'date-fns';
import Image from 'next/image';

interface MessageBoxProps {
isLast: boolean;
data: FullMessageTypes;
}

const MessageBox: React.FC<MessageBoxProps> = ({ isLast, data }) => {
const session = useSession();

const isOwn = session?.data?.user?.email === data.sender?.email;
const seenList = (data.seen || [])
.filter((user) => user.email !== session?.data?.user?.email)
.map((user) => user.name)
.join(', ');

// dynamic classes
const container = clsx('flex gap-3 p-4', isOwn && 'justify-end');
const avatar = clsx(isOwn && 'order-2');
const body = clsx('flex flex-col gap-2', isOwn && 'items-end');
const message = clsx(
'text-sm w-fit overflow-hidden',
isOwn ? 'bg-sky-500 text-white' : 'bg-gray-100',
data.image ? 'rounded-md p-0' : 'rounded-full py-2 px-3'
);

return (
<div className={container}>
<div className={avatar}>
<Avatar user={data.sender} />
</div>

<div className={body}>
<div className="flex items-center gap-1">
<div className="text-sm text-gray-500">
{data.sender?.name || data.sender?.email}
</div>
<div className="text-xs text-gray-400">
{format(new Date(data.createdAt), 'p')}
</div>
</div>

<div className={message}>
{data.image ? (
<Image
src={data.image}
width={288}
height={288}
alt="image"
className="object-cover cursor-pointer hover:scale-110 transition translate"
/>
) : (
<div>{data.body}</div>
)}
</div>

{
// show seen list if last message
isLast && isOwn && seenList && (
<div className="text-xs font-light text-gray-500">
Seen by {seenList}
</div>
)
}
</div>
</div>
);
};
export default MessageBox;
2 changes: 1 addition & 1 deletion app/conversations/[conversationId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const ConversationId = async ({ params }: { params: IParams }) => {
<div className="lg:pl-80 h-full">
<div className="h-full flex flex-col">
<Header conversation={conversation} />
<Body />
<Body initialMessages={messages} />
<Form />
</div>
</div>
Expand Down

0 comments on commit 4e1285f

Please sign in to comment.