Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added app/Chat/chat.php
Empty file.
Empty file added app/Chat/chat_api/config.php
Empty file.
Empty file.
Empty file.
29 changes: 29 additions & 0 deletions app/Http/Controllers/ChatController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Mensagem;

class ChatController extends Controller
{
public function index($projeto_id)
{
return view('chat', compact('projeto_id'));
}

public function fetchMessages($projeto_id)
{
return Mensagem::where('projeto_id', $projeto_id)->get();
}

public function sendMessage(Request $request, $projeto_id)
{
return Mensagem::create([
'projeto_id' => $projeto_id,
'usuario' => $request->usuario,
'mensagem' => $request->mensagem,
]);
}

}
16 changes: 16 additions & 0 deletions app/Models/Mensagem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Mensagem extends Model
{
use HasFactory;

protected $fillable = ['projeto_id', 'usuario', 'mensagem'];


protected $table = 'mensagens';
}
30 changes: 30 additions & 0 deletions database/migrations/2025_05_07_162656_create_mensagens_table.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('mensagens', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('projeto_id');
$table->string('usuario');
$table->text('mensagem');
$table->timestamps();
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('mensagens');
}
};
34 changes: 19 additions & 15 deletions database/seeders/DatabaseSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public function run()
$this->call(BasesSearchSeeder::class);
$this->call(PermissionSeeder::class);

DB::table('levels')->insert([
DB::table('levels')->insert([
['id_level' => 1, 'level' => 'Administrator'],
['id_level' => 2, 'level' => 'Viewer'],
['id_level' => 3, 'level' => 'Researcher'],
Expand All @@ -31,21 +31,26 @@ public function run()
['id_module' => 4, 'description' => 'Export'],
['id_module' => 5, 'description' => 'Super Administrator'],
]);

// Refatoração e adição de linguagens extras:
DB::table('language')->insert([
'description' => 'Portuguese',
]);
DB::table('language')->insert([
'description' => 'English',
]);
DB::table('language')->insert([
'description' => 'Spanish',
]);
DB::table('language')->insert([
'description' => 'French',
]);
DB::table('language')->insert([
'description' => 'Russian',
['description' => 'Portuguese'],
['description' => 'English'],
['description' => 'Spanish'],
['description' => 'French'],
['description' => 'Russian'],
['description' => 'German'],
['description' => 'Chinese'],
['description' => 'Italian'],
['description' => 'Japanese'],
['description' => 'Arabic'],
['description' => 'Dutch'],
['description' => 'Korean'],
['description' => 'Hindi'],
['description' => 'Greek'],
['description' => 'Turkish'],
]);

DB::table('study_type')->insert([
['id_study_type' => 1, 'description' => 'Book'],
['id_study_type' => 2, 'description' => 'Thesis'],
Expand Down Expand Up @@ -89,6 +94,5 @@ public function run()
['description' => 'Unclassified'],
['description' => 'Removed'],
]);

}
}
50 changes: 50 additions & 0 deletions resources/views/chat.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="pt">
<head>
<meta charset="UTF-8">
<title>Chat Projeto {{ $projeto_id }}</title>
<meta name="csrf-token" content="{{ csrf_token() }}">
</head>
<body>
<div id="chat-box" style="border:1px solid #ccc; height:300px; overflow:auto;"></div>

<input type="text" id="usuario" placeholder="Seu nome"><br>
<textarea id="mensagem" placeholder="Digite a mensagem"></textarea><br>
<button onclick="enviar()">Enviar</button>

<script>
const projetoId = "{{ $projeto_id }}";

async function carregarMensagens() {
const res = await fetch(`/chat/${projetoId}/messages`);
const data = await res.json();
let chatBox = document.getElementById('chat-box');
chatBox.innerHTML = '';
data.forEach(msg => {
chatBox.innerHTML += `<div><strong>${msg.usuario}</strong>: ${msg.mensagem} (${msg.created_at})</div>`;
});
chatBox.scrollTop = chatBox.scrollHeight;
}

async function enviar() {
const usuario = document.getElementById('usuario').value;
const mensagem = document.getElementById('mensagem').value;

await fetch(`/chat/${projetoId}/messages`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
},
body: JSON.stringify({ usuario, mensagem })
});

document.getElementById('mensagem').value = '';
carregarMensagens();
}

carregarMensagens();
setInterval(carregarMensagens, 3000);
</script>
</body>
</html>
85 changes: 85 additions & 0 deletions resources/views/components/chat.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<div id="chat-container" style="position:fixed; bottom:0; right:15px; width:300px; z-index:9999;">
<div id="chat-header" style="background:#007bff;color:#fff;padding:8px;cursor:pointer;">
Chat do Projeto
<span id="chat-notif" style="float:right;background:red;padding:2px 5px;border-radius:10px;display:none;">!</span>
</div>
<div id="chat-body" style="border:1px solid #ccc;background:#fff;height:250px;overflow:auto;display:none;padding:10px;">
<div id="chat-messages" style="height:150px; overflow-y: auto;"></div>
<textarea id="chat-input" placeholder="Digite sua mensagem..." style="width:100%;height:50px;"></textarea>
<button id="chat-send" style="width:100%;margin-top:5px;">Enviar</button>
</div>
</div>

<script>
document.addEventListener("DOMContentLoaded", function() {
let chatOpen = false;

const chatHeader = document.getElementById('chat-header');
const chatBody = document.getElementById('chat-body');
const chatNotif = document.getElementById('chat-notif');
const chatSend = document.getElementById('chat-send');
const chatInput = document.getElementById('chat-input');
const chatMessages = document.getElementById('chat-messages');

const projetoId = {{ $projeto_id ?? 1 }};
const usuarioLogado = @json(Auth::user()->name);

chatHeader.addEventListener('click', function() {
console.log("Clique detectado");
chatOpen = !chatOpen;
chatBody.style.display = chatOpen ? 'block' : 'none';
if (chatOpen) {
chatNotif.style.display = 'none';
carregarMensagens();
}
});

function carregarMensagens() {
fetch(`/chat/${projetoId}/messages`)
.then(resp => resp.json())
.then(data => {
chatMessages.innerHTML = '';
data.forEach(msg => {
chatMessages.innerHTML += `<div><strong>${msg.usuario}</strong>: ${msg.mensagem}</div>`;
});
chatMessages.scrollTop = chatMessages.scrollHeight;
});
}

chatSend.addEventListener('click', function() {
const mensagem = chatInput.value.trim();
if (!mensagem) return;

fetch(`/chat/${projetoId}/messages`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
body: JSON.stringify({
usuario: usuarioLogado,
mensagem: mensagem
})
}).then(() => {
chatInput.value = '';
carregarMensagens();
});
});

carregarMensagens();

setInterval(() => {
if (!chatOpen) {
fetch(`/chat/${projetoId}/messages`)
.then(resp => resp.json())
.then(data => {
if (data.length > 0) {
chatNotif.style.display = 'inline';
}
});
} else {
carregarMensagens();
}
}, 5000);
});
</script>
Loading
Loading