versao 2
This commit is contained in:
parent
3be22ccb94
commit
a0c63edc92
128
budgets.php
Normal file
128
budgets.php
Normal file
@ -0,0 +1,128 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
// Proteger a página
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$pdo = db();
|
||||
$error_message = '';
|
||||
$success_message = '';
|
||||
|
||||
// Definir o mês do orçamento (padrão para o mês atual)
|
||||
$budget_month_str = $_GET['month'] ?? date('Y-m');
|
||||
$budget_month_date = date('Y-m-01', strtotime($budget_month_str . '-01'));
|
||||
|
||||
// Lógica para salvar/atualizar orçamentos
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$budgets = $_POST['budgets'] ?? [];
|
||||
$posted_month = $_POST['budget_month'] ?? $budget_month_date;
|
||||
|
||||
try {
|
||||
$sql = "INSERT INTO budgets (user_id, category, amount, budget_month) VALUES (:user_id, :category, :amount, :budget_month)
|
||||
ON DUPLICATE KEY UPDATE amount = :amount";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
|
||||
foreach ($budgets as $category => $amount) {
|
||||
if (is_numeric($amount) && $amount >= 0) {
|
||||
$stmt->execute([
|
||||
'user_id' => $user_id,
|
||||
'category' => $category,
|
||||
'amount' => $amount,
|
||||
'budget_month' => $posted_month
|
||||
]);
|
||||
}
|
||||
}
|
||||
$success_message = 'Orçamentos salvos com sucesso!';
|
||||
// Redirecionar para o mesmo mês para mostrar a atualização
|
||||
header('Location: budgets.php?month=' . date('Y-m', strtotime($posted_month)));
|
||||
exit;
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Erro ao salvar orçamentos: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// Buscar orçamentos existentes para o mês selecionado
|
||||
$existing_budgets = [];
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT category, amount FROM budgets WHERE user_id = :user_id AND budget_month = :budget_month");
|
||||
$stmt->execute(['user_id' => $user_id, 'budget_month' => $budget_month_date]);
|
||||
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
foreach ($results as $row) {
|
||||
$existing_budgets[$row['category']] = $row['amount'];
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error_message = "Erro ao buscar orçamentos existentes.";
|
||||
}
|
||||
|
||||
|
||||
// Categorias fixas
|
||||
$categories = ['Alimentação', 'Transporte', 'Moradia', 'Lazer', 'Saúde', 'Outros'];
|
||||
|
||||
include __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
|
||||
<div class="container mt-4">
|
||||
<h1 class="mb-4">Gerenciar Orçamentos</h1>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<!-- Seletor de Mês -->
|
||||
<form method="GET" action="budgets.php" class="mb-4">
|
||||
<div class="row align-items-end">
|
||||
<div class="col-md-4">
|
||||
<label for="month" class="form-label">Selecione o Mês</label>
|
||||
<input type="month" class="form-control" id="month" name="month" value="<?php echo htmlspecialchars($budget_month_str); ?>">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button type="submit" class="btn btn-primary">Carregar</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<hr>
|
||||
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (isset($_SESSION['success_message'])) {
|
||||
echo '<div class="alert alert-success">' . htmlspecialchars($_SESSION['success_message']) . '</div>';
|
||||
unset($_SESSION['success_message']);
|
||||
}?>
|
||||
|
||||
<!-- Formulário de Orçamentos -->
|
||||
<form method="POST" action="budgets.php">
|
||||
<input type="hidden" name="budget_month" value="<?php echo htmlspecialchars($budget_month_date); ?>">
|
||||
<h4 class="mb-3">Orçamentos para <?php echo date('F \d\e Y', strtotime($budget_month_date)); ?></h4>
|
||||
|
||||
<?php foreach ($categories as $category): ?>
|
||||
<div class="row mb-2 align-items-center">
|
||||
<div class="col-md-3">
|
||||
<label for="budget_<?php echo htmlspecialchars($category); ?>" class="form-label"><?php echo htmlspecialchars($category); ?></label>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">R$</span>
|
||||
<input type="number" step="0.01" class="form-control" id="budget_<?php echo htmlspecialchars($category); ?>"
|
||||
name="budgets[<?php echo htmlspecialchars($category); ?>]"
|
||||
value="<?php echo htmlspecialchars($existing_budgets[$category] ?? '0.00'); ?>">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<div class="d-grid mt-4">
|
||||
<button type="submit" class="btn btn-primary">Salvar Orçamentos</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include __DIR__ . '/includes/footer.php'; ?>
|
||||
@ -1,31 +1,66 @@
|
||||
<?php
|
||||
// Simples script para rodar migrações SQL
|
||||
// Script de migração aprimorado para rodar múltiplos arquivos SQL de forma idempotente.
|
||||
require_once __DIR__ . '/config.php';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$sql_file = __DIR__ . '/migrations/001_create_users_table.sql';
|
||||
$sql = file_get_contents($sql_file);
|
||||
|
||||
$pdo->exec($sql);
|
||||
// 1. Garantir que a tabela de controle de migrações exista
|
||||
$pdo->exec("CREATE TABLE IF NOT EXISTS `migrations` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`migration_name` VARCHAR(255) NOT NULL UNIQUE,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
|
||||
|
||||
echo "Migração '001_create_users_table.sql' executada com sucesso!\n";
|
||||
// 2. Obter migrações já executadas
|
||||
$executed_migrations_stmt = $pdo->query("SELECT migration_name FROM migrations");
|
||||
$executed_migrations = $executed_migrations_stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
// Criar hash de senha para o usuário de teste
|
||||
// 3. Encontrar todos os arquivos de migração
|
||||
$migration_files = glob(__DIR__ . '/migrations/*.sql');
|
||||
sort($migration_files);
|
||||
|
||||
$new_migrations_run = false;
|
||||
|
||||
// 4. Iterar e executar novas migrações
|
||||
foreach ($migration_files as $file) {
|
||||
$migration_name = basename($file);
|
||||
|
||||
if (!in_array($migration_name, $executed_migrations)) {
|
||||
echo "Executando migração: {$migration_name}...\n";
|
||||
|
||||
$sql = file_get_contents($file);
|
||||
$pdo->exec($sql);
|
||||
|
||||
// Registrar a migração como executada
|
||||
$stmt = $pdo->prepare("INSERT INTO migrations (migration_name) VALUES (:migration_name)");
|
||||
$stmt->execute(['migration_name' => $migration_name]);
|
||||
|
||||
echo "Migração '{$migration_name}' executada com sucesso!\n";
|
||||
|
||||
$new_migrations_run = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$new_migrations_run) {
|
||||
echo "Nenhuma nova migração para executar. O banco de dados já está atualizado.\n";
|
||||
} else {
|
||||
echo "\nMigrações concluídas.\n";
|
||||
}
|
||||
|
||||
// Lógica de atualização de senha do usuário de teste (executada sempre)
|
||||
// Garante que a senha seja corrigida mesmo que a migração inicial tenha falhado.
|
||||
$password = 'password123';
|
||||
$hash = password_hash($password, PASSWORD_DEFAULT);
|
||||
|
||||
// Atualizar o hash no SQL para garantir que é compatível com a versão do PHP
|
||||
// Força a atualização da senha para o usuário de teste, independentemente do valor atual.
|
||||
$update_hash_sql = "UPDATE users SET password_hash = :hash WHERE email = 'chefe@familia.com'";
|
||||
$stmt = $pdo->prepare($update_hash_sql);
|
||||
$stmt->execute(['hash' => $hash]);
|
||||
echo "Hash do usuário de teste atualizado no banco de dados.\n\n";
|
||||
$stmt_user = $pdo->prepare($update_hash_sql);
|
||||
$stmt_user->execute(['hash' => $hash]);
|
||||
|
||||
echo "Usuário de teste criado:\n";
|
||||
echo "Email: chefe@familia.com\n";
|
||||
echo "Senha: " . $password . "\n";
|
||||
if ($stmt_user->rowCount() > 0) {
|
||||
echo "Hash do usuário de teste foi corrigido para o valor padrão.\n";
|
||||
}
|
||||
|
||||
} catch (PDOException $e) {
|
||||
die("Erro na migração: " . $e->getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
10
db/migrations/002_create_expenses_table.sql
Normal file
10
db/migrations/002_create_expenses_table.sql
Normal file
@ -0,0 +1,10 @@
|
||||
CREATE TABLE IF NOT EXISTS `expenses` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`user_id` INT NOT NULL,
|
||||
`description` VARCHAR(255) NOT NULL,
|
||||
`amount` DECIMAL(10, 2) NOT NULL,
|
||||
`category` VARCHAR(100) NOT NULL,
|
||||
`expense_date` DATE NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
11
db/migrations/003_create_budgets_table.sql
Normal file
11
db/migrations/003_create_budgets_table.sql
Normal file
@ -0,0 +1,11 @@
|
||||
CREATE TABLE IF NOT EXISTS `budgets` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`user_id` INT NOT NULL,
|
||||
`category` VARCHAR(100) NOT NULL,
|
||||
`amount` DECIMAL(10, 2) NOT NULL,
|
||||
`budget_month` DATE NOT NULL, -- Stores the first day of the month, e.g., 2025-10-01
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE,
|
||||
UNIQUE KEY `user_category_month` (`user_id`, `category`, `budget_month`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
46
delete_expense.php
Normal file
46
delete_expense.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
// Proteger a página: redirecionar para o login se não estiver logado
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$expense_id = $_GET['id'] ?? null;
|
||||
$user_id = $_SESSION['user_id'];
|
||||
|
||||
if (!$expense_id) {
|
||||
// Se não houver ID, redireciona de volta
|
||||
header('Location: expenses.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
// A cláusula WHERE garante que um usuário só pode deletar suas próprias despesas
|
||||
$sql = "DELETE FROM expenses WHERE id = :id AND user_id = :user_id";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([
|
||||
'id' => $expense_id,
|
||||
'user_id' => $user_id
|
||||
]);
|
||||
|
||||
// Opcional: verificar se alguma linha foi afetada para dar um feedback mais preciso
|
||||
if ($stmt->rowCount() > 0) {
|
||||
$_SESSION['success_message'] = 'Despesa excluída com sucesso!';
|
||||
} else {
|
||||
$_SESSION['error_message'] = 'Não foi possível excluir a despesa. Ela não foi encontrada ou não pertence a você.';
|
||||
}
|
||||
|
||||
} catch (PDOException $e) {
|
||||
$_SESSION['error_message'] = 'Erro ao excluir a despesa: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
// Redirecionar de volta para a página de despesas
|
||||
header('Location: expenses.php');
|
||||
exit;
|
||||
126
edit_expense.php
Normal file
126
edit_expense.php
Normal file
@ -0,0 +1,126 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
// Proteger a página
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$expense_id = $_GET['id'] ?? null;
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$error_message = '';
|
||||
$expense = null;
|
||||
|
||||
if (!$expense_id) {
|
||||
header('Location: expenses.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$pdo = db();
|
||||
|
||||
// Buscar a despesa para garantir que ela pertence ao usuário
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT * FROM expenses WHERE id = :id AND user_id = :user_id");
|
||||
$stmt->execute(['id' => $expense_id, 'user_id' => $user_id]);
|
||||
$expense = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$expense) {
|
||||
$_SESSION['error_message'] = 'Despesa não encontrada.';
|
||||
header('Location: expenses.php');
|
||||
exit;
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$_SESSION['error_message'] = 'Erro ao buscar despesa.';
|
||||
header('Location: expenses.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Lógica para atualizar a despesa
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$description = $_POST['description'] ?? '';
|
||||
$amount = $_POST['amount'] ?? '';
|
||||
$category = $_POST['category'] ?? '';
|
||||
$expense_date = $_POST['expense_date'] ?? '';
|
||||
|
||||
if (empty($description) || empty($amount) || empty($category) || empty($expense_date)) {
|
||||
$error_message = 'Todos os campos são obrigatórios.';
|
||||
} else {
|
||||
try {
|
||||
$sql = "UPDATE expenses SET description = :description, amount = :amount, category = :category, expense_date = :expense_date WHERE id = :id AND user_id = :user_id";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([
|
||||
'description' => $description,
|
||||
'amount' => $amount,
|
||||
'category' => $category,
|
||||
'expense_date' => $expense_date,
|
||||
'id' => $expense_id,
|
||||
'user_id' => $user_id
|
||||
]);
|
||||
|
||||
$_SESSION['success_message'] = 'Despesa atualizada com sucesso!';
|
||||
header('Location: expenses.php');
|
||||
exit;
|
||||
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Erro ao atualizar a despesa: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
include __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
|
||||
<div class="container mt-4">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">Editar Despesa</h4>
|
||||
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST" action="edit_expense.php?id=<?php echo htmlspecialchars($expense_id); ?>">
|
||||
<div class="mb-3">
|
||||
<label for="description" class="form-label">Descrição</label>
|
||||
<input type="text" class="form-control" id="description" name="description" value="<?php echo htmlspecialchars($expense['description']); ?>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="amount" class="form-label">Valor (R$)</label>
|
||||
<input type="number" step="0.01" class="form-control" id="amount" name="amount" value="<?php echo htmlspecialchars($expense['amount']); ?>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="category" class="form-label">Categoria</label>
|
||||
<select class="form-select" id="category" name="category" required>
|
||||
<option value="">Selecione...</option>
|
||||
<?php
|
||||
$categories = ['Alimentação', 'Transporte', 'Moradia', 'Lazer', 'Saúde', 'Outros'];
|
||||
foreach ($categories as $cat) {
|
||||
$selected = ($expense['category'] === $cat) ? 'selected' : '';
|
||||
echo "<option value=\"".htmlspecialchars($cat)."\" $selected>".htmlspecialchars($cat)."</option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="expense_date" class="form-label">Data da Despesa</label>
|
||||
<input type="date" class="form-control" id="expense_date" name="expense_date" value="<?php echo htmlspecialchars($expense['expense_date']); ?>" required>
|
||||
</div>
|
||||
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
|
||||
<a href="expenses.php" class="btn btn-secondary">Cancelar</a>
|
||||
<button type="submit" class="btn btn-primary">Salvar Alterações</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include __DIR__ . '/includes/footer.php'; ?>
|
||||
247
expenses.php
Normal file
247
expenses.php
Normal file
@ -0,0 +1,247 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
// Proteger a página
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$pdo = db();
|
||||
$error_message = '';
|
||||
$success_message = '';
|
||||
|
||||
// Lógica para ADICIONAR nova despesa (POST)
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$description = $_POST['description'] ?? '';
|
||||
$amount = $_POST['amount'] ?? '';
|
||||
$category = $_POST['category'] ?? '';
|
||||
$expense_date = $_POST['expense_date'] ?? '';
|
||||
|
||||
if (empty($description) || empty($amount) || empty($category) || empty($expense_date)) {
|
||||
$error_message = 'Todos os campos são obrigatórios para adicionar uma despesa.';
|
||||
} else {
|
||||
try {
|
||||
$sql = "INSERT INTO expenses (user_id, description, amount, category, expense_date) VALUES (:user_id, :description, :amount, :category, :expense_date)";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([
|
||||
'user_id' => $user_id,
|
||||
'description' => $description,
|
||||
'amount' => $amount,
|
||||
'category' => $category,
|
||||
'expense_date' => $expense_date
|
||||
]);
|
||||
$_SESSION['success_message'] = 'Despesa registrada com sucesso!';
|
||||
header('Location: expenses.php'); // Redirecionar para limpar o POST
|
||||
exit;
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Erro ao registrar a despesa: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lógica para FILTRAR e BUSCAR despesas (GET)
|
||||
$filter_start_date = $_GET['start_date'] ?? '';
|
||||
$filter_end_date = $_GET['end_date'] ?? '';
|
||||
$filter_category = $_GET['category'] ?? '';
|
||||
|
||||
$sql = "SELECT * FROM expenses WHERE user_id = :user_id";
|
||||
$params = ['user_id' => $user_id];
|
||||
|
||||
if ($filter_start_date) {
|
||||
$sql .= " AND expense_date >= :start_date";
|
||||
$params['start_date'] = $filter_start_date;
|
||||
}
|
||||
if ($filter_end_date) {
|
||||
$sql .= " AND expense_date <= :end_date";
|
||||
$params['end_date'] = $filter_end_date;
|
||||
}
|
||||
if ($filter_category) {
|
||||
$sql .= " AND category = :category";
|
||||
$params['category'] = $filter_category;
|
||||
}
|
||||
|
||||
$sql .= " ORDER BY expense_date DESC";
|
||||
|
||||
$expenses = [];
|
||||
$total_filtered_amount = 0;
|
||||
try {
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
$expenses = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Calcular total dos itens filtrados
|
||||
foreach ($expenses as $expense) {
|
||||
$total_filtered_amount += $expense['amount'];
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Erro ao buscar despesas: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
// Obter todas as categorias para o dropdown do filtro
|
||||
$categories = ['Alimentação', 'Transporte', 'Moradia', 'Lazer', 'Saúde', 'Outros'];
|
||||
|
||||
include __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
|
||||
<div class="container mt-4">
|
||||
<div class="row">
|
||||
<!-- Coluna para Adicionar Despesa -->
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">Registrar Nova Despesa</h4>
|
||||
<?php if ($_SERVER['REQUEST_METHOD'] === 'POST' && $error_message): ?>
|
||||
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
|
||||
<?php endif; ?>
|
||||
<form method="POST" action="expenses.php">
|
||||
<!-- Campos do formulário de adição -->
|
||||
<div class="mb-3">
|
||||
<label for="description" class="form-label">Descrição</label>
|
||||
<input type="text" class="form-control" id="description" name="description" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="amount" class="form-label">Valor (R$)</label>
|
||||
<input type="number" step="0.01" class="form-control" id="amount" name="amount" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="category" class="form-label">Categoria</label>
|
||||
<select class="form-select" id="category" name="category" required>
|
||||
<option value="">Selecione...</option>
|
||||
<?php foreach ($categories as $cat): ?>
|
||||
<option value="<?php echo htmlspecialchars($cat); ?>"><?php echo htmlspecialchars($cat); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="expense_date" class="form-label">Data da Despesa</label>
|
||||
<input type="date" class="form-control" id="expense_date" name="expense_date" required>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-primary">Adicionar Despesa</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Coluna para Listar e Filtrar Despesas -->
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">Minhas Despesas</h4>
|
||||
|
||||
<!-- Mensagens de feedback -->
|
||||
<?php
|
||||
if (isset($_SESSION['success_message'])) {
|
||||
echo '<div class="alert alert-success">' . htmlspecialchars($_SESSION['success_message']) . '</div>';
|
||||
unset($_SESSION['success_message']);
|
||||
}
|
||||
if (isset($_SESSION['error_message'])) {
|
||||
echo '<div class="alert alert-danger">' . htmlspecialchars($_SESSION['error_message']) . '</div>';
|
||||
unset($_SESSION['error_message']);
|
||||
}
|
||||
?>
|
||||
|
||||
<!-- Formulário de Filtro -->
|
||||
<form method="GET" action="expenses.php" class="mb-4 p-3 bg-light rounded">
|
||||
<div class="row g-3 align-items-end">
|
||||
<div class="col-md-4">
|
||||
<label for="start_date" class="form-label">De</label>
|
||||
<input type="date" class="form-control" id="start_date" name="start_date" value="<?php echo htmlspecialchars($filter_start_date); ?>">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for="end_date" class="form-label">Até</label>
|
||||
<input type="date" class="form-control" id="end_date" name="end_date" value="<?php echo htmlspecialchars($filter_end_date); ?>">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for="filter_category" class="form-label">Categoria</label>
|
||||
<select class="form-select" id="filter_category" name="category">
|
||||
<option value="">Todas</option>
|
||||
<?php foreach ($categories as $cat): ?>
|
||||
<option value="<?php echo htmlspecialchars($cat); ?>" <?php echo ($filter_category === $cat) ? 'selected' : ''; ?>><?php echo htmlspecialchars($cat); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-12 d-flex justify-content-end mt-3">
|
||||
<a href="expenses.php" class="btn btn-secondary me-2">Limpar</a>
|
||||
<button type="submit" class="btn btn-primary me-2">Filtrar</button>
|
||||
<a href="#" id="export-csv" class="btn btn-success"><i class="bi bi-download me-2"></i>Exportar CSV</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Resumo dos Filtros -->
|
||||
<div class="alert alert-info">
|
||||
<strong>Total Filtrado:</strong> R$ <?php echo number_format($total_filtered_amount, 2, ',', '.'); ?>
|
||||
</div>
|
||||
|
||||
<!-- Tabela de Despesas -->
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Descrição</th>
|
||||
<th>Valor</th>
|
||||
<th>Categoria</th>
|
||||
<th>Data</th>
|
||||
<th>Ações</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($expenses)): ?>
|
||||
<tr>
|
||||
<td colspan="5" class="text-center">Nenhuma despesa encontrada para os filtros aplicados.</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($expenses as $expense): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($expense['description']); ?></td>
|
||||
<td>R$ <?php echo number_format($expense['amount'], 2, ',', '.'); ?></td>
|
||||
<td><?php echo htmlspecialchars($expense['category']); ?></td>
|
||||
<td><?php echo date('d/m/Y', strtotime($expense['expense_date'])); ?></td>
|
||||
<td>
|
||||
<a href="edit_expense.php?id=<?php echo $expense['id']; ?>" class="btn btn-sm btn-outline-primary"><i class="bi bi-pencil-sm"></i></a>
|
||||
<a href="delete_expense.php?id=<?php echo $expense['id']; ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Tem certeza que deseja excluir esta despesa?');"><i class="bi bi-trash-sm"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const exportBtn = document.getElementById('export-csv');
|
||||
if (exportBtn) {
|
||||
exportBtn.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const startDate = document.getElementById('start_date').value;
|
||||
const endDate = document.getElementById('end_date').value;
|
||||
const category = document.getElementById('filter_category').value;
|
||||
|
||||
const params = new URLSearchParams();
|
||||
if (startDate) params.append('start_date', startDate);
|
||||
if (endDate) params.append('end_date', endDate);
|
||||
if (category) params.append('category', category);
|
||||
|
||||
const exportUrl = 'export.php?' + params.toString();
|
||||
window.location.href = exportUrl;
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php include __DIR__ . '/includes/footer.php'; ?>
|
||||
60
export.php
Normal file
60
export.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
|
||||
// Check if user is logged in
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: login.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$pdo = db();
|
||||
|
||||
// Build query with filters
|
||||
$sql = "SELECT * FROM expenses WHERE user_id = :user_id";
|
||||
$params = ['user_id' => $user_id];
|
||||
|
||||
if (!empty($_GET['start_date'])) {
|
||||
$sql .= " AND expense_date >= :start_date";
|
||||
$params['start_date'] = $_GET['start_date'];
|
||||
}
|
||||
if (!empty($_GET['end_date'])) {
|
||||
$sql .= " AND expense_date <= :end_date";
|
||||
$params['end_date'] = $_GET['end_date'];
|
||||
}
|
||||
if (!empty($_GET['category'])) {
|
||||
$sql .= " AND category = :category";
|
||||
$params['category'] = $_GET['category'];
|
||||
}
|
||||
|
||||
$sql .= " ORDER BY expense_date DESC";
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
$expenses = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Set headers for CSV download
|
||||
header('Content-Type: text/csv; charset=utf-8');
|
||||
header('Content-Disposition: attachment; filename="despesas.csv"');
|
||||
|
||||
// Open output stream
|
||||
$output = fopen('php://output', 'w');
|
||||
|
||||
// Write CSV header
|
||||
fputcsv($output, ['Data', 'Descricao', 'Valor', 'Categoria']);
|
||||
|
||||
// Write data
|
||||
if ($expenses) {
|
||||
foreach ($expenses as $expense) {
|
||||
fputcsv($output, [
|
||||
$expense['expense_date'],
|
||||
$expense['description'],
|
||||
$expense['amount'],
|
||||
$expense['category']
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
fclose($output);
|
||||
exit();
|
||||
@ -2,16 +2,32 @@
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
// Buscar o nome do usuário se estiver logado
|
||||
$user_name = '';
|
||||
if (isset($_SESSION['user_id'])) {
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("SELECT name FROM users WHERE id = :id");
|
||||
$stmt->execute(['id' => $_SESSION['user_id']]);
|
||||
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if ($user) {
|
||||
$user_name = $user['name'];
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
// Em caso de erro, o nome fica em branco
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="pt-BR">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Galilei-finance-v1</title>
|
||||
<title>Galilei Finance</title>
|
||||
<meta name="description" content="Software de controle financeiro familiar para transformar despesas em investimentos.">
|
||||
<meta name="keywords" content="controle financeiro, finanças pessoais, orçamento familiar, investimentos, economizar dinheiro, gestão de despesas, app de finanças, Built with Flatlogic Generator">
|
||||
<meta property="og:title" content="Galilei-finance-v1">
|
||||
<meta property="og:title" content="Galilei Finance">
|
||||
<meta property="og:description" content="Software de controle financeiro familiar para transformar despesas em investimentos.">
|
||||
<meta property="og:image" content="<?php echo htmlspecialchars($_SERVER['PROJECT_IMAGE_URL'] ?? '', ENT_QUOTES, 'UTF-8'); ?>">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
@ -25,3 +41,40 @@ if (session_status() === PHP_SESSION_NONE) {
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div class="container">
|
||||
<a class="navbar-brand navbar-brand-logo" href="index.php">
|
||||
<i class="bi bi-safe me-2"></i>
|
||||
Galilei Finance
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<?php if (isset($_SESSION['user_id'])): ?>
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">Dashboard</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="expenses.php">Despesas</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="budgets.php">Orçamentos</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="dropdown">
|
||||
<a href="#" class="d-flex align-items-center text-dark text-decoration-none dropdown-toggle" id="dropdownUser1" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<span class="me-2">Olá, <?php echo htmlspecialchars($user_name); ?></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end text-small" aria-labelledby="dropdownUser1">
|
||||
<li><a class="dropdown-item" href="profile.php">Meu Perfil</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="logout.php">Sair</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
203
index.php
203
index.php
@ -3,7 +3,6 @@ if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
// Proteger a página: se não estiver logado, redireciona para o login
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
@ -11,76 +10,160 @@ if (!isset($_SESSION['user_id'])) {
|
||||
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("SELECT id, name, email, role FROM users WHERE id = :id");
|
||||
$stmt->execute(['id' => $_SESSION['user_id']]);
|
||||
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
// Em caso de erro, desloga o usuário para segurança
|
||||
header('Location: logout.php');
|
||||
exit;
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$pdo = db();
|
||||
$current_month_date = date('Y-m-01');
|
||||
|
||||
// --- Coleta de Dados para o Dashboard ---
|
||||
|
||||
// 1. Despesas do Mês Atual
|
||||
$stmt_expenses = $pdo->prepare(
|
||||
"SELECT category, SUM(amount) as total_spent FROM expenses
|
||||
WHERE user_id = :user_id AND MONTH(expense_date) = MONTH(CURRENT_DATE()) AND YEAR(expense_date) = YEAR(CURRENT_DATE())
|
||||
GROUP BY category"
|
||||
);
|
||||
$stmt_expenses->execute(['user_id' => $user_id]);
|
||||
$monthly_expenses = $stmt_expenses->fetchAll(PDO::FETCH_KEY_PAIR);
|
||||
|
||||
// 2. Orçamentos do Mês Atual
|
||||
$stmt_budgets = $pdo->prepare("SELECT category, amount FROM budgets WHERE user_id = :user_id AND budget_month = :budget_month");
|
||||
$stmt_budgets->execute(['user_id' => $user_id, 'budget_month' => $current_month_date]);
|
||||
$monthly_budgets = $stmt_budgets->fetchAll(PDO::FETCH_KEY_PAIR);
|
||||
|
||||
// 3. Consolidar dados de Orçamento e Despesas
|
||||
$categories = ['Alimentação', 'Transporte', 'Moradia', 'Lazer', 'Saúde', 'Outros'];
|
||||
$summary = [];
|
||||
$total_spent_this_month = 0;
|
||||
$total_budget_this_month = 0;
|
||||
|
||||
foreach ($categories as $category) {
|
||||
$spent = $monthly_expenses[$category] ?? 0;
|
||||
$budget = $monthly_budgets[$category] ?? 0;
|
||||
$summary[$category] = [
|
||||
'spent' => $spent,
|
||||
'budget' => $budget,
|
||||
'remaining' => $budget - $spent,
|
||||
];
|
||||
$total_spent_this_month += $spent;
|
||||
$total_budget_this_month += $budget;
|
||||
}
|
||||
|
||||
if (!$user) {
|
||||
// Se o usuário não for encontrado no DB, desloga
|
||||
header('Location: logout.php');
|
||||
exit;
|
||||
}
|
||||
// 4. Últimas 5 despesas
|
||||
$stmt_recent = $pdo->prepare("SELECT * FROM expenses WHERE user_id = :user_id ORDER BY expense_date DESC LIMIT 5");
|
||||
$stmt_recent->execute(['user_id' => $user_id]);
|
||||
$recent_expenses = $stmt_recent->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Função para determinar a classe da barra de progresso
|
||||
function get_progress_bar_class($percentage) {
|
||||
if ($percentage > 100) return 'bg-danger';
|
||||
if ($percentage > 75) return 'bg-warning';
|
||||
return 'bg-success';
|
||||
}
|
||||
|
||||
include __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
|
||||
<div class="container">
|
||||
<a class="navbar-brand navbar-brand-logo" href="#">
|
||||
<i class="bi bi-safe me-2"></i>
|
||||
Galilei Finance
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-person-circle me-1"></i>
|
||||
<?php echo htmlspecialchars($user['name']); ?>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
|
||||
<li><a class="dropdown-item" href="#">Meu Perfil</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="logout.php">Sair</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="container mt-4">
|
||||
<div class="p-5 mb-4 bg-light rounded-3">
|
||||
<div class="container-fluid py-5">
|
||||
<h1 class="display-5 fw-bold">Bem-vindo(a) ao seu Painel Financeiro</h1>
|
||||
<p class="col-md-8 fs-4">Este é o seu centro de controle. Em breve, você poderá adicionar despesas, criar orçamentos e visualizar relatórios detalhados aqui.</p>
|
||||
<button class="btn btn-primary btn-lg" type="button">Adicionar Despesa (em breve)</button>
|
||||
</div>
|
||||
</div>
|
||||
<h1 class="mb-4">Dashboard de <?php echo date('F', strtotime('now')); ?></h1>
|
||||
|
||||
<div class="row align-items-md-stretch">
|
||||
<div class="col-md-6">
|
||||
<div class="h-100 p-5 text-white bg-dark rounded-3">
|
||||
<h2>Orçamentos</h2>
|
||||
<p>Acompanhe seus orçamentos mensais e veja onde seu dinheiro está indo. (Funcionalidade futura)</p>
|
||||
<button class="btn btn-outline-light" type="button">Ver Orçamentos</button>
|
||||
<!-- Resumo Geral do Mês -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-6">
|
||||
<h4>Visão Geral do Mês</h4>
|
||||
<p class="text-muted">Gastos vs. Orçamento Total</p>
|
||||
<span class="fs-3 fw-bold">R$ <?php echo number_format($total_spent_this_month, 2, ',', '.'); ?></span>
|
||||
<span class="fs-5 text-muted">/ R$ <?php echo number_format($total_budget_this_month, 2, ',', '.'); ?></span>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<?php
|
||||
$overall_percentage = ($total_budget_this_month > 0) ? ($total_spent_this_month / $total_budget_this_month) * 100 : 0;
|
||||
$progress_class = get_progress_bar_class($overall_percentage);
|
||||
?>
|
||||
<div class="progress" style="height: 25px;">
|
||||
<div class="progress-bar <?php echo $progress_class; ?>" role="progressbar"
|
||||
style="width: <?php echo min(100, $overall_percentage); ?>%;"
|
||||
aria-valuenow="<?php echo $overall_percentage; ?>" aria-valuemin="0" aria-valuemax="100">
|
||||
<?php echo number_format($overall_percentage, 1); ?>%
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="h-100 p-5 bg-light border rounded-3">
|
||||
<h2>Metas</h2>
|
||||
<p>Defina e acompanhe suas metas de poupança para alcançar seus sonhos. (Funcionalidade futura)</p>
|
||||
<button class="btn btn-outline-secondary" type="button">Ver Metas</button>
|
||||
</div>
|
||||
|
||||
<!-- Resumo por Categoria -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Resumo do Orçamento por Categoria</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Categoria</th>
|
||||
<th class="text-end">Gasto</th>
|
||||
<th class="text-end">Orçamento</th>
|
||||
<th class="text-end">Restante</th>
|
||||
<th style="width: 25%;">Progresso</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($summary as $category => $data): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($category); ?></td>
|
||||
<td class="text-end">R$ <?php echo number_format($data['spent'], 2, ',', '.'); ?></td>
|
||||
<td class="text-end">R$ <?php echo number_format($data['budget'], 2, ',', '.'); ?></td>
|
||||
<td class="text-end <?php echo ($data['remaining'] < 0) ? 'text-danger' : 'text-success'; ?>">
|
||||
R$ <?php echo number_format($data['remaining'], 2, ',', '.'); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
$percentage = ($data['budget'] > 0) ? ($data['spent'] / $data['budget']) * 100 : 0;
|
||||
$progress_class = get_progress_bar_class($percentage);
|
||||
?>
|
||||
<div class="progress">
|
||||
<div class="progress-bar <?php echo $progress_class; ?>" role="progressbar"
|
||||
style="width: <?php echo min(100, $percentage); ?>%;"
|
||||
aria-valuenow="<?php echo $percentage; ?>" aria-valuemin="0" aria-valuemax="100">
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Despesas Recentes -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Despesas Recentes</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<?php if (empty($recent_expenses)): ?>
|
||||
<tr><td class="text-center">Nenhuma despesa registrada este mês.</td></tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($recent_expenses as $expense): ?>
|
||||
<tr>
|
||||
<td><span class="badge bg-secondary me-2"><?php echo htmlspecialchars($expense['category']); ?></span> <?php echo htmlspecialchars($expense['description']); ?></td>
|
||||
<td class="text-end">R$ <?php echo number_format($expense['amount'], 2, ',', '.'); ?></td>
|
||||
<td class="text-end text-muted"><?php echo date('d/m/Y', strtotime($expense['expense_date'])); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="text-end mt-2">
|
||||
<a href="expenses.php">Ver todas as despesas →</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
10
login.php
10
login.php
@ -35,6 +35,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// Credenciais inválidas
|
||||
$error_message = 'E-mail ou senha inválidos.';
|
||||
}
|
||||
|
||||
if ($user && password_verify($password, $user['password_hash'])) {
|
||||
// Login bem-sucedido
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
} else {
|
||||
// Credenciais inválidas
|
||||
$error_message = 'E-mail ou senha inválidos.';
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
// Idealmente, logar o erro em vez de exibir
|
||||
$error_message = 'Erro no banco de dados. Tente novamente mais tarde.';
|
||||
|
||||
136
profile.php
Normal file
136
profile.php
Normal file
@ -0,0 +1,136 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$pdo = db();
|
||||
$update_name_error = '';
|
||||
$update_name_success = '';
|
||||
$update_password_error = '';
|
||||
$update_password_success = '';
|
||||
|
||||
// Obter dados do usuário
|
||||
$stmt = $pdo->prepare("SELECT name, email FROM users WHERE id = :id");
|
||||
$stmt->execute(['id' => $user_id]);
|
||||
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
// Lógica para lidar com o POST
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// Atualizar Nome
|
||||
if (isset($_POST['update_name'])) {
|
||||
$name = $_POST['name'] ?? '';
|
||||
if (empty($name)) {
|
||||
$update_name_error = 'O nome não pode estar em branco.';
|
||||
} else {
|
||||
try {
|
||||
$stmt = $pdo->prepare("UPDATE users SET name = :name WHERE id = :id");
|
||||
$stmt->execute(['name' => $name, 'id' => $user_id]);
|
||||
$user['name'] = $name; // Atualizar o nome na página
|
||||
$update_name_success = 'Nome atualizado com sucesso!';
|
||||
} catch (PDOException $e) {
|
||||
$update_name_error = 'Erro ao atualizar o nome.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Atualizar Senha
|
||||
if (isset($_POST['update_password'])) {
|
||||
$current_password = $_POST['current_password'] ?? '';
|
||||
$new_password = $_POST['new_password'] ?? '';
|
||||
$confirm_password = $_POST['confirm_password'] ?? '';
|
||||
|
||||
if (empty($current_password) || empty($new_password) || empty($confirm_password)) {
|
||||
$update_password_error = 'Todos os campos de senha são obrigatórios.';
|
||||
} elseif ($new_password !== $confirm_password) {
|
||||
$update_password_error = 'A nova senha e a confirmação não correspondem.';
|
||||
} else {
|
||||
try {
|
||||
// Verificar senha atual
|
||||
$stmt = $pdo->prepare("SELECT password_hash FROM users WHERE id = :id");
|
||||
$stmt->execute(['id' => $user_id]);
|
||||
$hash = $stmt->fetchColumn();
|
||||
|
||||
if (password_verify($current_password, $hash)) {
|
||||
// Se a senha atual estiver correta, criar novo hash e atualizar
|
||||
$new_hash = password_hash($new_password, PASSWORD_DEFAULT);
|
||||
$stmt_update = $pdo->prepare("UPDATE users SET password_hash = :hash WHERE id = :id");
|
||||
$stmt_update->execute(['hash' => $new_hash, 'id' => $user_id]);
|
||||
$update_password_success = 'Senha atualizada com sucesso!';
|
||||
} else {
|
||||
$update_password_error = 'A senha atual está incorreta.';
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$update_password_error = 'Erro ao atualizar a senha.';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
include __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
|
||||
<div class="container mt-4">
|
||||
<h1 class="mb-4">Meu Perfil</h1>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">Atualizar Informações</div>
|
||||
<div class="card-body">
|
||||
<?php if ($update_name_success): ?><div class="alert alert-success"><?php echo $update_name_success; ?></div><?php endif; ?>
|
||||
<?php if ($update_name_error): ?><div class="alert alert-danger"><?php echo $update_name_error; ?></div><?php endif; ?>
|
||||
|
||||
<form method="POST" action="profile.php">
|
||||
<input type="hidden" name="update_name" value="1">
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Nome</label>
|
||||
<input type="text" class="form-control" id="name" name="name" value="<?php echo htmlspecialchars($user['name']); ?>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">E-mail</label>
|
||||
<input type="email" class="form-control" id="email" value="<?php echo htmlspecialchars($user['email']); ?>" disabled>
|
||||
<div class="form-text">O e-mail não pode ser alterado.</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Salvar Nome</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">Alterar Senha</div>
|
||||
<div class="card-body">
|
||||
<?php if ($update_password_success): ?><div class="alert alert-success"><?php echo $update_password_success; ?></div><?php endif; ?>
|
||||
<?php if ($update_password_error): ?><div class="alert alert-danger"><?php echo $update_password_error; ?></div><?php endif; ?>
|
||||
|
||||
<form method="POST" action="profile.php">
|
||||
<input type="hidden" name="update_password" value="1">
|
||||
<div class="mb-3">
|
||||
<label for="current_password" class="form-label">Senha Atual</label>
|
||||
<input type="password" class="form-control" id="current_password" name="current_password" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="new_password" class="form-label">Nova Senha</label>
|
||||
<input type="password" class="form-control" id="new_password" name="new_password" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="confirm_password" class="form-label">Confirmar Nova Senha</label>
|
||||
<input type="password" class="form-control" id="confirm_password" name="confirm_password" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Alterar Senha</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include __DIR__ . '/includes/footer.php'; ?>
|
||||
Loading…
x
Reference in New Issue
Block a user