forked from felipe.fontana/simples-painel
Felipe Fontana
7 months ago
8 changed files with 437 additions and 31 deletions
@ -0,0 +1,147 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace App\Http\Controllers\Admin; |
||||||
|
|
||||||
|
use App\Helpers\Helper; |
||||||
|
use App\Http\Controllers\Controller; |
||||||
|
use App\Models\QuickMessage; |
||||||
|
use App\Models\NumberChannel; |
||||||
|
use Illuminate\Http\Request; |
||||||
|
use Illuminate\Support\Facades\Gate; |
||||||
|
use Illuminate\Support\Facades\Validator; |
||||||
|
|
||||||
|
class QuickMessageController extends Controller |
||||||
|
{ |
||||||
|
public function __construct( |
||||||
|
protected QuickMessage $quickMessageRepository, |
||||||
|
protected NumberChannel $numberChannelRepository, |
||||||
|
) { |
||||||
|
} |
||||||
|
|
||||||
|
public function index(Request $request) |
||||||
|
{ |
||||||
|
$user = auth()->user(); |
||||||
|
if(Gate::forUser($user)->denies('show_quick_messages')){ |
||||||
|
abort(404); |
||||||
|
} |
||||||
|
|
||||||
|
$search = $request->channel; |
||||||
|
|
||||||
|
$id_empresa = Helper::getIdEmpresa(); |
||||||
|
$channels = $this->numberChannelRepository->list(['id_empresa' => $id_empresa]); |
||||||
|
$quickMessages = $this->quickMessageRepository->list(['id_empresa' => $id_empresa, 'id_number' => $search]); |
||||||
|
|
||||||
|
return view('admin.cadastros.quickMessage', compact('quickMessages', 'channels', 'search')); |
||||||
|
} |
||||||
|
|
||||||
|
public function store(Request $request) |
||||||
|
{ |
||||||
|
$user = auth()->user(); |
||||||
|
if(Gate::forUser($user)->denies('store_quick_messages')){ |
||||||
|
abort(404); |
||||||
|
} |
||||||
|
|
||||||
|
$validator = Validator::make($request->all(), [ |
||||||
|
'channel' => 'required', |
||||||
|
'atalho' => [ |
||||||
|
'required', |
||||||
|
function ($attribute, $value, $fail) { |
||||||
|
if ($value[0] != '@') { |
||||||
|
$fail("É necessário que o atalho começe com @."); |
||||||
|
} |
||||||
|
}, |
||||||
|
], |
||||||
|
'texto' => 'required', |
||||||
|
], [ |
||||||
|
'required' => 'É preciso informar o campo :attribute.' |
||||||
|
]); |
||||||
|
|
||||||
|
if ($validator->fails()) { |
||||||
|
return redirect()->back()->with('error', $validator->errors()->first()); |
||||||
|
} |
||||||
|
|
||||||
|
QuickMessage::create([ |
||||||
|
'atalho' => $request->atalho, |
||||||
|
'texto' => $request->texto, |
||||||
|
'id_number' => $request->channel |
||||||
|
]); |
||||||
|
|
||||||
|
return redirect('quick_messages'); |
||||||
|
} |
||||||
|
|
||||||
|
public function edit($id) |
||||||
|
{ |
||||||
|
$user = auth()->user(); |
||||||
|
if(Gate::forUser($user)->denies('update_quick_messages')){ |
||||||
|
abort(404); |
||||||
|
} |
||||||
|
|
||||||
|
if (empty($id)) { |
||||||
|
return redirect('quick_messages'); |
||||||
|
} |
||||||
|
|
||||||
|
$quickMessage = QuickMessage::find($id); |
||||||
|
$id_empresa = Helper::getIdEmpresa(); |
||||||
|
$channels = $this->numberChannelRepository->list(['id_empresa' => $id_empresa]); |
||||||
|
|
||||||
|
$response = [ |
||||||
|
'data' => [ |
||||||
|
'status' => true, |
||||||
|
'quickMessage' => $quickMessage, |
||||||
|
'channels' => $channels, |
||||||
|
], |
||||||
|
|
||||||
|
]; |
||||||
|
|
||||||
|
return response()->json($response); |
||||||
|
} |
||||||
|
|
||||||
|
public function update(Request $request, $id) |
||||||
|
{ |
||||||
|
$user = auth()->user(); |
||||||
|
if(Gate::forUser($user)->denies('update_quick_messages')){ |
||||||
|
abort(404); |
||||||
|
} |
||||||
|
|
||||||
|
$validator = Validator::make($request->all(), [ |
||||||
|
'channel' => 'required', |
||||||
|
'atalho' => [ |
||||||
|
'required', |
||||||
|
function ($attribute, $value, $fail) { |
||||||
|
if ($value[0] != '@') { |
||||||
|
$fail("É necessário que o atalho começe com @."); |
||||||
|
} |
||||||
|
}, |
||||||
|
], |
||||||
|
'texto' => 'required', |
||||||
|
], [ |
||||||
|
'required' => 'É preciso informar o campo :attribute.' |
||||||
|
]); |
||||||
|
|
||||||
|
if ($validator->fails()) { |
||||||
|
return redirect()->back()->with('error', $validator->errors()->first()); |
||||||
|
} |
||||||
|
|
||||||
|
QuickMessage::where("id", $id) |
||||||
|
->update([ |
||||||
|
'atalho' => $request->atalho, |
||||||
|
'texto' => $request->texto, |
||||||
|
'id_number' => $request->channel |
||||||
|
]); |
||||||
|
|
||||||
|
return redirect('quick_messages')->with('status', 'atualizado com sucesso'); |
||||||
|
} |
||||||
|
|
||||||
|
public function destroy($id) |
||||||
|
{ |
||||||
|
$user = auth()->user(); |
||||||
|
if(Gate::forUser($user)->denies('destroy_quick_messages')){ |
||||||
|
abort(404); |
||||||
|
} |
||||||
|
|
||||||
|
QuickMessage::where("id", $id) |
||||||
|
->delete(); |
||||||
|
|
||||||
|
return redirect('quick_messages')->with('status', 'deletado com sucesso'); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,38 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace App\Models; |
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||||
|
use Illuminate\Database\Eloquent\Model; |
||||||
|
use Illuminate\Support\Facades\DB; |
||||||
|
|
||||||
|
class QuickMessage extends Model |
||||||
|
{ |
||||||
|
use HasFactory; |
||||||
|
public $timestamps = false; |
||||||
|
protected $table = "quick_message"; |
||||||
|
|
||||||
|
protected $fillable = [ |
||||||
|
'atalho', |
||||||
|
'texto', |
||||||
|
'id_number', |
||||||
|
'data_reg' |
||||||
|
]; |
||||||
|
|
||||||
|
public function list(array $params) |
||||||
|
{ |
||||||
|
$messages = DB::table('quick_message as qm') |
||||||
|
->join('number_channel as nc', 'qm.id_number', '=', 'nc.id') |
||||||
|
->select('qm.*'); |
||||||
|
|
||||||
|
if(isset($params['id_empresa'])){ |
||||||
|
$messages->where('nc.id_empresa', $params['id_empresa']); |
||||||
|
} |
||||||
|
|
||||||
|
if(isset($params['id_number'])){ |
||||||
|
$messages->where('qm.id_number', $params['id_number']); |
||||||
|
} |
||||||
|
|
||||||
|
return $messages->get(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,83 @@ |
|||||||
|
<x-app-layout> |
||||||
|
<div class="py-8 px-8"> |
||||||
|
@if(session('status')) |
||||||
|
<div class="w-full p-5 bg-blue-600 mb-5 text-white rounded uppercase font-bold text-lg"> |
||||||
|
{{session('status')}} |
||||||
|
</div> |
||||||
|
@endif |
||||||
|
|
||||||
|
@if(session('error')) |
||||||
|
<div class="w-full p-5 bg-red-600 mb-5 text-white rounded uppercase font-bold text-lg"> |
||||||
|
{{session('error')}} |
||||||
|
</div> |
||||||
|
@endif |
||||||
|
<div class="header flex flex-col items-center gap-4 mt-2 mb-8"> |
||||||
|
<div class="flex justify-between items-center w-full mb-5"> |
||||||
|
<h1 class=" text-gray-900 dark:text-gray-100 text-3xl font-bold text-center"> |
||||||
|
Mensagens Rápidas |
||||||
|
</h1> |
||||||
|
@can('store_quick_messages') |
||||||
|
<button class="bg-blue-500 hover:bg-opacity-90 transition-all text-white py-2 px-6 rounded text-base overflow-hidden" @click="modal = !modal" type="button">Cadastrar Mensagens</button> |
||||||
|
@endcan |
||||||
|
</div> |
||||||
|
<form action="{{route('quick_messages.index')}}" method="GET" class="flex w-full gap-3 flex-col lg:flex-row "> |
||||||
|
<div class="flex-1 flex flex-col gap-1"> |
||||||
|
<label class="text-gray-900 dark:text-gray-100" >Canal: </label> |
||||||
|
<select class="w-full dark:bg-gray-800 placeholder:text-gray-800 dark:placeholder:text-gray-100 dark:text-gray-100" id="channel" name="channel" style="width: 300px;"> |
||||||
|
<option value="">-----------------</option> |
||||||
|
@foreach($channels as $channel) |
||||||
|
<option value="{{ $channel->id}}" {{ !empty($search) && ($channel->id == $search) ? 'selected' : '' }}> |
||||||
|
{{ $channel->title }} |
||||||
|
</option> |
||||||
|
@endforeach |
||||||
|
</select> |
||||||
|
</div> |
||||||
|
<div class="flex-1 flex flex-col gap-1" style="background-color: transparent; margin-top: 25px;"> |
||||||
|
<button class="lg:ml-auto ml-0 bg-blue-900 hover:bg-opacity-90 transition-all text-white py-2 px-6 rounded text-lg overflow-hidden">Pesquisar</button> |
||||||
|
</div> |
||||||
|
</form> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="body mt-4 overflow-auto rounded-lg shadow"> |
||||||
|
<table class="w-full"> |
||||||
|
<thead class="bg-gray-50 dark:bg-gray-700 dark:text-gray-100"> |
||||||
|
<tr> |
||||||
|
<th class="p-3 text-sm font-semibold tracking-wide text-left ">ID</th> |
||||||
|
<th class="p-3 text-sm font-semibold tracking-wide text-left">Atalho</th> |
||||||
|
<th class="p-3 text-sm font-semibold tracking-wide text-left">Texto</th> |
||||||
|
<th class="p-3 text-sm font-semibold tracking-wide text-left">Canal</th> |
||||||
|
<th class="p-3 text-sm font-semibold tracking-wide text-left">Ações</th> |
||||||
|
</tr> |
||||||
|
</thead> |
||||||
|
<tbody> |
||||||
|
@foreach($quickMessages as $quickMessage) |
||||||
|
<tr class="bg-white dark:bg-gray-800 dark:border-gray-600 border-b-2"> |
||||||
|
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{$quickMessage->id}}</td> |
||||||
|
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{$quickMessage->atalho}}</td> |
||||||
|
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{$quickMessage->texto}}</td> |
||||||
|
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{$quickMessage->id_number}}</td> |
||||||
|
<td class="p-3 text-sm font-bold flex-wrap w-32"> |
||||||
|
@can('update_quick_messages') |
||||||
|
<button class="bg-blue-600 text-white p-2 rounded text-lg w-full mb-2" title="editar mensagem" onclick="atualizaQuickMessage(<?= $quickMessage->id ?>)"><i class="fas fa-edit"></i></button>
|
||||||
|
@endcan |
||||||
|
@can('destroy_quick_messages') |
||||||
|
<form method="POST" action="{{ route('quick_messages.destroy', ['quick_message' => $quickMessage->id]) }}" class="w-full flex" title="desativar mensagem" onclick="javascript: if(!confirm('Deseja deletar esses dados?')) return false;"> |
||||||
|
@csrf |
||||||
|
@method('delete') |
||||||
|
<button class="bg-red-600 text-white p-2 rounded text-lg w-full"> |
||||||
|
<i class="fas fa-trash"></i> |
||||||
|
</button> |
||||||
|
</form> |
||||||
|
@endcan |
||||||
|
</td> |
||||||
|
</tr> |
||||||
|
@endforeach |
||||||
|
</tbody> |
||||||
|
|
||||||
|
</table> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<x-modal.insert.modalQuickMessage :channels="$channels"></x-modalQuickMessage> |
||||||
|
<x-modal.edit.modalEditQuickMessage :channels="$channels"></x-modalEditQuickMessage> |
||||||
|
</x-app-layout> |
@ -0,0 +1,80 @@ |
|||||||
|
<!-- Main modal --> |
||||||
|
<div class="fixed z-50 hidden p-4 bg-gray-900 bg-opacity-60 h-full w-full modal-edit"> |
||||||
|
<div class="fixed w-full max-w-2xl md:h-auto top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%] "> |
||||||
|
<!-- Modal content --> |
||||||
|
<form method="POST" action="" class="relative bg-white rounded-lg shadow dark:bg-gray-700" > |
||||||
|
@method('PUT') |
||||||
|
@csrf |
||||||
|
<!-- Modal header --> |
||||||
|
<div class="flex items-start justify-between border-b rounded-t dark:border-gray-600 px-3 py-4"> |
||||||
|
<h3 class="text-xl font-semibold text-gray-900 dark:text-white pl-3"> |
||||||
|
Atualizar Resposta Rápida |
||||||
|
</h3> |
||||||
|
<button type="button" class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-xl ml-auto inline-flex items-center dark:hover:bg-gray-600 dark:hover:text-white" onclick="fecharModal()"> |
||||||
|
<i class="fas fa-times"></i> |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
<!-- Modal body --> |
||||||
|
<div class="p-6 space-y-6"> |
||||||
|
<div class="flex flex-col gap-3"> |
||||||
|
<p class="dark:text-gray-100"><strong>Mensagem</strong>: No campo abaixo, utilize palavras-chave reservadas para servirem de atalho para respostas rápidas. Use a anotação @ seguida do texto do atalho.</p> |
||||||
|
|
||||||
|
<div class="flex flex-col gap-2 mt-2"> |
||||||
|
<label class="dark:text-gray-100">Atalho: </label> |
||||||
|
<input type="text" class="w-full dark:bg-gray-800 placeholder:text-gray-800 dark:placeholder:text-gray-100 dark:text-gray-100" placeholder="Digite o atalho: " name="atalho"> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="flex flex-col gap-2 mt-2"> |
||||||
|
<label class="dark:text-gray-100">Resposta: </label> |
||||||
|
<textarea rows="3" class="w-full dark:bg-gray-800 placeholder:text-gray-800 dark:placeholder:text-gray-100 dark:text-gray-100" placeholder="Digite o texto da resposta: " name="texto"></textarea> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="flex flex-col gap-2 mt-2"> |
||||||
|
<label class="dark:text-gray-100">Canal:</label> |
||||||
|
<select name="channel" class="w-full dark:bg-gray-800 placeholder:text-gray-800 dark:placeholder:text-gray-100 dark:text-gray-100 container-select"> |
||||||
|
</select> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<!-- Modal footer --> |
||||||
|
<div class="flex items-center p-6 space-x-2 border-t border-gray-200 rounded-b dark:border-gray-600"> |
||||||
|
<button type="submit" class="bg-blue-500 hover:bg-opacity-90 transition-all text-white py-2 px-6 rounded text-lg">Atualizar</button> |
||||||
|
|
||||||
|
</div> |
||||||
|
</form> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<script> |
||||||
|
function atualizaQuickMessage(id) { |
||||||
|
$.ajax({ |
||||||
|
type: "get", |
||||||
|
url: `quick_messages/${id}/edit`, |
||||||
|
success: function({ |
||||||
|
data |
||||||
|
}) { |
||||||
|
const systemMessageData = data.quickMessage; |
||||||
|
const channels = data.channels; |
||||||
|
const modal = document.querySelector('.modal-edit'); |
||||||
|
|
||||||
|
modal.style.display = 'block'; |
||||||
|
modal.querySelector('form').action = `/quick_messages/${id}`; |
||||||
|
modal.querySelector("input[name='atalho']").value = systemMessageData.atalho; |
||||||
|
modal.querySelector("textarea[name='texto']").value = systemMessageData.texto; |
||||||
|
|
||||||
|
const containerSelect = modal.querySelector(".container-select"); |
||||||
|
containerSelect.innerHTML = ''; |
||||||
|
|
||||||
|
channels.forEach(channel => { |
||||||
|
if (systemMessageData.id_number == channel.id) { |
||||||
|
containerSelect.innerHTML += `<option value="${channel.id}" selected>${channel.title}</option>` |
||||||
|
} else { |
||||||
|
containerSelect.innerHTML += `<option value="${channel.id}" >${channel.title}</option>` |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
function fecharModal() { |
||||||
|
$('.modal-edit').hide(); |
||||||
|
} |
||||||
|
</script> |
@ -0,0 +1,47 @@ |
|||||||
|
<!-- Main modal --> |
||||||
|
<div class="fixed z-50 hidden p-4 bg-gray-900 bg-opacity-60 h-full w-full" :class="{'block': modal, 'hidden': !modal}"> |
||||||
|
<div class="fixed w-full max-w-2xl md:h-auto top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%]"> |
||||||
|
<!-- Modal content --> |
||||||
|
<form method="POST" action="{{ route('quick_messages.store') }}" class="relative bg-white rounded-lg shadow dark:bg-gray-700" id="formSystemMessage"> |
||||||
|
@csrf |
||||||
|
<!-- Modal header --> |
||||||
|
<div class="flex items-start justify-between border-b rounded-t dark:border-gray-600 px-3 py-4"> |
||||||
|
<h3 class="text-xl font-semibold text-gray-900 dark:text-white pl-3"> |
||||||
|
Cadastrar Mensagem Rápida |
||||||
|
</h3> |
||||||
|
<button type="button" class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-xl ml-auto inline-flex items-center dark:hover:bg-gray-600 dark:hover:text-white" @click="modal = false" onclick="fecharModal()"> |
||||||
|
<i class="fas fa-times"></i> |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
<!-- Modal body --> |
||||||
|
<div class="p-6 space-y-6"> |
||||||
|
<div class="flex flex-col gap-3"> |
||||||
|
<p class="dark:text-gray-100"><strong>Mensagem</strong>: No campo abaixo, utilize palavras-chave reservadas para servirem de atalho para respostas rápidas. Use a anotação @ seguida do texto do atalho.</p> |
||||||
|
|
||||||
|
<div class="flex flex-col gap-2 mt-2"> |
||||||
|
<label class="dark:text-gray-100">Atalho: </label> |
||||||
|
<input type="text" class="w-full dark:bg-gray-800 placeholder:text-gray-800 dark:placeholder:text-gray-100 dark:text-gray-100" placeholder="Digite o atalho: " name="atalho"> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="flex flex-col gap-2 mt-2"> |
||||||
|
<label class="dark:text-gray-100">Resposta: </label> |
||||||
|
<textarea rows="3" class="w-full dark:bg-gray-800 placeholder:text-gray-800 dark:placeholder:text-gray-100 dark:text-gray-100" placeholder="Digite o texto da resposta: " name="texto"></textarea> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="flex flex-col gap-2 mt-2"> |
||||||
|
<label class="dark:text-gray-100">Canal:</label> |
||||||
|
<select name="channel" class="w-full dark:bg-gray-800 placeholder:text-gray-800 dark:placeholder:text-gray-100 dark:text-gray-100"> |
||||||
|
@foreach($channels as $channel) |
||||||
|
<option value="{{ $channel->id }}">{{$channel->title}}</option> |
||||||
|
@endforeach |
||||||
|
</select> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<!-- Modal footer --> |
||||||
|
<div class="flex items-center p-6 space-x-2 border-t border-gray-200 rounded-b dark:border-gray-600"> |
||||||
|
<button type="submit" class="bg-blue-500 hover:bg-opacity-90 transition-all text-white py-2 px-6 rounded text-lg">Cadastrar</button> |
||||||
|
</div> |
||||||
|
</form> |
||||||
|
</div> |
||||||
|
</div> |
Loading…
Reference in new issue