dash2 / index.html
castro777's picture
Add 2 files
0072178 verified
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Gerenciador de Sessão de Poker</title>
<!-- Import Lucide Icons -->
<script src="https://unpkg.com/lucide@latest"></script>
<style>
:root {
--primary: #3b82f6;
--primary-hover: #2563eb;
--danger: #ef4444;
--danger-hover: #dc2626;
--success: #22c55e;
--success-hover: #16a34a;
--warning: #f59e0b;
--warning-hover: #d97706;
--dark: #1e293b;
--light: #f8fafc;
--gray: #64748b;
--gray-light: #e2e8f0;
--red-dark: #991b1b;
--red-light: #fef2f2;
--green-dark: #166534;
--green-light: #f0fdf4;
--border-radius: 0.5rem;
--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
--transition: all 0.3s ease;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background-color: #f1f5f9;
color: var(--dark);
line-height: 1.6;
padding: 1rem;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 1rem;
}
/* Header Styles */
.header {
display: flex;
flex-direction: column;
gap: 1rem;
margin-bottom: 1.5rem;
}
.header h1 {
font-size: 1.75rem;
font-weight: 700;
color: var(--dark);
}
.header p {
color: var(--gray);
font-size: 0.875rem;
}
/* Button Styles */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.5rem 1rem;
border-radius: var(--border-radius);
font-weight: 500;
font-size: 0.875rem;
cursor: pointer;
transition: var(--transition);
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-warning {
background-color: var(--warning);
color: white;
}
.btn-warning:hover {
background-color: var(--warning-hover);
}
.btn-outline {
background-color: transparent;
border-color: var(--gray-light);
color: var(--dark);
}
.btn-outline:hover {
background-color: var(--gray-light);
}
.btn-icon {
margin-right: 0.5rem;
}
/* Quick Actions */
.quick-actions {
display: flex;
gap: 0.5rem;
margin-bottom: 1.5rem;
flex-wrap: wrap;
}
/* Grid Layout */
.grid {
display: grid;
gap: 1rem;
}
.grid-cols-1 {
grid-template-columns: repeat(1, 1fr);
}
.grid-cols-2 {
grid-template-columns: repeat(2, 1fr);
}
.grid-cols-3 {
grid-template-columns: repeat(3, 1fr);
}
/* Player Card */
.player-card {
background-color: white;
border-radius: var(--border-radius);
box-shadow: var(--shadow);
overflow: hidden;
transition: var(--transition);
}
.player-card:hover {
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
.player-header {
background-color: var(--primary);
color: white;
padding: 1rem;
position: relative;
}
.player-name {
font-weight: 600;
font-size: 1.125rem;
}
.player-balance {
font-size: 1.5rem;
font-weight: 700;
margin: 0.5rem 0;
}
.player-content {
padding: 1rem;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0.5rem;
}
.player-stat {
display: flex;
flex-direction: column;
align-items: center;
}
.stat-label {
font-size: 0.75rem;
color: var(--gray);
margin-bottom: 0.25rem;
}
.stat-value {
font-weight: 600;
}
.player-actions {
display: flex;
gap: 0.5rem;
padding: 0 1rem 1rem;
}
.player-actions .btn {
flex: 1;
font-size: 0.75rem;
padding: 0.25rem 0.5rem;
}
/* Summary Card */
.summary-card {
background-color: white;
border-radius: var(--border-radius);
box-shadow: var(--shadow);
padding: 1rem;
margin-top: 1.5rem;
}
.summary-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.summary-title {
font-weight: 600;
font-size: 1.125rem;
}
.summary-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
}
.summary-item {
display: flex;
justify-content: space-between;
padding: 0.5rem 0;
border-bottom: 1px solid var(--gray-light);
}
.summary-item-label {
color: var(--gray);
}
.summary-item-value {
font-weight: 600;
}
.summary-total {
font-size: 1.25rem;
font-weight: 700;
color: var(--primary);
margin-top: 1rem;
padding-top: 1rem;
border-top: 1px solid var(--gray-light);
}
/* Loading State */
.loading {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
}
.spinner {
width: 3rem;
height: 3rem;
border: 3px solid transparent;
border-top-color: var(--primary);
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 1rem;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* Error State */
.error-card {
background-color: var(--red-light);
border: 1px solid var(--danger);
border-radius: var(--border-radius);
padding: 2rem;
text-align: center;
max-width: 600px;
margin: 2rem auto;
}
.error-icon {
color: var(--danger);
width: 3rem;
height: 3rem;
margin-bottom: 1rem;
}
.error-title {
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 1rem;
color: var(--danger);
}
.error-message {
margin-bottom: 1.5rem;
color: var(--red-dark);
}
.error-actions {
display: flex;
gap: 1rem;
justify-content: center;
}
/* Modal Styles */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal {
background-color: white;
border-radius: var(--border-radius);
width: 90%;
max-width: 500px;
max-height: 90vh;
overflow-y: auto;
padding: 1.5rem;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
}
.modal-title {
font-size: 1.25rem;
font-weight: 600;
}
.modal-close {
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
color: var(--gray);
}
.form-group {
margin-bottom: 1rem;
}
.form-label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
}
.form-input {
width: 100%;
padding: 0.5rem;
border: 1px solid var(--gray-light);
border-radius: var(--border-radius);
font-size: 1rem;
}
.form-select {
width: 100%;
padding: 0.5rem;
border: 1px solid var(--gray-light);
border-radius: var(--border-radius);
font-size: 1rem;
background-color: white;
}
.modal-footer {
display: flex;
justify-content: flex-end;
gap: 0.5rem;
margin-top: 1.5rem;
}
/* Utilities */
.flex {
display: flex;
}
.flex-col {
flex-direction: column;
}
.items-center {
align-items: center;
}
.justify-center {
justify-content: center;
}
.justify-between {
justify-content: space-between;
}
.gap-1 {
gap: 0.25rem;
}
.gap-2 {
gap: 0.5rem;
}
.gap-4 {
gap: 1rem;
}
.mt-1 {
margin-top: 0.25rem;
}
.mt-2 {
margin-top: 0.5rem;
}
.mt-4 {
margin-top: 1rem;
}
.mb-1 {
margin-bottom: 0.25rem;
}
.mb-2 {
margin-bottom: 0.5rem;
}
.mb-4 {
margin-bottom: 1rem;
}
.p-4 {
padding: 1rem;
}
.text-center {
text-align: center;
}
/* Responsive Adjustments */
@media (min-width: 640px) {
.header {
flex-direction: row;
align-items: center;
}
.quick-actions {
flex-wrap: nowrap;
}
}
@media (max-width: 768px) {
.grid-cols-2,
.grid-cols-3 {
grid-template-columns: repeat(1, 1fr);
}
.summary-grid {
grid-template-columns: repeat(1, 1fr);
}
}
</style>
</head>
<body>
<div class="container" id="app">
<!-- Loading state will be inserted here by JavaScript -->
</div>
<script>
document.addEventListener('DOMContentLoaded', async () => {
// Initialize Lucide icons
lucide.createIcons();
// Simulate loading initial data
const app = document.getElementById('app');
// Show loading state
app.innerHTML = `
<div class="loading">
<div class="spinner"></div>
<p class="text-gray-400">Carregando sessão...</p>
</div>
`;
// Simulate network request delay
await new Promise(resolve => setTimeout(resolve, 1500));
// Simulated data
const currentSession = {
id: 'session-123',
name: 'Sessão VIP - Torneio Mensal',
startTime: new Date().toISOString(),
isActive: true
};
const players = [
{ id: 'player-1', name: 'João Silva', buyins: 500, cashouts: 200, payments: 50, pendingAmount: 250 },
{ id: 'player-2', name: 'Maria Oliveira', buyins: 300, cashouts: 150, payments: 100, pendingAmount: 50 },
{ id: 'player-3', name: 'Carlos Mendes', buyins: 1000, cashouts: 500, payments: 200, pendingAmount: 300 },
{ id: 'player-4', name: 'Ana Souza', buyins: 700, cashouts: 300, payments: 150, pendingAmount: 250 },
{ id: 'player-5', name: 'Pedro Rocha', buyins: 200, cashouts: 100, payments: 75, pendingAmount: 25 }
];
const sessionSummary = {
chipsInPlay: 1500,
totalBuyins: 2700,
totalCashouts: 1250,
totalPayments: 575,
cashReceived: 1200,
cashPaid: 800,
pixReceived: 500,
pixPaid: 200,
creditReceived: 300,
creditPaid: 150,
debitReceived: 200,
debitPaid: 100,
pendingToReceive: 500,
pendingToPay: 250
};
const chipSets = [
{ id: 'chip-1', value: 1, quantity: 50 },
{ id: 'chip-2', value: 5, quantity: 40 },
{ id: 'chip-3', value: 10, quantity: 30 },
{ id: 'chip-4', value: 25, quantity: 20 },
{ id: 'chip-5', value: 50, quantity: 10 },
{ id: 'chip-6', value: 100, quantity: 5 }
];
const chipSetTotal = chipSets.reduce((total, chip) => total + (chip.value * chip.quantity), 0);
// State management
let state = {
currentSession,
players,
sessionSummary,
chipSets,
chipSetTotal,
hidePlayersValues: false,
hideSummaryValues: false,
selectedPlayerId: null,
modals: {
addPlayer: false,
buyChips: false,
cashout: false,
payment: false,
security: false,
log: false
},
securityMode: 'players'
};
// Helper functions
function formatDate(dateString) {
const date = new Date(dateString);
return date.toLocaleDateString('pt-BR', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
}
function formatCurrency(amount) {
return new Intl.NumberFormat('pt-BR', {
style: 'currency',
currency: 'BRL'
}).format(amount);
}
// Toggle modal visibility
function toggleModal(modalName, isOpen) {
state.modals[modalName] = isOpen;
render();
}
function setSecurityMode(mode) {
state.securityMode = mode;
toggleModal('security', true);
}
function toggleHideValues(value) {
if (state.securityMode === 'players') {
state.hidePlayersValues = value;
localStorage.setItem('hidePlayersValues', JSON.stringify(value));
} else {
state.hideSummaryValues = value;
localStorage.setItem('hideSummaryValues', JSON.stringify(value));
}
toggleModal('security', false);
}
// Event handlers
function handleAddPlayer(name) {
const newPlayer = {
id: `player-${Date.now()}`,
name,
buyins: 0,
cashouts: 0,
payments: 0,
pendingAmount: 0
};
state.players = [...state.players, newPlayer];
toggleModal('addPlayer', false);
render();
}
function handleBuyChips({ playerId, amount, payNow, paymentMethod }) {
const playerIndex = state.players.findIndex(p => p.id === playerId);
if (playerIndex !== -1) {
const updatedPlayer = {
...state.players[playerIndex],
buyins: state.players[playerIndex].buyins + amount,
pendingAmount: payNow ?
state.players[playerIndex].pendingAmount :
state.players[playerIndex].pendingAmount + amount
};
const updatedPlayers = [...state.players];
updatedPlayers[playerIndex] = updatedPlayer;
state.players = updatedPlayers;
// Update session summary
state.sessionSummary = {
...state.sessionSummary,
totalBuyins: state.sessionSummary.totalBuyins + amount,
chipsInPlay: state.sessionSummary.chipsInPlay + amount,
...(payNow && {
cashReceived: paymentMethod === 'cash' ?
state.sessionSummary.cashReceived + amount :
state.sessionSummary.cashReceived,
pixReceived: paymentMethod === 'pix' ?
state.sessionSummary.pixReceived + amount :
state.sessionSummary.pixReceived,
creditReceived: paymentMethod === 'credit' ?
state.sessionSummary.creditReceived + amount :
state.sessionSummary.creditReceived,
debitReceived: paymentMethod === 'debit' ?
state.sessionSummary.debitReceived + amount :
state.sessionSummary.debitReceived
}),
...(!payNow && {
pendingToReceive: state.sessionSummary.pendingToReceive + amount
})
};
}
toggleModal('buyChips', false);
render();
}
function handleCashout({ playerId, amount, payNow, paymentMethod }) {
const playerIndex = state.players.findIndex(p => p.id === playerId);
if (playerIndex !== -1) {
const updatedPlayer = {
...state.players[playerIndex],
cashouts: state.players[playerIndex].cashouts + amount,
pendingAmount: payNow ?
state.players[playerIndex].pendingAmount - amount :
state.players[playerIndex].pendingAmount
};
const updatedPlayers = [...state.players];
updatedPlayers[playerIndex] = updatedPlayer;
state.players = updatedPlayers;
// Update session summary
state.sessionSummary = {
...state.sessionSummary,
totalCashouts: state.sessionSummary.totalCashouts + amount,
chipsInPlay: state.sessionSummary.chipsInPlay - amount,
...(payNow && {
cashPaid: paymentMethod === 'cash' ?
state.sessionSummary.cashPaid + amount :
state.sessionSummary.cashPaid,
pixPaid: paymentMethod === 'pix' ?
state.sessionSummary.pixPaid + amount :
state.sessionSummary.pixPaid,
creditPaid: paymentMethod === 'credit' ?
state.sessionSummary.creditPaid + amount :
state.sessionSummary.creditPaid,
debitPaid: paymentMethod === 'debit' ?
state.sessionSummary.debitPaid + amount :
state.sessionSummary.debitPaid
}),
...(!payNow && {
pendingToPay: state.sessionSummary.pendingToPay + amount
})
};
}
toggleModal('cashout', false);
render();
}
function handlePayment({ playerId, amount, paymentMethod, direction }) {
const playerIndex = state.players.findIndex(p => p.id === playerId);
if (playerIndex !== -1) {
const paymentAmount = direction === 'in' ? amount : -amount;
const updatedPlayer = {
...state.players[playerIndex],
payments: state.players[playerIndex].payments + paymentAmount,
pendingAmount: direction === 'in' ?
Math.max(0, state.players[playerIndex].pendingAmount - amount) :
Math.min(0, state.players[playerIndex].pendingAmount - amount)
};
const updatedPlayers = [...state.players];
updatedPlayers[playerIndex] = updatedPlayer;
state.players = updatedPlayers;
// Update session summary
state.sessionSummary = {
...state.sessionSummary,
totalPayments: state.sessionSummary.totalPayments + amount,
...(direction === 'in' && {
cashReceived: paymentMethod === 'cash' ?
state.sessionSummary.cashReceived + amount :
state.sessionSummary.cashReceived,
pixReceived: paymentMethod === 'pix' ?
state.sessionSummary.pixReceived + amount :
state.sessionSummary.pixReceived,
creditReceived: paymentMethod === 'credit' ?
state.sessionSummary.creditReceived + amount :
state.sessionSummary.creditReceived,
debitReceived: paymentMethod === 'debit' ?
state.sessionSummary.debitReceived + amount :
state.sessionSummary.debitReceived,
pendingToReceive: Math.max(0, state.sessionSummary.pendingToReceive - amount)
}),
...(direction === 'out' && {
cashPaid: paymentMethod === 'cash' ?
state.sessionSummary.cashPaid + amount :
state.sessionSummary.cashPaid,
pixPaid: paymentMethod === 'pix' ?
state.sessionSummary.pixPaid + amount :
state.sessionSummary.pixPaid,
creditPaid: paymentMethod === 'credit' ?
state.sessionSummary.creditPaid + amount :
state.sessionSummary.creditPaid,
debitPaid: paymentMethod === 'debit' ?
state.sessionSummary.debitPaid + amount :
state.sessionSummary.debitPaid,
pendingToPay: Math.max(0, state.sessionSummary.pendingToPay - amount)
})
};
}
toggleModal('payment', false);
render();
}
function updateChipSets(updatedChipSets) {
state.chipSets = updatedChipSets;
state.chipSetTotal = updatedChipSets.reduce((total, chip) => total + (chip.value * chip.quantity), 0);
render();
}
// Component rendering functions
function renderPlayerCard(player) {
const balance = player.buyins - player.cashouts + player.payments;
return `
<div class="player-card">
<div class="player-header">
<div class="player-name">${player.name}</div>
<div class="player-balance">
${state.hidePlayersValues ? '••••' : formatCurrency(balance)}
</div>
</div>
<div class="player-content">
<div class="player-stat">
<span class="stat-label">Buy-ins</span>
<span class="stat-value">
${state.hidePlayersValues ? '•••' : formatCurrency(player.buyins)}
</span>
</div>
<div class="player-stat">
<span class="stat-label">Cashouts</span>
<span class="stat-value">
${state.hidePlayersValues ? '•••' : formatCurrency(player.cashouts)}
</span>
</div>
<div class="player-stat">
<span class="stat-label">Saldo Pendente</span>
<span class="stat-value">
${state.hidePlayersValues ? '•••' : formatCurrency(player.pendingAmount)}
</span>
</div>
</div>
<div class="player-actions">
<button class="btn btn-primary"
onclick="state.selectedPlayerId='${player.id}'; toggleModal('buyChips', true)">
<i data-lucide="plus-circle" class="btn-icon"></i>
Comprar Fichas
</button>
<button class="btn btn-success"
onclick="state.selectedPlayerId='${player.id}'; toggleModal('cashout', true)">
<i data-lucide="dollar-sign" class="btn-icon"></i>
Cashout
</button>
<button class="btn btn-warning"
onclick="state.selectedPlayerId='${player.id}'; toggleModal('payment', true)">
<i data-lucide="credit-card" class="btn-icon"></i>
Pagamento
</button>
</div>
</div>
`;
}
function renderQuickActions() {
return `
<div class="quick-actions">
<button class="btn btn-primary" onclick="toggleModal('addPlayer', true)">
<i data-lucide="user-plus" class="btn-icon"></i>
Adicionar Jogador
</button>
<button class="btn btn-success" onclick="state.selectedPlayerId=null; toggleModal('buyChips', true)">
<i data-lucide="plus-circle" class="btn-icon"></i>
Comprar Fichas
</button>
<button class="btn btn-warning" onclick="state.selectedPlayerId=null; toggleModal('cashout', true)">
<i data-lucide="dollar-sign" class="btn-icon"></i>
Cashout
</button>
<button class="btn btn-danger" onclick="toggleModal('log', true)">
<i data-lucide="list" class="btn-icon"></i>
Log da Sessão
</button>
</div>
`;
}
function renderSessionSummary() {
const {
chipsInPlay,
totalBuyins,
totalCashouts,
totalPayments,
cashReceived,
cashPaid,
pixReceived,
pixPaid,
creditReceived,
creditPaid,
debitReceived,
debitPaid,
pendingToReceive,
pendingToPay
} = state.sessionSummary;
return `
<div class="summary-card">
<div class="summary-header">
<h3 class="summary-title">Resumo da Sessão</h3>
<button class="btn ${state.hideSummaryValues ? 'btn-outline' : 'btn-success'}"
onclick="setSecurityMode('summary')">
<i data-lucide="${state.hideSummaryValues ? 'eye-off' : 'eye'}" class="btn-icon"></i>
${state.hideSummaryValues ? 'Mostrar' : 'Ocultar'}
</button>
</div>
<div class="summary-grid">
<div class="summary-item">
<span class="summary-item-label">Fichas em Jogo</span>
<span class="summary-item-value">
${state.hideSummaryValues ? '••••' : formatCurrency(chipsInPlay)}
</span>
</div>
<div class="summary-item">
<span class="summary-item-label">Total Buy-ins</span>
<span class="summary-item-value">
${state.hideSummaryValues ? '••••' : formatCurrency(totalBuyins)}
</span>
</div>
<div class="summary-item">
<span class="summary-item-label">Total Cashouts</span>
<span class="summary-item-value">
${state.hideSummaryValues ? '••••' : formatCurrency(totalCashouts)}
</span>
</div>
<div class="summary-item">
<span class="summary-item-label">Total Pagamentos</span>
<span class="summary-item-value">
${state.hideSummaryValues ? '••••' : formatCurrency(totalPayments)}
</span>
</div>
<div class="summary-item">
<span class="summary-item-label">Caixa (Dinheiro)</span>
<span class="summary-item-value">
${state.hideSummaryValues ? '••••' : formatCurrency(cashReceived - cashPaid)}
</span>
</div>
<div class="summary-item">
<span class="summary-item-label">PIX Líquido</span>
<span class="summary-item-value">
${state.hideSummaryValues ? '••••' : formatCurrency(pixReceived - pixPaid)}
</span>
</div>
<div class="summary-item">
<span class="summary-item-label">Crédito Líquido</span>
<span class="summary-item-value">
${state.hideSummaryValues ? '••••' : formatCurrency(creditReceived - creditPaid)}
</span>
</div>
<div class="summary-item">
<span class="summary-item-label">Débito Líquido</span>
<span class="summary-item-value">
${state.hideSummaryValues ? '••••' : formatCurrency(debitReceived - debitPaid)}
</span>
</div>
<div class="summary-item">
<span class="summary-item-label">A Receber</span>
<span class="summary-item-value">
${state.hideSummaryValues ? '••••' : formatCurrency(pendingToReceive)}
</span>
</div>
<div class="summary-item">
<span class="summary-item-label">A Pagar</span>
<span class="summary-item-value">
${state.hideSummaryValues ? '••••' : formatCurrency(pendingToPay)}
</span>
</div>
</div>
<div class="summary-total mt-4 text-center">
Total em Fichas: ${state.hideSummaryValues ? '••••' : formatCurrency(state.chipSetTotal)}
</div>
</div>
`;
}
function renderAddPlayerModal() {
return `
<div class="modal-overlay" ${state.modals.addPlayer ? '' : 'style="display: none;"'}>
<div class="modal">
<div class="modal-header">
<h3 class="modal-title">Adicionar Jogador</h3>
<button class="modal-close" onclick="toggleModal('addPlayer', false)">&times;</button>
</div>
<form id="addPlayerForm" onsubmit="event.preventDefault();
const name = document.getElementById('playerName').value;
handleAddPlayer(name);">
<div class="form-group">
<label for="playerName" class="form-label">Nome do Jogador</label>
<input type="text" id="playerName" class="form-input" required autofocus>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline" onclick="toggleModal('addPlayer', false)">
Cancelar
</button>
<button type="submit" class="btn btn-primary">
Adicionar
</button>
</div>
</form>
</div>
</div>
`;
}
function renderBuyChipsModal() {
const player = state.selectedPlayerId ?
state.players.find(p => p.id === state.selectedPlayerId) : null;
return `
<div class="modal-overlay" ${state.modals.buyChips ? '' : 'style="display: none;"'}>
<div class="modal">
<div class="modal-header">
<h3 class="modal-title">
${player ? `Comprar Fichas - ${player.name}` : 'Comprar Fichas'}
</h3>
<button class="modal-close" onclick="toggleModal('buyChips', false)">&times;</button>
</div>
<form id="buyChipsForm" onsubmit="event.preventDefault();
const formData = new FormData(document.getElementById('buyChipsForm'));
handleBuyChips({
playerId: '${state.selectedPlayerId || ''}',
amount: parseFloat(formData.get('amount')),
payNow: formData.get('payNow') === 'true',
paymentMethod: formData.get('paymentMethod')
});">
${!player ? `
<div class="form-group">
<label for="playerSelect" class="form-label">Jogador</label>
<select id="playerSelect" name="playerId" class="form-select" required>
<option value="">Selecione um jogador</option>
${state.players.map(p => `
<option value="${p.id}">${p.name}</option>
`).join('')}
</select>
</div>
` : ''}
<div class="form-group">
<label for="amount" class="form-label">Valor</label>
<input type="number" id="amount" name="amount"
class="form-input" min="1" step="0.01" required>
</div>
<div class="form-group">
<label class="form-label">Forma de Pagamento</label>
<select name="paymentMethod" class="form-select" required>
<option value="cash">Dinheiro</option>
<option value="pix">PIX</option>
<option value="credit">Crédito</option>
<option value="debit">Débito</option>
</select>
</div>
<div class="form-group">
<label class="form-label">Status do Pagamento</label>
<div class="flex gap-2">
<label class="flex items-center gap-1">
<input type="radio" name="payNow" value="true" checked>
Pagamento Recebido
</label>
<label class="flex items-center gap-1">
<input type="radio" name="payNow" value="false">
Pendente
</label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline"
onclick="toggleModal('buyChips', false)">
Cancelar
</button>
<button type="submit" class="btn btn-primary">
Confirmar
</button>
</div>
</form>
</div>
</div>
`;
}
function renderCashoutModal() {
const player = state.selectedPlayerId ?
state.players.find(p => p.id === state.selectedPlayerId) : null;
return `
<div class="modal-overlay" ${state.modals.cashout ? '' : 'style="display: none;"'}>
<div class="modal">
<div class="modal-header">
<h3 class="modal-title">
${player ? `Cashout - ${player.name}` : 'Cashout'}
</h3>
<button class="modal-close" onclick="toggleModal('cashout', false)">&times;</button>
</div>
<form id="cashoutForm" onsubmit="event.preventDefault();
const formData = new FormData(document.getElementById('cashoutForm'));
handleCashout({
playerId: '${state.selectedPlayerId || ''}',
amount: parseFloat(formData.get('amount')),
payNow: formData.get('payNow') === 'true',
paymentMethod: formData.get('paymentMethod')
});">
${!player ? `
<div class="form-group">
<label for="playerSelect" class="form-label">Jogador</label>
<select id="playerSelect" name="playerId" class="form-select" required>
<option value="">Selecione um jogador</option>
${state.players.map(p => `
<option value="${p.id}">${p.name}</option>
`).join('')}
</select>
</div>
` : ''}
<div class="form-group">
<label for="amount" class="form-label">Valor</label>
<input type="number" id="amount" name="amount"
class="form-input" min="1" step="0.01" required>
</div>
<div class="form-group">
<label class="form-label">Forma de Pagamento</label>
<select name="paymentMethod" class="form-select" required>
<option value="cash">Dinheiro</option>
<option value="pix">PIX</option>
<option value="credit">Crédito</option>
<option value="debit">Débito</option>
</select>
</div>
<div class="form-group">
<label class="form-label">Status do Pagamento</label>
<div class="flex gap-2">
<label class="flex items-center gap-1">
<input type="radio" name="payNow" value="true" checked>
Pagamento Efetuado
</label>
<label class="flex items-center gap-1">
<input type="radio" name="payNow" value="false">
Pendente
</label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline"
onclick="toggleModal('cashout', false)">
Cancelar
</button>
<button type="submit" class="btn btn-success">
Confirmar
</button>
</div>
</form>
</div>
</div>
`;
}
function renderPaymentModal() {
const player = state.selectedPlayerId ?
state.players.find(p => p.id === state.selectedPlayerId) : null;
return `
<div class="modal-overlay" ${state.modals.payment ? '' : 'style="display: none;"'}>
<div class="modal">
<div class="modal-header">
<h3 class="modal-title">
${player ? `Pagamento - ${player.name}` : 'Pagamento'}
</h3>
<button class="modal-close" onclick="toggleModal('payment', false)">&times;</button>
</div>
<form id="paymentForm" onsubmit="event.preventDefault();
const formData = new FormData(document.getElementById('paymentForm'));
handlePayment({
playerId: '${state.selectedPlayerId || ''}',
amount: parseFloat(formData.get('amount')),
paymentMethod: formData.get('paymentMethod'),
direction: formData.get('direction')
});">
${!player ? `
<div class="form-group">
<label for="playerSelect" class="form-label">Jogador</label>
<select id="playerSelect" name="playerId" class="form-select" required>
<option value="">Selecione um jogador</option>
${state.players.map(p => `
<option value="${p.id}">${p.name}</option>
`).join('')}
</select>
</div>
` : ''}
<div class="form-group">
<label for="amount" class="form-label">Valor</label>
<input type="number" id="amount" name="amount"
class="form-input" min="1" step="0.01" required>
</div>
<div class="form-group">
<label class="form-label">Direção</label>
<div class="flex gap-2">
<label class="flex items-center gap-1">
<input type="radio" name="direction" value="in" checked>
Recebimento
</label>
<label class="flex items-center gap-1">
<input type="radio" name="direction" value="out">
Pagamento
</label>
</div>
</div>
<div class="form-group">
<label class="form-label">Forma de Pagamento</label>
<select name="paymentMethod" class="form-select" required>
<option value="cash">Dinheiro</option>
<option value="pix">PIX</option>
<option value="credit">Crédito</option>
<option value="debit">Débito</option>
</select>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline"
onclick="toggleModal('payment', false)">
Cancelar
</button>
<button type="submit" class="btn btn-success">
Confirmar
</button>
</div>
</form>
</div>
</div>
`;
}
function renderSecurityModal() {
return `
<div class="modal-overlay" ${state.modals.security ? '' : 'style="display: none;"'}>
<div class="modal">
<div class="modal-header">
<h3 class="modal-title">
Ocultar Valores - ${state.securityMode === 'players' ? 'Jogadores' : 'Resumo'}
</h3>
<button class="modal-close" onclick="toggleModal('security', false)">&times;</button>
</div>
<div class="p-4">
<p class="mb-4">
${state.securityMode === 'players' ?
'Deseja ocultar os valores dos jogadores para que outras pessoas não vejam?' :
'Deseja ocultar os valores do resumo da sessão para que outras pessoas não vejam?'}
</p>
<div class="flex justify-center gap-4">
<button class="btn btn-outline"
onclick="toggleHideValues(false)">
<i data-lucide="eye" class="btn-icon"></i>
Manter Visível
</button>
<button class="btn btn-danger"
onclick="toggleHideValues(true)">
<i data-lucide="eye-off" class="btn-icon"></i>
Ocultar Valores
</button>
</div>
</div>
</div>
</div>
`;
}
function renderLogModal() {
// Simulated log entries
const logEntries = [
{ id: 'log-1', type: 'player_join', playerName: 'João Silva', description: 'Jogador João Silva adicionado à sessão', timestamp: new Date().toISOString() },
{ id: 'log-2', type: 'buyin', playerName: 'Maria Oliveira', description: 'Buy-in de R$ 300.00 via pix', timestamp: new Date(Date.now() - 3600000).toISOString() },
{ id: 'log-3', type: 'cashout', playerName: 'Carlos Mendes', description: 'Cashout de R$ 500.00 via cash', timestamp: new Date(Date.now() - 7200000).toISOString() },
{ id: 'log-4', type: 'payment', playerName: 'Ana Souza', description: 'Recebimento de R$ 150.00 via credit', timestamp: new Date(Date.now() - 10800000).toISOString() }
];
return `
<div class="modal-overlay" ${state.modals.log ? '' : 'style="display: none;"'}>
<div class="modal" style="max-width: 800px;">
<div class="modal-header">
<h3 class="modal-title">Log da Sessão</h3>
<button class="modal-close" onclick="toggleModal('log', false)">&times;</button>
</div>
<div style="max-height: 60vh; overflow-y: auto;">
<table style="width: 100%; border-collapse: collapse;">
<thead>
<tr style="background-color: #f8fafc;">
<th style="padding: 0.75rem; text-align: left; border-bottom: 1px solid #e2e8f0;">Data/Hora</th>
<th style="padding: 0.75rem; text-align: left; border-bottom: 1px solid #e2e8f0;">Tipo</th>
<th style="padding: 0.75rem; text-align: left; border-bottom: 1px solid #e2e8f0;">Jogador</th>
<th style="padding: 0.75rem; text-align: left; border-bottom: 1px solid #e2e8f0;">Descrição</th>
</tr>
</thead>
<tbody>
${logEntries.map(log => `
<tr>
<td style="padding: 0.75rem; border-bottom: 1px solid #e2e8f0;">
${formatDate(log.timestamp)}
</td>
<td style="padding: 0.75rem; border-bottom: 1px solid #e2e8f0;">
${log.type === 'player_join' ? 'Entrada' :
log.type === 'buyin' ? 'Buy-in' :
log.type === 'cashout' ? 'Cashout' :
'Pagamento'}
</td>
<td style="padding: 0.75rem; border-bottom: 1px solid #e2e8f0;">
${log.playerName}
</td>
<td style="padding: 0.75rem; border-bottom: 1px solid #e2e8f0;">
${log.description}
</td>
</tr>
`).join('')}
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline"
onclick="toggleModal('log', false)">
Fechar
</button>
</div>
</div>
</div>
`;
}
// Main render function
function render() {
app.innerHTML = `
<div>
<div class="header">
<div>
<h1>${state.currentSession.name}</h1>
<p>Iniciada em ${formatDate(state.currentSession.startTime)}</p>
</div>
<div class="flex flex-wrap gap-2">
<button class="btn ${state.hidePlayersValues ? 'btn-outline' : 'btn-success'}"
onclick="setSecurityMode('players')">
<i data-lucide="${state.hidePlayersValues ? 'eye-off' : 'eye'}" class="btn-icon"></i>
Jogadores
</button>
<button class="btn ${state.hideSummaryValues ? 'btn-outline' : 'btn-success'}"
onclick="setSecurityMode('summary')">
<i data-lucide="${state.hideSummaryValues ? 'eye-off' : 'eye'}" class="btn-icon"></i>
Resumo
</button>
</div>
</div>
${renderQuickActions()}
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 mt-6">
${state.players.map(player => renderPlayerCard(player)).join('')}
</div>
${renderSessionSummary()}
${renderAddPlayerModal()}
${renderBuyChipsModal()}
${renderCashoutModal()}
${renderPaymentModal()}
${renderSecurityModal()}
${renderLogModal()}
</div>
`;
// Refresh Lucide icons after rendering
lucide.createIcons();
}
// Initial render
render();
// Set references to functions in global scope for event handlers
window.state = state;
window.toggleModal = toggleModal;
window.setSecurityMode = setSecurityMode;
window.toggleHideValues = toggleHideValues;
window.handleAddPlayer = handleAddPlayer;
window.handleBuyChips = handleBuyChips;
window.handleCashout = handleCashout;
window.handlePayment = handlePayment;
window.updateChipSets = updateChipSets;
});
</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>