diff --git a/hesabixCore/migrations/Version20241220000000.php b/hesabixCore/migrations/Version20241220000000.php new file mode 100644 index 0000000..3d12ad1 --- /dev/null +++ b/hesabixCore/migrations/Version20241220000000.php @@ -0,0 +1,40 @@ +addSql('ALTER TABLE chat_channel ADD member_count INT NOT NULL DEFAULT 0'); + + // Update existing channels with correct member count + $this->addSql(' + UPDATE chat_channel c + SET member_count = ( + SELECT COUNT(*) + FROM chat_channel_member m + WHERE m.channel_id = c.id AND m.is_active = 1 + ) + '); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE chat_channel DROP member_count'); + } +} \ No newline at end of file diff --git a/hesabixCore/src/Controller/ChatController.php b/hesabixCore/src/Controller/ChatController.php index f2c2300..99cd4ee 100644 --- a/hesabixCore/src/Controller/ChatController.php +++ b/hesabixCore/src/Controller/ChatController.php @@ -54,6 +54,7 @@ class ChatController extends AbstractController 'isPublic' => $channel->isPublic(), 'avatar' => $channel->getAvatar(), 'messageCount' => $channel->getMessageCount(), + 'memberCount' => $channel->getMemberCount(), 'lastMessageAt' => $channel->getLastMessageAt()?->format('Y-m-d H:i:s'), 'createdAt' => $channel->getCreatedAt()->format('Y-m-d H:i:s'), 'isAdmin' => $this->chatService->isUserAdmin($channel, $user), @@ -128,7 +129,7 @@ class ChatController extends AbstractController 'description' => $channel->getDescription(), 'isPublic' => $channel->isPublic(), 'messageCount' => $channel->getMessageCount(), - 'memberCount' => $this->chatService->getChannelStats($channel)['memberCount'], + 'memberCount' => $channel->getMemberCount(), 'lastMessageAt' => $channel->getLastMessageAt()?->format('Y-m-d H:i:s'), ]; } @@ -387,10 +388,13 @@ class ChatController extends AbstractController ], Response::HTTP_FORBIDDEN); } - $limit = (int) $request->query->get('limit', 50); + $limit = (int) $request->query->get('limit', 30); $offset = (int) $request->query->get('offset', 0); $messages = $this->chatService->getChannelMessages($channel, $limit, $offset); + + // Get total message count for pagination info + $totalMessages = $this->chatService->getChannelMessageCount($channel); $data = []; foreach ($messages as $message) { @@ -418,7 +422,13 @@ class ChatController extends AbstractController return $this->json([ 'success' => true, - 'data' => $data + 'data' => $data, + 'pagination' => [ + 'limit' => $limit, + 'offset' => $offset, + 'total' => $totalMessages, + 'hasMore' => ($offset + $limit) < $totalMessages + ] ]); } @@ -478,6 +488,11 @@ class ChatController extends AbstractController 'id' => $message->getSender()->getId(), 'fullName' => $message->getSender()->getFullName(), ], + 'quotedMessage' => $message->getQuotedMessage() ? [ + 'id' => $message->getQuotedMessage()->getId(), + 'content' => $message->getQuotedMessage()->getContent(), + 'sender' => $message->getQuotedMessage()->getSender()->getFullName(), + ] : null, ] ]); } catch (\Exception $e) { @@ -564,6 +579,44 @@ class ChatController extends AbstractController } } + #[Route('/messages/{messageId}/reactions', name: 'chat_remove_reaction', methods: ['DELETE'])] + public function removeReaction(int $messageId, Request $request): JsonResponse + { + $message = $this->messageRepository->find($messageId); + if (!$message) { + return $this->json([ + 'success' => false, + 'message' => 'پیام یافت نشد' + ], Response::HTTP_NOT_FOUND); + } + + $data = json_decode($request->getContent(), true); + + if (!isset($data['emoji']) || empty($data['emoji'])) { + return $this->json([ + 'success' => false, + 'message' => 'ایموجی الزامی است' + ], Response::HTTP_BAD_REQUEST); + } + + /** @var User $user */ + $user = $this->security->getUser(); + + $success = $this->chatService->removeReaction($message, $user, $data['emoji']); + + if ($success) { + return $this->json([ + 'success' => true, + 'message' => 'واکنش حذف شد' + ]); + } else { + return $this->json([ + 'success' => false, + 'message' => 'خطا در حذف واکنش' + ], Response::HTTP_BAD_REQUEST); + } + } + #[Route('/users/search', name: 'chat_search_users', methods: ['GET'])] public function searchUsers(Request $request): JsonResponse { diff --git a/hesabixCore/src/Entity/ChatChannel.php b/hesabixCore/src/Entity/ChatChannel.php index 75ed9aa..b42f4a2 100644 --- a/hesabixCore/src/Entity/ChatChannel.php +++ b/hesabixCore/src/Entity/ChatChannel.php @@ -52,6 +52,9 @@ class ChatChannel #[ORM\Column] private int $messageCount = 0; + #[ORM\Column] + private int $memberCount = 0; + #[ORM\Column(nullable: true)] private ?\DateTimeImmutable $lastMessageAt = null; @@ -236,6 +239,17 @@ class ChatChannel return $this; } + public function getMemberCount(): int + { + return $this->memberCount; + } + + public function setMemberCount(int $memberCount): static + { + $this->memberCount = $memberCount; + return $this; + } + public function getLastMessageAt(): ?\DateTimeImmutable { return $this->lastMessageAt; diff --git a/hesabixCore/src/Repository/ChatMessageRepository.php b/hesabixCore/src/Repository/ChatMessageRepository.php index 549ea2d..b623892 100644 --- a/hesabixCore/src/Repository/ChatMessageRepository.php +++ b/hesabixCore/src/Repository/ChatMessageRepository.php @@ -130,13 +130,28 @@ class ChatMessageRepository extends ServiceEntityRepository ->getResult(); } + /** + * Get total message count for a channel + */ + public function getChannelMessageCount(ChatChannel $channel): int + { + return $this->createQueryBuilder('m') + ->select('COUNT(m.id)') + ->where('m.channel = :channel') + ->andWhere('m.isDeleted = :isDeleted') + ->setParameter('channel', $channel) + ->setParameter('isDeleted', false) + ->getQuery() + ->getSingleScalarResult(); + } + /** * Get message statistics for a channel */ public function getChannelMessageStats(ChatChannel $channel): array { $qb = $this->createQueryBuilder('m') - ->select('COUNT(m.id) as total, COUNT(CASE WHEN m.messageType = :emoji THEN 1 END) as emoji_count') + ->select('COUNT(m.id) as total, SUM(CASE WHEN m.messageType = :emoji THEN 1 ELSE 0 END) as emoji_count') ->where('m.channel = :channel') ->andWhere('m.isDeleted = :isDeleted') ->setParameter('channel', $channel) diff --git a/hesabixCore/src/Service/ChatService.php b/hesabixCore/src/Service/ChatService.php index d37cdc6..a4c6bb0 100644 --- a/hesabixCore/src/Service/ChatService.php +++ b/hesabixCore/src/Service/ChatService.php @@ -34,6 +34,7 @@ class ChatService $channel->setDescription($description); $channel->setIsPublic($isPublic); $channel->setCreatedBy($creator); + $channel->setMemberCount(1); // Creator is the first member // Add creator as admin member $member = new ChatChannelMember(); @@ -72,6 +73,10 @@ class ChatService $member->setIsAdmin(false); $this->entityManager->persist($member); + + // Update channel member count + $channel->setMemberCount($channel->getMemberCount() + 1); + $this->entityManager->flush(); return true; @@ -88,6 +93,10 @@ class ChatService } $member->setIsActive(false); + + // Update channel member count + $channel->setMemberCount($channel->getMemberCount() - 1); + $this->entityManager->flush(); return true; @@ -120,6 +129,10 @@ class ChatService } $member->setIsActive(false); + + // Update channel member count + $channel->setMemberCount($channel->getMemberCount() - 1); + $this->entityManager->flush(); return true; @@ -258,6 +271,14 @@ class ChatService return $this->messageRepository->findChannelMessages($channel, $limit, $offset); } + /** + * Get total message count for a channel + */ + public function getChannelMessageCount(ChatChannel $channel): int + { + return $this->messageRepository->getChannelMessageCount($channel); + } + /** * Search public channels */ @@ -279,7 +300,10 @@ class ChatService */ public function getChannelStats(ChatChannel $channel): array { - return $this->channelRepository->getChannelStats($channel); + return [ + 'memberCount' => $channel->getMemberCount(), + 'messageCount' => $channel->getMessageCount() + ]; } /** diff --git a/webUI/src/views/chat/home.vue b/webUI/src/views/chat/home.vue index 9938aeb..c52ed67 100644 --- a/webUI/src/views/chat/home.vue +++ b/webUI/src/views/chat/home.vue @@ -78,7 +78,7 @@ - {{ channel.messageCount }} پیام + {{ channel.messageCount }} پیام • {{ channel.memberCount || 0 }} عضو