Spaces:
Running
Running
| <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> |