First Commit

This commit is contained in:
marco
2026-09-01 10:46:29 -03:00
commit bf96b77e9c
10000 changed files with 3508600 additions and 0 deletions
+106
View File
@@ -0,0 +1,106 @@
{% extends "layouts/dashboard.twig" %}
{% block title %}{{ target_user ? __('users.titles.edit') : __('users.titles.create') }} - {{ platformName }}{% endblock %}
{% block content %}
<div class="container-fluid px-4">
<h1 class="mt-4">{{ target_user ? __('users.titles.edit') : __('users.titles.create') }}</h1>
<ol class="breadcrumb mb-4">
<li class="breadcrumb-item"><a href="{{ url('admin/dashboard') }}">{{ __('dashboard.title') }}</a></li>
<li class="breadcrumb-item"><a href="{{ url('admin/users') }}">{{ __('users.breadcrumb.users') }}</a></li>
<li class="breadcrumb-item active">{{ target_user ? __('users.breadcrumb.edit') : __('users.breadcrumb.create') }}</li>
</ol>
{% include '@users/admin/nav.twig' ignore missing %}
<div class="card mb-4">
<div class="card-header">
<i class="bi bi-person-gear me-1"></i>
{{ __('users.headers.user_details') }}
</div>
<div class="card-body">
{% if error %}
<div class="alert alert-danger" role="alert">
{{ error }}
</div>
{% endif %}
<form action="{{ target_user ? url('admin/users/' ~ target_user.users_id) : url('admin/users') }}" method="POST" enctype="multipart/form-data">
{% if target_user %}
<input type="hidden" name="_method" value="PUT">
{% endif %}
{{ csrf_field()|raw }}
<div class="row">
<div class="col-md-8">
<div class="mb-3">
<label for="name" class="form-label">{{ __('users.fields.name') }}</label>
<input type="text" class="form-control" id="name" name="name" value="{{ target_user ? target_user.users_name : '' }}" required>
</div>
<div class="mb-3">
<label for="email" class="form-label">{{ __('users.fields.email') }}</label>
<input type="email" class="form-control" id="email" name="email" value="{{ target_user ? target_user.users_email : '' }}" required>
</div>
<div class="mb-3" x-data="{ show: false }">
<label for="password" class="form-label">{{ __('users.fields.password') }} {{ target_user ? __('users.fields.password_hint') : '' }}</label>
<div class="input-group">
<input :type="show ? 'text' : 'password'" class="form-control" id="password" name="password" {{ target_user ? '' : 'required' }} autocomplete="new-password" value="">
<button class="btn btn-outline-secondary" type="button" @click="show = !show">
<i :class="show ? 'bi bi-eye-slash' : 'bi bi-eye'"></i>
</button>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label for="role" class="form-label">{{ __('users.fields.role') }}</label>
<select class="form-select" id="role" name="role">
<option value="user" {{ target_user.users_role == 'user' ? 'selected' : '' }}>{{ __('users.roles.user') }}</option>
<option value="member" {{ target_user.users_role == 'member' ? 'selected' : '' }}>{{ __('users.roles.member') }}</option>
<option value="admin" {{ target_user.users_role == 'admin' ? 'selected' : '' }}>{{ __('users.roles.admin') }}</option>
<option value="super_admin" {{ target_user.users_role == 'super_admin' ? 'selected' : '' }}>{{ __('users.roles.super_admin') ?: 'Super Admin' }}</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="status" class="form-label">{{ __('users.fields.status') }}</label>
<select class="form-select" id="status" name="status">
<option value="active" {{ target_user and target_user.users_status == 'active' ? 'selected' : '' }}>{{ __('users.statuses.active') }}</option>
<option value="inactive" {{ target_user and target_user.users_status == 'inactive' ? 'selected' : '' }}>{{ __('users.statuses.inactive') }}</option>
</select>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card mb-3">
<div class="card-header">{{ __('users.fields.avatar') }}</div>
<div class="card-body text-center">
<div class="mb-3">
{% if target_user and target_user.users_avatar %}
<img src="{{ target_user.avatar_url }}" alt="Avatar" class="img-thumbnail rounded-circle mb-2" style="width: 150px; height: 150px; object-fit: cover;">
{% else %}
<div class="bg-light rounded-circle d-inline-flex align-items-center justify-content-center mb-2" style="width: 150px; height: 150px;">
<i class="bi bi-person fs-1 text-secondary"></i>
</div>
{% endif %}
</div>
<input type="file" class="form-control" id="avatar" name="avatar" accept="image/*">
<div class="form-text small text-muted mt-2">JPG, PNG or GIF. Max 2MB.</div>
</div>
</div>
</div>
</div>
<div class="d-flex justify-content-between">
<a href="{{ url('admin/users') }}" class="btn btn-secondary">{{ __('users.actions.cancel') }}</a>
<button type="submit" class="btn btn-primary">{{ target_user ? __('users.actions.update_user') : __('users.actions.create_user') }}</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
+83
View File
@@ -0,0 +1,83 @@
{% extends "layouts/dashboard.twig" %}
{% block title %}{{ __('users.titles.management') }} - {{ platformName }}{% endblock %}
{% block content %}
<div class="container-fluid px-4">
<h1 class="mt-4">{{ __('users.titles.management') }}</h1>
<ol class="breadcrumb mb-4">
<li class="breadcrumb-item"><a href="{{ url('admin/dashboard') }}">{{ __('dashboard.title') }}</a></li>
<li class="breadcrumb-item active">{{ __('users.breadcrumb.users') }}</li>
</ol>
{% include '@users/admin/nav.twig' ignore missing %}
<div class="card mb-4">
<div class="card-header d-flex justify-content-between align-items-center">
<div>
<i class="bi bi-people me-1"></i>
{{ __('users.headers.all_users') }}
</div>
</div>
<div class="card-body">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>{{ __('users.fields.name') }}</th>
<th>{{ __('users.fields.email') }}</th>
<th>{{ __('users.fields.role') }}</th>
<th>{{ __('users.fields.status') }}</th>
<th>{{ __('users.fields.created_at') }}</th>
<th>{{ __('users.fields.actions') }}</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td>{{ user.users_name }}</td>
<td>{{ user.users_email }}</td>
<td>{{ __('users.roles.' ~ user.users_role) }}</td>
<td>
{% if user.users_status == 'active' %}
<span class="badge bg-success">{{ __('users.statuses.active') }}</span>
{% else %}
<span class="badge bg-secondary">{{ __('users.statuses.' ~ user.users_status) }}</span>
{% endif %}
</td>
<td>{{ user.created_at|date("Y-m-d") }}</td>
<td>
<a href="{{ url('admin/users/' ~ user.users_id) }}" class="btn btn-sm btn-secondary" title="{{ __('users.actions.view') }}">
<i class="bi bi-eye"></i>
</a>
<a href="{{ url('admin/users/' ~ user.users_id ~ '/edit') }}" class="btn btn-sm btn-info" title="{{ __('users.actions.edit') }}">
<i class="bi bi-pencil"></i>
</a>
{% if (session('user_role') == 'super_admin' or session('user_role') == 'admin') and (user.users_role == 'member' or user.users_role == 'user') %}
<a href="{{ url('admin/users/' ~ user.users_id ~ '/permissions') }}" class="btn btn-sm btn-warning" title="{{ __('users.headers.user_permissions') }}">
<i class="bi bi-shield-lock"></i>
</a>
{% endif %}
{% if user.users_id != session('user_id') %}
<form action="{{ url('admin/users/' ~ user.users_id) }}" method="POST" class="d-inline" onsubmit="return confirm('{{ __('users.actions.confirm_delete') }}');">
<input type="hidden" name="_method" value="DELETE">
{{ csrf_field()|raw }}
<button type="submit" class="btn btn-sm btn-danger" title="{{ __('users.actions.delete') }}">
<i class="bi bi-trash"></i>
</button>
</form>
{% endif %}
</td>
</tr>
{% else %}
<tr>
<td colspan="6" class="text-center">{{ __('users.messages.no_users_found') }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
+75
View File
@@ -0,0 +1,75 @@
{% extends "layouts/dashboard.twig" %}
{% block content %}
<div class="container-fluid px-4">
<h1 class="mt-4">{{ title }}</h1>
<ol class="breadcrumb mb-4">
<li class="breadcrumb-item"><a href="{{ url('admin/dashboard') }}">{{ __('dashboard.title') }}</a></li>
<li class="breadcrumb-item"><a href="{{ url('admin/users') }}">{{ __('users.breadcrumb.users') }}</a></li>
<li class="breadcrumb-item active">Manual</li>
</ol>
{% include '@users/admin/nav.twig' ignore missing %}
<div class="row">
<div class="col-lg-3 d-none d-lg-block">
<div class="list-group sticky-top" style="top: 100px; z-index: 1;">
<a href="#visao-geral" class="list-group-item list-group-item-action">Visão Geral</a>
<a href="#niveis-acesso" class="list-group-item list-group-item-action">Níveis de Acesso</a>
<a href="#permissoes" class="list-group-item list-group-item-action">Permissões Granulares</a>
<a href="#status" class="list-group-item list-group-item-action">Status do Usuário</a>
</div>
</div>
<div class="col-lg-9">
<!-- Visão Geral -->
<div class="card shadow mb-4" id="visao-geral">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">1. Visão Geral</h6>
</div>
<div class="card-body">
<p>O módulo de <strong>Usuários</strong> é o coração da segurança do SysCMS. Aqui você gerencia quem pode acessar o painel administrativo, quais módulos cada pessoa pode ver e o que cada uma pode fazer.</p>
</div>
</div>
<!-- Níveis de Acesso -->
<div class="card shadow mb-4" id="niveis-acesso">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">2. Níveis de Acesso (Roles)</h6>
</div>
<div class="card-body">
<ul>
<li><strong>Super Admin:</strong> Acesso total a todos os módulos e configurações globais do sistema.</li>
<li><strong>Admin:</strong> Acesso administrativo total apenas para a sua empresa/unidade.</li>
<li><strong>Manager:</strong> Pode gerenciar conteúdos, mas não usuários ou configurações críticas.</li>
<li><strong>User/Member:</strong> Acesso limitado, geralmente apenas para visualização ou perfis públicos.</li>
</ul>
</div>
</div>
<!-- Permissões -->
<div class="card shadow mb-4" id="permissoes">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">3. Permissões Granulares</h6>
</div>
<div class="card-body">
<p>Além do nível de acesso, você pode definir permissões específicas. Clique no ícone de <strong>chave (escudo)</strong> na lista de usuários para escolher exatamente quais módulos aquele usuário pode gerenciar.</p>
</div>
</div>
<!-- Status -->
<div class="card shadow mb-4" id="status">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">4. Status do Usuário</h6>
</div>
<div class="card-body">
<ul>
<li><strong>Ativo:</strong> Acesso normal ao sistema.</li>
<li><strong>Inativo:</strong> O usuário não consegue fazer login, mas seus dados e históricos são preservados.</li>
</ul>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
+13
View File
@@ -0,0 +1,13 @@
<div class="mb-4 d-print-none">
<div class="btn-group" role="group" aria-label="Navegação Usuários">
<a href="/admin/users" class="btn btn-outline-primary {% if request_path == '/admin/users' %}active{% endif %}">
<i class="bi bi-people"></i> Todos os Usuários
</a>
<a href="/admin/users/create" class="btn btn-outline-primary {% if request_path == '/admin/users/create' %}active{% endif %}">
<i class="bi bi-person-plus"></i> Novo Usuário
</a>
<a href="/admin/users/manual" class="btn btn-outline-info {% if request_path == '/admin/users/manual' %}active{% endif %}">
<i class="bi bi-book"></i> Manual
</a>
</div>
</div>
+117
View File
@@ -0,0 +1,117 @@
{% extends "layouts/dashboard.twig" %}
{% block title %}{{ __('users.headers.user_permissions') }} - {{ target_user.users_name }} - {{ platformName }}{% endblock %}
{% block scripts %}
<script>
document.addEventListener('DOMContentLoaded', function() {
// Select all permissions in a module
const selectAllSwitches = document.querySelectorAll('.select-all-module');
selectAllSwitches.forEach(sw => {
sw.addEventListener('change', function() {
const cardBody = this.closest('.card').querySelector('.card-body');
const checkboxes = cardBody.querySelectorAll('.form-check-input');
checkboxes.forEach(cb => {
cb.checked = this.checked;
});
});
});
// Update "Select All" switch based on individual checkboxes
const moduleCards = document.querySelectorAll('.card.h-100');
moduleCards.forEach(card => {
const selectAllSwitch = card.querySelector('.select-all-module');
if (!selectAllSwitch) return;
const checkboxes = card.querySelectorAll('.card-body .form-check-input');
const updateSelectAll = () => {
const allChecked = Array.from(checkboxes).every(cb => cb.checked);
const someChecked = Array.from(checkboxes).some(cb => cb.checked);
selectAllSwitch.checked = allChecked;
selectAllSwitch.indeterminate = someChecked && !allChecked;
};
checkboxes.forEach(cb => {
cb.addEventListener('change', updateSelectAll);
});
// Initial check
updateSelectAll();
});
});
</script>
{% endblock %}
{% block content %}
<div class="container-fluid px-4">
<h1 class="mt-4">{{ __('users.headers.user_permissions') }}</h1>
<ol class="breadcrumb mb-4">
<li class="breadcrumb-item"><a href="{{ url('admin/dashboard') }}">{{ __('users.breadcrumb.dashboard') }}</a></li>
<li class="breadcrumb-item"><a href="{{ url('admin/users') }}">{{ __('users.breadcrumb.users') }}</a></li>
<li class="breadcrumb-item active">{{ __('users.breadcrumb.permissions') }}: {{ target_user.users_name }}</li>
</ol>
{% include '@users/admin/nav.twig' ignore missing %}
<div class="card mb-4">
<div class="card-header">
<i class="bi bi-shield-lock me-1"></i>
{{ __('users.headers.manage_permissions', {
'name': target_user.users_name,
'role': attribute(__(['users.roles.', target_user.users_role]|join), '') ?: target_user.users_role|upper
}) }}
</div>
<div class="card-body">
<form action="{{ url('admin/users/' ~ target_user.users_id ~ '/permissions') }}" method="POST">
{{ csrf_field()|raw }}
<div class="row">
{% for module in modules %}
<div class="col-md-6 mb-4">
<div class="card h-100">
<div class="card-header bg-light d-flex justify-content-between align-items-center">
<h6 class="mb-0">
<i class="{{ module.modules_icon ?: 'bi bi-box' }} me-2"></i>
{{ module.modules_display_name }}
</h6>
{% if module.modules_permissions %}
<div class="form-check form-switch mb-0">
<input class="form-check-input select-all-module" type="checkbox" id="select_all_{{ module.modules_id }}">
<label class="form-check-label small" for="select_all_{{ module.modules_id }}">Marcar todos</label>
</div>
{% endif %}
</div>
<div class="card-body">
{% if module.modules_permissions %}
{% for permission in module.modules_permissions %}
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" name="permissions[]"
value="{{ permission }}" id="perm_{{ loop.parent.loop.index }}_{{ loop.index }}"
{% if permission in user_permissions %}checked{% endif %}>
<label class="form-check-label" for="perm_{{ loop.parent.loop.index }}_{{ loop.index }}">
{{ attribute(__(['users.permissions.', permission]|join), '') ?: permission }}
</label>
</div>
{% endfor %}
{% else %}
<p class="text-muted small mb-0">{{ __('users.fields.no_permissions_config') }}</p>
{% endif %}
</div>
</div>
</div>
{% endfor %}
</div>
<div class="mt-4 d-flex justify-content-between">
<a href="{{ url('admin/users') }}" class="btn btn-secondary">{{ __('users.actions.back') }}</a>
<button type="submit" class="btn btn-primary">{{ __('users.actions.save_permissions') }}</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
+79
View File
@@ -0,0 +1,79 @@
{% extends "layouts/dashboard.twig" %}
{% block title %}{{ __('users.headers.user_details') }} - {{ platformName }}{% endblock %}
{% block content %}
<div class="container-fluid px-4">
<h1 class="mt-4">{{ __('users.headers.user_details') }}</h1>
<ol class="breadcrumb mb-4">
<li class="breadcrumb-item"><a href="{{ url('admin/dashboard') }}">{{ __('dashboard.title') }}</a></li>
<li class="breadcrumb-item"><a href="{{ url('admin/users') }}">{{ __('users.breadcrumb.users') }}</a></li>
<li class="breadcrumb-item active">{{ user.users_name }}</li>
</ol>
{% include '@users/admin/nav.twig' ignore missing %}
<div class="card mb-4">
<div class="card-header">
<i class="bi bi-person me-1"></i>
{{ __('users.headers.user_details') }}
</div>
<div class="card-body">
<div class="row mb-3">
<label class="col-sm-2 col-form-label fw-bold">{{ __('users.fields.name') }}</label>
<div class="col-sm-10">
<p class="form-control-plaintext">{{ user.users_name }}</p>
</div>
</div>
<div class="row mb-3">
<label class="col-sm-2 col-form-label fw-bold">{{ __('users.fields.email') }}</label>
<div class="col-sm-10">
<p class="form-control-plaintext">{{ user.users_email }}</p>
</div>
</div>
<div class="row mb-3">
<label class="col-sm-2 col-form-label fw-bold">{{ __('users.fields.role') }}</label>
<div class="col-sm-10">
<p class="form-control-plaintext">{{ __('users.roles.' ~ user.users_role) }}</p>
</div>
</div>
<div class="row mb-3">
<label class="col-sm-2 col-form-label fw-bold">{{ __('users.fields.status') }}</label>
<div class="col-sm-10">
{% if user.users_status == 'active' %}
<span class="badge bg-success">{{ __('users.statuses.active') }}</span>
{% else %}
<span class="badge bg-secondary">{{ __('users.statuses.' ~ user.users_status) }}</span>
{% endif %}
</div>
</div>
<div class="row mb-3">
<label class="col-sm-2 col-form-label fw-bold">{{ __('users.fields.created_at') }}</label>
<div class="col-sm-10">
<p class="form-control-plaintext">{{ user.created_at|date("Y-m-d H:i:s") }}</p>
</div>
</div>
<div class="row mb-3">
<label class="col-sm-2 col-form-label fw-bold">{{ __('users.fields.last_login') }}</label>
<div class="col-sm-10">
<p class="form-control-plaintext">
{{ user.users_last_login_at ? user.users_last_login_at|date("Y-m-d H:i:s") : __('users.messages.never') }}
</p>
</div>
</div>
<div class="d-flex justify-content-between mt-4">
<a href="{{ url('admin/users') }}" class="btn btn-secondary">{{ __('users.actions.back_to_list') }}</a>
<div>
<a href="{{ url('admin/users/' ~ user.users_id ~ '/edit') }}" class="btn btn-primary">{{ __('users.actions.edit') }}</a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}