Skip to content

Commit

Permalink
Merge branch 'messages' into Crud-Friendlist
Browse files Browse the repository at this point in the history
  • Loading branch information
Saodus committed Dec 12, 2024
2 parents 8211a82 + 55a7fe0 commit 22df795
Show file tree
Hide file tree
Showing 4 changed files with 292 additions and 46 deletions.
115 changes: 73 additions & 42 deletions app/Http/Controllers/ChatController.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,59 +69,90 @@ public function getMessages($chatId)
}

public function storeMessage(Request $request, $chatId)
{
$request->validate([
'message' => 'required|string',
]);
{
$request->validate([
'message' => 'required|string',
]);

$chat = Chat::with('members')->find($chatId);
$chat = Chat::with('members')->find($chatId);

if (!$chat || !$chat->members->contains(auth()->id())) {
return response()->json(['error' => 'Chat not found or unauthorized.'], 404);
}
if (!$chat || !$chat->members->contains(auth()->id())) {
return response()->json(['error' => 'Chat not found or unauthorized.'], 404);
}

if ($chat->members->count() > 2) {
$blockedByAnyone = $chat->members->filter(function ($member) {
return $member->id !== auth()->id();
})->contains(function ($member) {
$friendship = Friendship::where(function ($query) use ($member) {
if ($chat->members->count() > 2) {
$blockedByAnyone = $chat->members->filter(function ($member) {
return $member->id !== auth()->id();
})->contains(function ($member) {
$friendship = Friendship::where(function ($query) use ($member) {
$query->where('user_id', auth()->id())
->where('friend_id', $member->id);
})->orWhere(function ($query) use ($member) {
$query->where('user_id', $member->id)
->where('friend_id', auth()->id());
})->first();

return $friendship && $friendship->isBlocked();
});

if ($blockedByAnyone) {
return response()->json(['error' => 'You are blocked by one of the members of this group.']);
}
} else {
$otherMember = $chat->members->firstWhere('id', '!=', auth()->id());

$friendship = Friendship::where(function ($query) use ($otherMember) {
$query->where('user_id', auth()->id())
->where('friend_id', $member->id);
})->orWhere(function ($query) use ($member) {
$query->where('user_id', $member->id)
->where('friend_id', auth()->id());
->where('friend_id', $otherMember->id);
})->orWhere(function ($query) use ($otherMember) {
$query->where('user_id', $otherMember->id)
->where('friend_id', auth()->id());
})->first();

return $friendship && $friendship->isBlocked();
});

if ($blockedByAnyone) {
return response()->json(['error' => 'You are blocked by one of the members of this group.']);
if ($friendship && $friendship->isBlocked()) {
return response()->json(['error' => 'You are blocked by this user or you blocked this user.']);
}
}
} else {
$otherMember = $chat->members->firstWhere('id', '!=', auth()->id());

$friendship = Friendship::where(function ($query) use ($otherMember) {
$query->where('user_id', auth()->id())
->where('friend_id', $otherMember->id);
})->orWhere(function ($query) use ($otherMember) {
$query->where('user_id', $otherMember->id)
->where('friend_id', auth()->id());
})->first();

if ($friendship && $friendship->isBlocked()) {
return response()->json(['error' => 'You are blocked by this user or you blocked this user.']);
}
$message = new Message();
$message->user_id = auth()->id();
$message->chat_id = $chatId;
$message->message = $request->message;
$message->save();

return response()->json(['message' => $message]);
}

$message = new Message();
$message->user_id = auth()->id();
$message->chat_id = $chatId;
$message->message = $request->message;
$message->save();
public function storeCapsule(Request $request, $chatId)
{
// Validation
$request->validate([
'file' => 'required|file|mimes:jpeg,png,jpg,gif,mp3,mp4|max:1024',
'message' => 'required|string',
]);

// Vérification de la présence du fichier
if ($request->hasFile('file') && $request->file('file')->isValid()) {
$media = $request->file('file');
$mediaName = time() . '_' . $media->getClientOriginalName();

return response()->json(['message' => $message]);
}
// Déplacer le fichier vers le répertoire public/source/media
$media->move(public_path('source/media'), $mediaName);

// Créer un nouveau message et l'enregistrer dans la base de données
$message = new Message();
$message->user_id = auth()->id();
$message->chat_id = $chatId;
$message->message = $request->message;
$message->media_url = $mediaName;

$message->save();

return response()->json(['message' => $message]);
}

return response()->json(['error' => 'Le fichier n\'a pas été envoyé ou est invalide.'], 400);
}

public function storeChat(Request $request)
{
Expand Down
108 changes: 105 additions & 3 deletions resources/views/components/messaging/chatbar.blade.php
Original file line number Diff line number Diff line change
@@ -1,13 +1,115 @@
<div class="flex bottom-0 left-0 right-0 justify-center p-4 border-t border-black">
<div class="flex w-3/4 items-center">
<button onclick="sendFile()"
<button x-data="" x-on:click.prevent="$dispatch('open-modal', 'create-file-modal')"
class="rounded-full secondary-background-app p-2 flex items-center justify-center">
<img src="{{asset('source/assets/images/add.png')}}" alt="Icone" class="h-6 w-6">
</button>
<input type="text" id="message-content" class="flex-1 secondary-background-app text-white border-none rounded-3xl p-2 ml-2 mr-2" onkeypress="if(event.key === 'Enter') { sendMessage() }">
<button onclick="sendMessage()"
class="rounded-full secondary-background-app p-2 flex items-center justify-center">
<button onclick="sendMessage()" class="rounded-full secondary-background-app p-2 flex items-center justify-center">
<img src="{{asset('source/assets/images/send.png')}}" alt="Icone" class="h-6 w-6">
</button>
<x-modal name="create-file-modal" focusable>
<form method="post" class="p-6" x-data="capsuleForm()" id="create-file-modal-form" @submit.prevent="submitForm">
@csrf
<input type="hidden" id="discussion-id" name="discussion_id" value="CHAT_ID">
<h3 class="text-lg font-semibold text-gray-300 mb-5">Créer une capsule</h3>
<!-- Champ pour le fichier de la capsule -->
<div class="flex items-center justify-center bg-gray-800">
<div class="border-dashed border-4 border-gray-500 rounded-lg p-8 bg-gray-900 hover:bg-gray-700 transition duration-300" ondrop="handleDrop(event)" ondragover="handleDragOver(event)">
<label for="file" class="flex flex-col items-center justify-center cursor-pointer">
<div id="file-info">
<p class="text-gray-300 font-medium">Glissez et déposez votre fichier ici ou</p>
<p class="text-blue-400 underline">cliquez pour sélectionner un fichier</p>
</div>
</label>
<input id="file" name="file" type="file" class="hidden" onchange="updateFileName()">
</div>
</div>
<script>
function updateFileName() {
const fileInput = document.getElementById('file');
const fileInfo = document.getElementById('file-info');
if (fileInput.files.length > 0) {
const fileName = fileInput.files[0].name;
fileInfo.innerHTML = `<p class='text-green-400 font-medium'>Fichier sélectionné : ${fileName}</p>`;
}
}
function handleDragOver(event) {
event.preventDefault();
}
function handleDrop(event) {
event.preventDefault();
const fileInput = document.getElementById('file');
const fileInfo = document.getElementById('file-info');
if (event.dataTransfer.files.length > 0) {
const file = event.dataTransfer.files[0];
fileInput.files = event.dataTransfer.files;
fileInfo.innerHTML = `<p class='text-green-400 font-medium'>Fichier sélectionné : ${file.name}</p>`;
}
}
</script>
<!-- Champ pour le message de la capsule -->
<div class="mb-4">
<x-input-label for="message" value="Message" />
<x-text-input id="message" name="message" type="text" class="block w-full mt-1"
x-model="chatMessage" />
</div>
<!-- Boutons d'action -->
<div class="mt-6 flex justify-end">
<x-secondary-button x-on:click="$dispatch('close')">
Annuler
</x-secondary-button>
<x-primary-button class="ml-3" x-on:click.prevent="submitForm">
Envoyer la capsule
</x-primary-button>
</div>
</form>
</x-modal>
</div>
</div>

<script>
function capsuleForm() {
return {
chatMessage: '',
submitForm() {
event.preventDefault();
console.log('Soumettre le formulaire');
// Récupérer dynamiquement l'ID de la discussion depuis le champ caché
const discussionId = document.getElementById('discussion-id').value;
// Créer l'objet FormData avec les données du formulaire
const formData = new FormData(document.getElementById('create-file-modal-form'));
// Effectuer la requête AJAX avec `fetch`
fetch(`/chat/${discussionId}/capsule`, {
method: 'POST',
body: formData,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
})
.then(response => response.json())
.then(data => {
if (data.message.id) {
// Fermer le modal ou réinitialiser le formulaire
this.chatMessage = '';
$dispatch('close');
} else {
console.log(data)
alert('Erreur lors de l\'envoi de la capsule');
}
})
.catch(error => {
alert('Erreur lors de l\'envoi');
console.error(error);
});
}
};
}
</script>
114 changes: 113 additions & 1 deletion resources/views/dashboard.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,118 @@ function loadChat(chatId, discussionName, discussionPicture, newOpening = true)
if (currentChatId !== chatId) {
allMessages = [];
messagesContainer.innerHTML = '';
// Vérifier si la discussion est déjà chargée
if (currentChatId !== chatId) {
// Réinitialiser la liste de tout les messages
allMessages = [];
document.getElementById('messages').innerHTML = '';
// Récupérer le champ contenant l'id pour la création de capsule via son id et mettre à jour l'action
const hiddenInput = document.getElementById('discussion-id');
if (hiddenInput) hiddenInput.value = chatId;
}
// Mettre à jour l'ID de la discussion actuelle
currentChatId = chatId;
// Mettre à jour le titre du header si nécessaire
if (newOpening) {
const headerTitle = document.querySelector('.headerTitle');
if (headerTitle) headerTitle.textContent = discussionName;
const headerImage = document.querySelector('.headerImage');
if(headerImage) headerImage.src = discussionPicture;
}
fetch(`/chat/${chatId}/messages`, {
method: 'GET',
headers: {
'X-Requested-With': 'XMLHttpRequest',
'X-CSRF-TOKEN': '{{ csrf_token() }}'
}
})
.then(response => response.json())
.then(data => {
let newMessages = [];
// Si la liste de tout les messages correspond à la liste actuelle
if (JSON.stringify(allMessages) === JSON.stringify(data.messages)) {
return;
} else if (allMessages.length === 0) {
// Si la liste de tout les messages est vide
newMessages = data.messages;
} else {
// Récupérer la liste des messages qui ne sont pas déjà affichés
newMessages = data.messages.filter(message => !allMessages.some(m => m.id === message.id));
}
// Récupérer la position dans le scroll et vérifier si on est tout en bas
// Utile pour savoir si on doit défiler jusqu'en bas après l'ajout des nouveaux messages ou si l'utilisateur est entrain de consulter des anciens messages
const isAtBottom = messagesContainer.scrollHeight - messagesContainer.scrollTop === messagesContainer.clientHeight;
// Parcourir les messages et les ajouter
newMessages.forEach(message => {
const isCurrentUser = message.user_id === {{ auth()->id() }};
const messageElement = document.createElement('div');
messageElement.className = `flex ${isCurrentUser ? 'justify-end' : 'justify-start'} mb-2`;
messageElement.innerHTML = `
<!-- Encadré bleu avec le user_id en première ligne -->
<p class="max-w-[45%] ${isCurrentUser ? 'secondary-background-app rounded-tl-lg' : 'tertiary-background-app rounded-tr-lg'} text-white p-2 rounded-bl-lg rounded-br-lg">
<!-- Affichage du user_id dans l'encadré bleu -->
<span class="text-xs text-white block mb-1 font-bold">${message.user.name}</span>
${message.message}
</p>`;
// Gestion des médias
if (message.media_url) {
let mediaElement =
`
<div class="max-w-[45%] ${isCurrentUser ? 'secondary-background-app rounded-tl-lg' : 'tertiary-background-app rounded-tr-lg'} text-white p-2 rounded-bl-lg rounded-br-lg">
<span class="text-xs text-white block mb-1 font-bold">${message.user.name}</span>`;
if (message.media_url.endsWith('.mp4')) {
mediaElement += `
<video controls preload="none" class="w-full" poster="{{ asset('source/assets/images/') }}/video.png">
<source src="{{ asset('source/media/') }}/${message.media_url}" type="video/mp4">
</video>`;
} else if (message.media_url.endsWith('.mp3')) {
mediaElement += `
<audio preload="none" controls class="w-full">
<source src="{{ asset('source/media/') }}/${message.media_url}" type="audio/mpeg">
Your browser does not support the audio element.
</audio>`;
} else {
mediaElement += `
<img src="{{ asset('source/media/') }}/${message.media_url}" class="w-full rounded-lg">`;
}
mediaElement += `
<p class="mt-3">
${message.message}
</p>
</div>`;
messageElement.innerHTML = mediaElement;
}
messagesContainer.appendChild(messageElement);
});
// Mettre à jour la liste de tout les messages
allMessages = data.messages;
// Attendre que tout les médias soient chargés avant de faire défiler
const mediaElements = document.querySelectorAll('img, video');
mediaElements.forEach(mediaElement => {
mediaElement.addEventListener('load', () => {
if (isAtBottom) {
scrollToBottom()
};
});
});
// Faire défiler jusqu'en bas (utile si il y a pas de médias)
if (isAtBottom) {
scrollToBottom()
};
})
.catch(error => console.error('Erreur:', error))
}
currentChatId = chatId;
Expand Down Expand Up @@ -172,4 +284,4 @@ function scrollToBottom() {
}
startAutoRefresh();
</script>
</script>
1 change: 1 addition & 0 deletions routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
Route::get('/dashboard', [ChatController::class, 'index'])->name('dashboard');
Route::get('/chat/{discussion}/messages', [ChatController::class, 'getMessages']);
Route::post('/chat/{discussion}/messages', [ChatController::class, 'storeMessage']);
Route::post('/chat/{discussion}/capsule', [ChatController::class, 'storeCapsule']);
Route::post('/chats', [ChatController::class, 'storeChat'])->name('chats.store');
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
Expand Down

0 comments on commit 22df795

Please sign in to comment.