deash-session / index.html
castro777's picture
Add 2 files
e3f57b5 verified
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Poker Dashboard</title>
<script src="https://cdn.jsdelivr.net/npm/lucide@latest/dist/umd/lucide.min.js"></script>
<style>
:root {
--bg-primary: #1E1E1E;
--bg-secondary: #2D2D2D;
--bg-card: #1E1E1E;
--border: #333333;
--border-hover: #555555;
--text: #FFFFFF;
--text-secondary: #A1A1A1;
--primary: #3B82F6;
--primary-hover: #2563EB;
--success: #10B981;
--success-hover: #059669;
--danger: #EF4444;
--danger-hover: #DC2626;
--warning: #F59E0B;
--warning-hover: #D97706;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background-color: var(--bg-primary);
color: var(--text);
line-height: 1.5;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 1rem;
}
/* Typography */
h1, h2, h3, h4, h5, h6 {
font-weight: 600;
margin-bottom: 0.5rem;
}
h1 {
font-size: 2rem;
}
h2 {
font-size: 1.75rem;
}
h3 {
font-size: 1.5rem;
}
p, span {
color: var(--text-secondary);
}
/* Layout */
.flex {
display: flex;
}
.flex-col {
flex-direction: column;
}
.flex-row {
flex-direction: row;
}
.items-center {
align-items: center;
}
.items-start {
align-items: flex-start;
}
.justify-between {
justify-content: space-between;
}
.justify-center {
justify-content: center;
}
.gap-1 {
gap: 0.25rem;
}
.gap-2 {
gap: 0.5rem;
}
.gap-3 {
gap: 0.75rem;
}
.gap-4 {
gap: 1rem;
}
.gap-6 {
gap: 1.5rem;
}
.w-full {
width: 100%;
}
.w-auto {
width: auto;
}
.max-w-md {
max-width: 28rem;
}
.mx-auto {
margin-left: auto;
margin-right: auto;
}
.space-y-2 > * + * {
margin-top: 0.5rem;
}
.space-y-4 > * + * {
margin-top: 1rem;
}
.space-y-6 > * + * {
margin-top: 1.5rem;
}
.mb-1 {
margin-bottom: 0.25rem;
}
.mb-2 {
margin-bottom: 0.5rem;
}
.mb-4 {
margin-bottom: 1rem;
}
.mb-6 {
margin-bottom: 1.5rem;
}
.mt-1 {
margin-top: 0.25rem;
}
.mt-2 {
margin-top: 0.5rem;
}
.mt-4 {
margin-top: 1rem;
}
.py-2 {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
}
.py-4 {
padding-top: 1rem;
padding-bottom: 1rem;
}
.py-6 {
padding-top: 1.5rem;
padding-bottom: 1.5rem;
}
.py-8 {
padding-top: 2rem;
padding-bottom: 2rem;
}
.py-12 {
padding-top: 3rem;
padding-bottom: 3rem;
}
.pt-2 {
padding-top: 0.5rem;
}
.pt-4 {
padding-top: 1rem;
}
.pb-2 {
padding-bottom: 0.5rem;
}
.p-4 {
padding: 1rem;
}
.p-5 {
padding: 1.25rem;
}
.p-6 {
padding: 1.5rem;
}
.px-4 {
padding-left: 1rem;
padding-right: 1rem;
}
.px-5 {
padding-left: 1.25rem;
padding-right: 1.25rem;
}
.px-6 {
padding-left: 1.5rem;
padding-right: 1.5rem;
}
.pl-5 {
padding-left: 1.25rem;
}
/* Cards */
.card {
background-color: var(--bg-card);
border: 1px solid var(--border);
border-radius: 0.5rem;
overflow: hidden;
transition: all 0.2s ease;
}
.card-header {
padding: 1.5rem 1.5rem 0;
}
.card-content {
padding: 1.5rem;
}
.card-footer {
padding: 0 1.5rem 1.5rem;
}
/* Buttons */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.5rem 1rem;
border-radius: 0.375rem;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
border: 1px solid transparent;
}
.btn-primary {
background-color: var(--primary);
color: white;
}
.btn-primary:hover {
background-color: var(--primary-hover);
}
.btn-success {
background-color: var(--success);
color: white;
}
.btn-success:hover {
background-color: var(--success-hover);
}
.btn-danger {
background-color: var(--danger);
color: white;
}
.btn-danger:hover {
background-color: var(--danger-hover);
}
.btn-outline {
background-color: transparent;
border: 1px solid var(--border);
color: var(--text);
}
.btn-outline:hover {
background-color: var(--bg-secondary);
}
.btn-ghost {
background-color: transparent;
color: var(--text);
}
.btn-ghost:hover {
background-color: var(--bg-secondary);
}
.btn-sm {
padding: 0.25rem 0.5rem;
font-size: 0.875rem;
}
.btn-lg {
padding: 0.75rem 1.5rem;
font-size: 1.125rem;
}
.btn .icon {
margin-right: 0.5rem;
width: 1rem;
height: 1rem;
}
/* Badge */
.badge {
display: inline-flex;
align-items: center;
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
font-size: 0.75rem;
font-weight: 500;
}
.badge-success {
background-color: rgba(16, 185, 129, 0.1);
color: #10B981;
}
.badge-danger {
background-color: rgba(239, 68, 68, 0.1);
color: #EF4444;
}
.badge-warning {
background-color: rgba(245, 158, 11, 0.1);
color: #F59E0B;
}
/* Input */
.input {
display: block;
width: 100%;
padding: 0.5rem 1rem;
background-color: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 0.375rem;
color: var(--text);
transition: border-color 0.2s ease;
}
.input:focus {
outline: none;
border-color: var(--primary);
}
.input-error {
border-color: var(--danger);
}
/* Alert */
.alert {
padding: 1rem;
border-radius: 0.375rem;
margin-bottom: 1rem;
}
.alert-danger {
background-color: rgba(239, 68, 68, 0.1);
border: 1px solid rgba(239, 68, 68, 0.2);
color: #EF4444;
}
.alert-success {
background-color: rgba(16, 185, 129, 0.1);
border: 1px solid rgba(16, 185, 129, 0.2);
color: #10B981;
}
/* Loading */
.animate-spin {
animation: spin 1s linear infinite;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
/* Grid */
.grid {
display: grid;
}
.grid-cols-1 {
grid-template-columns: repeat(1, minmax(0, 1fr));
}
.grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.grid-cols-3 {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
/* Dialog */
.dialog-overlay {
position: fixed;
inset: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 100;
}
.dialog-content {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: var(--bg-primary);
border: 1px solid var(--border);
border-radius: 0.5rem;
padding: 1.5rem;
width: 90%;
max-width: 500px;
z-index: 101;
max-height: 90vh;
overflow-y: auto;
}
.dialog-header {
text-align: center;
margin-bottom: 1.5rem;
}
.dialog-title {
font-size: 1.25rem;
font-weight: 600;
}
.dialog-description {
color: var(--text-secondary);
}
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 0.5rem;
margin-top: 1.5rem;
}
/* Utils */
.text-center {
text-align: center;
}
.text-left {
text-align: left;
}
.text-right {
text-align: right;
}
.text-xl {
font-size: 1.25rem;
}
.text-lg {
font-size: 1.125rem;
}
.text-sm {
font-size: 0.875rem;
}
.text-xs {
font-size: 0.75rem;
}
.font-semibold {
font-weight: 600;
}
.font-bold {
font-weight: 700;
}
.rounded-lg {
border-radius: 0.5rem;
}
.rounded-md {
border-radius: 0.375rem;
}
.rounded-full {
border-radius: 9999px;
}
.border-l-4 {
border-left-width: 4px;
}
.border-l-green-600 {
border-left-color: #16A34A;
}
.cursor-pointer {
cursor: pointer;
}
.hidden {
display: none;
}
.relative {
position: relative;
}
.absolute {
position: absolute;
}
/* Responsive */
@media (min-width: 768px) {
.md:grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.md:flex-row {
flex-direction: row;
}
.md:w-auto {
width: auto;
}
}
/* Custom Components */
.session-card {
position: relative;
}
.session-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
.player-card {
transition: all 0.2s ease;
}
.player-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
.section-tabs {
width: 100%;
}
/* Animation */
@keyframes pulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
.animate-pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
</style>
</head>
<body>
<div class="container">
<div class="space-y-6">
<!-- Header -->
<div class="flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
<div>
<h1 class="text-2xl font-bold mb-1">Poker Dashboard</h1>
<p class="text-secondary" id="user-email">carregando...</p>
</div>
<div class="w-full md:w-auto flex gap-2">
<button id="new-session-btn" class="btn btn-primary" disabled>
Nova Sessão
</button>
<button id="reset-data-btn" class="btn btn-danger" disabled>
Reset Dados
</button>
</div>
</div>
<!-- New Session Form (Hidden by default) -->
<div id="new-session-form" class="card hidden">
<div class="card-header">
<h3 class="text-lg">Criar Nova Sessão</h3>
</div>
<div class="card-content">
<form id="session-form" class="space-y-4">
<div class="space-y-2">
<label for="session-name" class="block text-sm font-medium">Nome da Sessão</label>
<input
type="text"
id="session-name"
class="input"
placeholder="Digite um nome para a sessão"
/>
</div>
<div class="flex flex-col sm:flex-row gap-2 pt-2">
<button
type="button"
id="cancel-new-session"
class="btn btn-outline w-full sm:w-auto"
>
Cancelar
</button>
<button
type="submit"
id="create-session"
class="btn btn-primary w-full sm:w-auto"
disabled
>
Criar e Iniciar
</button>
</div>
</form>
</div>
</div>
<!-- Tab Navigation -->
<div class="flex justify-center mb-4">
<div class="bg-card rounded-lg border border-border p-1 grid grid-cols-3 w-full md:w-auto">
<button
id="active-sessions-tab"
class="btn btn-primary rounded-md"
>
<i class="icon" data-lucide="clock"></i>
<span class="truncate">Ativas</span>
</button>
<button
id="finished-sessions-tab"
class="btn btn-ghost rounded-md"
>
<i class="icon" data-lucide="check-circle"></i>
<span class="truncate">Finalizadas</span>
</button>
<button
id="players-tab"
class="btn btn-ghost rounded-md"
>
<i class="icon" data-lucide="users"></i>
<span class="truncate">Jogadores</span>
</button>
</div>
</div>
<!-- Content Area -->
<div class="card">
<div class="card-header">
<h3 id="content-title">Sessões Ativas</h3>
</div>
<div class="card-content">
<!-- Loading State -->
<div id="loading-state" class="py-8 flex justify-center">
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-white"></div>
</div>
<!-- Error State -->
<div id="error-state" class="hidden bg-red-900/20 border border-red-800 rounded-lg p-6 text-center">
<i class="icon mx-auto mb-4" style="height: 3rem; width: 3rem; color: #EF4444" data-lucide="alert-circle"></i>
<h3 class="text-xl font-medium text-red-300 mb-2">Erro</h3>
<p class="text-red-200 mb-4" id="error-message"></p>
<button id="retry-btn" class="btn btn-danger">
Tentar Novamente
</button>
</div>
<!-- Active Sessions Content -->
<div id="active-sessions-content" class="hidden space-y-4">
<!-- Active sessions will be dynamically inserted here -->
</div>
<!-- No Active Sessions -->
<div id="no-active-sessions" class="hidden text-center py-12 bg-card rounded-lg border border-border">
<i class="icon mx-auto mb-4" style="height: 3rem; width: 3rem; color: #A1A1A1" data-lucide="clock"></i>
<h3 class="text-lg font-medium mb-2">Nenhuma sessão ativa</h3>
<p class="text-secondary mt-2 mb-6 max-w-md mx-auto">
Crie uma nova sessão para começar a gerenciar suas partidas de poker
</p>
<button id="new-session-empty-btn" class="btn btn-primary">
<i class="icon" data-lucide="plus"></i>
Nova Sessão
</button>
</div>
<!-- Finished Sessions Content -->
<div id="finished-sessions-content" class="hidden space-y-4">
<!-- Finished sessions will be dynamically inserted here -->
</div>
<!-- No Finished Sessions -->
<div id="no-finished-sessions" class="hidden text-center py-12 bg-card rounded-lg border border-border">
<i class="icon mx-auto mb-4" style="height: 3rem; width: 3rem; color: #A1A1A1" data-lucide="check-circle"></i>
<h3 class="text-lg font-medium mb-2">Nenhuma sessão finalizada</h3>
<p class="text-secondary mt-2 max-w-md mx-auto">
As sessões finalizadas aparecerão aqui para consulta
</p>
</div>
<!-- Players Content -->
<div id="players-content" class="hidden">
<div id="players-grid" class="grid grid-cols-1 md:grid-cols-2 gap-4">
<!-- Players will be dynamically inserted here -->
</div>
<!-- No Players -->
<div id="no-players" class="hidden py-8 text-center">
<p class="text-secondary mb-4">Nenhum jogador cadastrado ainda.</p>
<button id="add-players-btn" class="btn btn-primary">
<i class="icon" data-lucide="plus"></i>
Cadastrar Jogadores
</button>
</div>
<!-- View All Players Button -->
<div id="view-all-players" class="hidden flex justify-center mt-6">
<button id="all-players-btn" class="btn btn-primary">
Ver Todos os Jogadores
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Reset Data Confirmation Dialog -->
<div id="reset-dialog" class="dialog-overlay hidden">
<div class="dialog-content">
<div class="dialog-header">
<div class="dialog-title flex items-center gap-2">
<i class="icon text-red-400" data-lucide="alert-circle"></i>
Atenção! Reset de Dados
</div>
<div class="dialog-description">
<div class="mt-2 p-3 bg-red-950/30 border border-red-900 rounded-md text-red-300">
Esta ação irá excluir <span class="font-bold">todos os dados</span> do sistema, incluindo:
<ul class="list-disc pl-5 mt-2 space-y-1">
<li>Todas as sessões</li>
<li>Todos os dados de transações</li>
<li>Todas as fichas cadastradas</li>
<li>Todos os saldos e históricos</li>
</ul>
<p class="mt-2 font-semibold">Esta ação não pode ser desfeita!</p>
</div>
</div>
</div>
<div class="space-y-4 py-2">
<div class="space-y-2">
<label for="reset-password" class="text-red-300">Digite a senha de segurança:</label>
<input
type="password"
id="reset-password"
class="input"
placeholder="Senha de segurança"
/>
<p id="password-error" class="hidden text-red-500 text-sm">Senha incorreta. Tente novamente.</p>
</div>
</div>
<div class="dialog-footer">
<button
id="cancel-reset"
class="btn btn-outline"
>
Cancelar
</button>
<button
id="confirm-reset"
class="btn btn-danger"
disabled
>
Confirmar Reset
</button>
</div>
</div>
</div>
<script>
// Initialize Lucide icons
lucide.createIcons();
// Mock data - in a real app, this would come from an API
const mockUser = {
id: 'user-123',
email: 'admin@poker.com',
name: 'Admin'
};
const mockSessions = [
{
id: 'session-1',
name: 'Sessão do Clube',
startTime: '2023-06-15T19:00:00',
endTime: '',
isActive: true,
createdBy: mockUser.email,
cashBoxId: 'cashbox-1'
},
{
id: 'session-2',
name: 'Torneio Mensal',
startTime: '2023-06-01T15:00:00',
endTime: '2023-06-01T22:30:00',
isActive: false,
createdBy: mockUser.email,
cashBoxId: 'cashbox-1'
},
{
id: 'session-3',
name: 'Torneio Anual',
startTime: '2023-01-15T12:00:00',
endTime: '2023-01-16T03:45:00',
isActive: false,
createdBy: mockUser.email,
cashBoxId: 'cashbox-1'
}
];
const mockPlayers = [
{
id: 'player-1',
name: 'João Silva',
email: 'joao@example.com',
totalBalance: 250.50,
pendingAmount: 50.00
},
{
id: 'player-2',
name: 'Maria Oliveira',
email: 'maria@example.com',
totalBalance: -120.75,
pendingAmount: 0
},
{
id: 'player-3',
name: 'Pedro Santos',
email: 'pedro@example.com',
totalBalance: 75.20,
pendingAmount: 100.00
},
{
id: 'player-4',
name: 'Ana Costa',
email: 'ana@example.com',
totalBalance: -200.30,
pendingAmount: 0
}
];
// State management
let currentSessionName = '';
let activeTab = 'active-sessions'; // default tab
let isLoading = false;
// DOM elements
const elements = {
userEmail: document.getElementById('user-email'),
newSessionBtn: document.getElementById('new-session-btn'),
resetDataBtn: document.getElementById('reset-data-btn'),
newSessionForm: document.getElementById('new-session-form'),
sessionForm: document.getElementById('session-form'),
sessionNameInput: document.getElementById('session-name'),
cancelNewSession: document.getElementById('cancel-new-session'),
createSession: document.getElementById('create-session'),
activeSessionsTab: document.getElementById('active-sessions-tab'),
finishedSessionsTab: document.getElementById('finished-sessions-tab'),
playersTab: document.getElementById('players-tab'),
contentTitle: document.getElementById('content-title'),
loadingState: document.getElementById('loading-state'),
errorState: document.getElementById('error-state'),
errorMessage: document.getElementById('error-message'),
retryBtn: document.getElementById('retry-btn'),
activeSessionsContent: document.getElementById('active-sessions-content'),
noActiveSessions: document.getElementById('no-active-sessions'),
newSessionEmptyBtn: document.getElementById('new-session-empty-btn'),
finishedSessionsContent: document.getElementById('finished-sessions-content'),
noFinishedSessions: document.getElementById('no-finished-sessions'),
playersContent: document.getElementById('players-content'),
playersGrid: document.getElementById('players-grid'),
noPlayers: document.getElementById('no-players'),
addPlayersBtn: document.getElementById('add-players-btn'),
viewAllPlayers: document.getElementById('view-all-players'),
allPlayersBtn: document.getElementById('all-players-btn'),
resetDialog: document.getElementById('reset-dialog'),
resetPassword: document.getElementById('reset-password'),
passwordError: document.getElementById('password-error'),
cancelReset: document.getElementById('cancel-reset'),
confirmReset: document.getElementById('confirm-reset')
};
// Format date to Brazilian format
function formatDate(dateString) {
if (!dateString) return '--';
const date = new Date(dateString);
return date.toLocaleString('pt-BR', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
}
// Format duration between two dates
function formatDuration(startDate, endDate) {
if (!startDate || !endDate) return "--";
const start = new Date(startDate);
const end = new Date(endDate);
const diff = Math.abs(end.getTime() - start.getTime());
const hours = Math.floor(diff / (1000 * 60 * 60));
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
return `${hours}h ${minutes}min`;
}
// Format currency to Brazilian Real
function formatCurrency(amount) {
return new Intl.NumberFormat('pt-BR', {
style: 'currency',
currency: 'BRL'
}).format(amount);
}
// Show active sessions
function renderActiveSessions(sessions) {
elements.activeSessionsContent.innerHTML = '';
if (sessions.length === 0) {
elements.noActiveSessions.classList.remove('hidden');
elements.activeSessionsContent.classList.add('hidden');
return;
}
elements.noActiveSessions.classList.add('hidden');
elements.activeSessionsContent.classList.remove('hidden');
sessions.forEach(session => {
const sessionElement = document.createElement('div');
sessionElement.className = 'card session-card bg-card border border-border border-l-4 border-l-green-600 transition-all hover:border-border-hover';
sessionElement.innerHTML = `
<div class="card-content p-5">
<div class="flex flex-col gap-4">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-full bg-green-900/30 flex items-center justify-center">
<i class="icon text-green-400" data-lucide="clock"></i>
</div>
<div>
<h3 class="text-lg font-semibold">${session.name}</h3>
<div class="text-sm text-secondary">
Iniciada em ${formatDate(session.startTime)}
</div>
</div>
</div>
<div class="flex flex-col sm:flex-row gap-3">
<button
data-session-id="${session.id}"
class="btn btn-success w-full sm:w-auto continue-session-btn"
>
<i class="icon" data-lucide="play"></i>
Continuar Sessão
</button>
<button
data-session-id="${session.id}"
class="btn btn-outline border-red-700 text-red-400 hover:bg-red-950 w-full sm:w-auto end-session-btn"
>
Finalizar
</button>
</div>
</div>
</div>
`;
elements.activeSessionsContent.appendChild(sessionElement);
});
// Reinitialize icons in the new content
lucide.createIcons();
// Add event listeners
document.querySelectorAll('.continue-session-btn').forEach(btn => {
btn.addEventListener('click', function() {
const sessionId = this.getAttribute('data-session-id');
continueSession(sessionId);
});
});
document.querySelectorAll('.end-session-btn').forEach(btn => {
btn.addEventListener('click', function() {
const sessionId = this.getAttribute('data-session-id');
endSession(sessionId);
});
});
}
// Show finished sessions
function renderFinishedSessions(sessions) {
elements.finishedSessionsContent.innerHTML = '';
if (sessions.length === 0) {
elements.noFinishedSessions.classList.remove('hidden');
elements.finishedSessionsContent.classList.add('hidden');
return;
}
elements.noFinishedSessions.classList.add('hidden');
elements.finishedSessionsContent.classList.remove('hidden');
sessions.forEach(session => {
const sessionElement = document.createElement('div');
sessionElement.className = 'card bg-card border border-border';
sessionElement.innerHTML = `
<div class="card-content p-4">
<div class="flex flex-col gap-3">
<div>
<h3 class="text-xl font-bold">${session.name}</h3>
<p class="text-sm text-secondary mt-1">
Iniciada em ${formatDate(session.startTime)}
</p>
<p class="text-sm text-secondary">
Finalizada em ${formatDate(session.endTime)}
</p>
<div class="mt-1 flex items-center gap-1">
<i class="icon w-3 h-3 text-secondary" data-lucide="calendar"></i>
<span class="text-xs text-secondary">
Duração: ${formatDuration(session.startTime, session.endTime)}
</span>
</div>
</div>
<button
data-session-id="${session.id}"
class="btn btn-primary w-full sm:w-auto view-session-details"
>
<i class="icon" data-lucide="arrow-right"></i>
Ver Detalhes
</button>
</div>
</div>
`;
elements.finishedSessionsContent.appendChild(sessionElement);
});
// Reinitialize icons in the new content
lucide.createIcons();
// Add event listeners
document.querySelectorAll('.view-session-details').forEach(btn => {
btn.addEventListener('click', function() {
const sessionId = this.getAttribute('data-session-id');
viewSessionDetails(sessionId);
});
});
}
// Show players
function renderPlayers(players) {
elements.playersGrid.innerHTML = '';
if (players.length === 0) {
elements.noPlayers.classList.remove('hidden');
elements.playersGrid.classList.add('hidden');
elements.viewAllPlayers.classList.add('hidden');
return;
}
elements.noPlayers.classList.add('hidden');
elements.playersGrid.classList.remove('hidden');
// Only show view all button if more than 4 players
elements.viewAllPlayers.classList.toggle('hidden', players.length <= 4);
// Show only first 4 players initially
const playersToShow = players.length > 4 ? players.slice(0, 4) : players;
playersToShow.forEach(player => {
const playerElement = document.createElement('div');
playerElement.className = 'player-card bg-card border border-border rounded-lg p-4 hover:border-border-hover cursor-pointer transition-colors';
playerElement.setAttribute('data-player-id', player.id);
const balanceClass = player.totalBalance < 0 ? 'text-red-400' :
player.totalBalance > 0 ? 'text-green-400' : 'text-white';
playerElement.innerHTML = `
<div class="flex justify-between items-start mb-2">
<h3 class="font-semibold text-lg">${player.name}</h3>
<div class="font-bold ${balanceClass}">
${formatCurrency(Math.abs(player.totalBalance))}
${player.totalBalance !== 0 ?
`<span class="text-sm ml-1">${player.totalBalance < 0 ? '(deve)' : '(recebe)'}</span>` :
''
}
</div>
</div>
${player.pendingAmount !== 0 ? `
<div class="mt-2">
<span class="badge ${player.pendingAmount > 0 ? 'badge-danger' : 'badge-success'}">
${player.pendingAmount > 0 ?
`Pendente: deve ${formatCurrency(player.pendingAmount)}` :
`Pendente: recebe ${formatCurrency(Math.abs(player.pendingAmount))}`
}
</span>
</div>
` : ''}
`;
elements.playersGrid.appendChild(playerElement);
});
// Add event listeners
document.querySelectorAll('.player-card').forEach(card => {
card.addEventListener('click', function() {
const playerId = this.getAttribute('data-player-id');
viewPlayerDetails(playerId);
});
});
}
// Change active tab
function setActiveTab(tab) {
activeTab = tab;
// Update tab buttons
elements.activeSessionsTab.className = tab === 'active-sessions' ? 'btn btn-primary rounded-md' : 'btn btn-ghost rounded-md';
elements.finishedSessionsTab.className = tab === 'finished-sessions' ? 'btn btn-primary rounded-md' : 'btn btn-ghost rounded-md';
elements.playersTab.className = tab === 'players' ? 'btn btn-primary rounded-md' : 'btn btn-ghost rounded-md';
// Update content title
if (tab === 'active-sessions') {
elements.contentTitle.textContent = 'Sessões Ativas';
} else if (tab === 'finished-sessions') {
elements.contentTitle.textContent = 'Sessões Finalizadas';
} else {
elements.contentTitle.textContent = 'Jogadores';
}
// Hide all content
elements.loadingState.classList.add('hidden');
elements.errorState.classList.add('hidden');
elements.activeSessionsContent.classList.add('hidden');
elements.noActiveSessions.classList.add('hidden');
elements.finishedSessionsContent.classList.add('hidden');
elements.noFinishedSessions.classList.add('hidden');
elements.playersContent.classList.add('hidden');
elements.playersGrid.classList.add('hidden');
elements.noPlayers.classList.add('hidden');
// Show loading state initially
elements.loadingState.classList.remove('hidden');
// Simulate loading time
setTimeout(() => {
elements.loadingState.classList.add('hidden');
if (tab === 'active-sessions') {
const activeSessions = mockSessions.filter(s => s.isActive);
renderActiveSessions(activeSessions);
} else if (tab === 'finished-sessions') {
const finishedSessions = mockSessions.filter(s => !s.isActive);
renderFinishedSessions(finishedSessions);
} else {
renderPlayers(mockPlayers);
}
}, 800);
}
// Simulate session functions
function createSession(sessionName) {
console.log(`Creating session: ${sessionName}`);
// In a real app, this would call an API
return new Promise((resolve) => {
setTimeout(() => {
const newSession = {
id: `session-${Date.now()}`,
name: sessionName,
startTime: new Date().toISOString(),
endTime: '',
isActive: true,
createdBy: mockUser.email,
cashBoxId: 'cashbox-1'
};
mockSessions.unshift(newSession);
resolve(newSession);
}, 1000);
});
}
function continueSession(sessionId) {
console.log(`Continuing session: ${sessionId}`);
// In a real app, this would navigate to the session page
alert(`Continuando sessão ${sessionId}. Redirecionando...`);
}
function endSession(sessionId) {
console.log(`Ending session: ${sessionId}`);
// In a real app, this would call an API
const session = mockSessions.find(s => s.id === sessionId);
if (session) {
session.isActive = false;
session.endTime = new Date().toISOString();
}
// Refresh the view
setActiveTab(activeTab);
}
function viewSessionDetails(sessionId) {
console.log(`Viewing session details: ${sessionId}`);
// In a real app, this would navigate to the session details page
alert(`Abrindo detalhes da sessão ${sessionId}...`);
}
function viewPlayerDetails(playerId) {
console.log(`Viewing player details: ${playerId}`);
// In a real app, this would navigate to the player details page
alert(`Abrindo detalhes do jogador ${playerId}...`);
}
function viewAllPlayers() {
console.log('Viewing all players');
// In a real app, this would navigate to the players page
alert('Abrindo lista completa de jogadores...');
}
function resetAllData() {
console.log('Resetting all data');
// In a real app, this would call an API to reset all data
return new Promise((resolve) => {
setTimeout(() => {
console.log('All data reset complete');
resolve();
}, 2000);
});
}
// Event listeners
elements.sessionForm.addEventListener('submit', async (e) => {
e.preventDefault();
if (!currentSessionName.trim()) return;
elements.createSession.disabled = true;
elements.createSession.innerHTML = `
<div class="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>
Criando...
`;
try {
await createSession(currentSessionName);
// Reset form
elements.newSessionForm.classList.add('hidden');
elements.sessionNameInput.value = '';
currentSessionName = '';
elements.createSession.disabled = true;
// Refresh the view
setActiveTab('active-sessions');
} catch (error) {
console.error('Error creating session:', error);
alert('Erro ao criar sessão. Por favor, tente novamente.');
} finally {
elements.createSession.disabled = false;
elements.createSession.innerHTML = `
<i class="icon" data-lucide="play"></i>
Criar e Iniciar
`;
lucide.createIcons();
}
});
elements.sessionNameInput.addEventListener('input', (e) => {
currentSessionName = e.target.value;
elements.createSession.disabled = !currentSessionName.trim();
});
elements.cancelNewSession.addEventListener('click', () => {
elements.newSessionForm.classList.add('hidden');
elements.sessionNameInput.value = '';
currentSessionName = '';
elements.createSession.disabled = true;
});
elements.activeSessionsTab.addEventListener('click', () => setActiveTab('active-sessions'));
elements.finishedSessionsTab.addEventListener('click', () => setActiveTab('finished-sessions'));
elements.playersTab.addEventListener('click', () => setActiveTab('players'));
elements.newSessionBtn.addEventListener('click', () => {
elements.newSessionForm.classList.remove('hidden');
elements.sessionNameInput.focus();
});
elements.newSessionEmptyBtn.addEventListener('click', () => {
elements.newSessionForm.classList.remove('hidden');
elements.sessionNameInput.focus();
});
elements.addPlayersBtn.addEventListener('click', viewAllPlayers);
elements.allPlayersBtn.addEventListener('click', viewAllPlayers);
elements.resetDataBtn.addEventListener('click', () => {
elements.resetDialog.classList.remove('hidden');
elements.resetPassword.focus();
});
elements.resetPassword.addEventListener('input', (e) => {
elements.passwordError.classList.add('hidden');
elements.confirmReset.disabled = !e.target.value;
});
elements.cancelReset.addEventListener('click', () => {
elements.resetDialog.classList.add('hidden');
elements.resetPassword.value = '';
elements.passwordError.classList.add('hidden');
elements.confirmReset.disabled = true;
});
elements.confirmReset.addEventListener('click', async () => {
if (elements.resetPassword.value !== '452631') {
elements.passwordError.classList.remove('hidden');
return;
}
elements.confirmReset.disabled = true;
elements.confirmReset.innerHTML = `
<div class="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>
Resetando...
`;
try {
await resetAllData();
alert('Dados resetados com sucesso!');
// Close dialog
elements.resetDialog.classList.add('hidden');
elements.resetPassword.value = '';
elements.passwordError.classList.add('hidden');
// Refresh the view (would reload data in a real app)
setActiveTab(activeTab);
} catch (error) {
console.error('Error resetting data:', error);
alert('Erro ao resetar dados. Por favor, tente novamente.');
} finally {
elements.confirmReset.disabled = false;
elements.confirmReset.innerHTML = 'Confirmar Reset';
}
});
elements.retryBtn.addEventListener('click', () => {
setActiveTab(activeTab);
});
// Simulate loading user data
setTimeout(() => {
elements.userEmail.textContent = mockUser.email;
elements.newSessionBtn.disabled = false;
elements.resetDataBtn.disabled = false;
// Load initial content
setActiveTab('active-sessions');
}, 1500);
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body>
</html>