Webbserver - Love Blomberg

Show sourcecode

The following files exists in this folder. Click to view.

public_html/smartkortet/pages/

hem.php
historik.php
installningar.php
restauranger.php
statistik.php

hem.php

208 lines UTF-8 Windows (CRLF)
<?php

declare(strict_types=1);

require_once 
__DIR__ '/../includes/data.php';

$userId = (int) $user['id'];

if (
$_SERVER['REQUEST_METHOD'] === 'POST') {
    
verifyCsrf();
    
$action $_POST['action'] ?? '';

    if (
$action === 'save_budget') {
        
$startingBalance parseAmount($_POST['starting_balance'] ?? '0');
        
$periodEnd $_POST['period_end'] ?? '';

        if (
$startingBalance || $periodEnd === '') {
            
setFlash('error''Ange ett giltigt saldo och slutdatum.');
        } else {
            
saveUserBudget($userId$startingBalance$periodEnd);
            
setFlash('success''Budgetperiod sparad.');
        }

        
redirect('/index.php?tab=hem');
    }

    if (
$action === 'add_spend') {
        
$amount parseAmount($_POST['amount'] ?? '0');
        
$spentOn normalizeIsoDate($_POST['spent_on'] ?? null'');
        
$selectedPlace normalizeNullableString($_POST['place_name'] ?? null);
        
$saveFavorite = isset($_POST['save_favorite']);

        if (
$amount || $amount 90 || $spentOn === '') {
            
setFlash('error''Du kan registrera mellan 0 och 90 kr per dag.');
            
redirect('/index.php?tab=hem');
        }

        
$todayDate date('Y-m-d');
        if (
$spentOn === $todayDate) {
            
$budgetMetricsForValidation calculateBudgetMetrics($userId);
            
$todayBudgetRemaining = (float) ($budgetMetricsForValidation['today_budget_remaining'] ?? 0.0);

            if (
$amount $todayBudgetRemaining 0.0001) {
                
setFlash(
                    
'error',
                    
sprintf('Köpet överskrider dagens kvarvarande budget (%s).'formatCurrency($todayBudgetRemaining))
                );
                
redirect('/index.php?tab=hem');
            }
        }

        
addSpendEntry($userId$amount$spentOn$selectedPlace);

        if (
$saveFavorite && $selectedPlace !== null) {
            
saveFavoritePlace($userId$selectedPlace);
        }

        
setFlash('success''Dagens köp är sparat.');
        
redirect('/index.php?tab=hem');
    }
}

$budgetMetrics calculateBudgetMetrics($userId);
$favorites getFavoritePlaces($userId);
$allRestaurantNames getMatkortRestaurantNames();
$flash getFlash();

$favoriteNames array_map(
    static fn (array 
$favorite): string => (string) ($favorite['name'] ?? ''),
    
$favorites
);

$normalizeName = static function (string $value): string {
    
$trimmed trim($value);
    return 
function_exists('mb_strtolower') ? mb_strtolower($trimmed) : strtolower($trimmed);
};

$favoriteLookup = [];
foreach (
$favoriteNames as $favoriteName) {
    
$favoriteLookup[$normalizeName($favoriteName)] = true;
}

$nonFavoriteRestaurantNames array_values(array_filter(
    
$allRestaurantNames,
    static fn (
string $name): bool => !isset($favoriteLookup[$normalizeName($name)])
));

$periodEnd = (string) $budgetMetrics['period_end'];
$startingBalance = (float) $budgetMetrics['starting_balance'];
$remaining = (float) $budgetMetrics['remaining'];
$todaySpent = (float) $budgetMetrics['today_spent'];
$hasSpendEntryToday = (bool) $budgetMetrics['has_spend_entry_today'];
$daysLeft = (int) $budgetMetrics['days_left'];
$spendPerDayLeft = (float) $budgetMetrics['spend_per_day_left'];
$todayBudgetRemaining = (float) $budgetMetrics['today_budget_remaining'];
$daysLeftLabel $hasSpendEntryToday 'Dagar kvar (exkl idag)' 'Dagar kvar (inkl idag)';
$todayBudgetHint 'Visar upp till 90 kr, eller lägre om saldo per dag är mindre, minus dagens spendering.';
$budgetPerDayHint 'Saldo kvar fördelat på antalet dagar kvar i perioden.';
$daysLeftHint $hasSpendEntryToday
    
'Antal vardagar kvar från i morgon till och med slutdatum.
Helger och helgdagar exkluderade.'
    
'Antal vardagar kvar från idag till och med slutdatum. 
Helger och helgdagar exkluderade.'
;
?>
<article class="card panel hero-panel">
    <div>
        <p class="pill" title="<?= e($todayBudgetHint ?>" aria-label="<?= e($todayBudgetHint?>">Dagens budget</p>
        <h2><?= e(formatCurrency($todayBudgetRemaining)) ?></h2>
    </div>
    <div class="kpi-grid">
        <div class="kpi">
            <span>Saldo kvar</span>
            <strong><?= e(formatCurrency($remaining)) ?></strong>
        </div>
        <div class="kpi">
            <span title="<?= e($budgetPerDayHint?>" aria-label="<?= e($budgetPerDayHint?>">Kan spendera / dag</span>
            <strong><?= e(formatCurrency($spendPerDayLeft)) ?></strong>
        </div>
        <div class="kpi">
            <span>Spenderat idag</span>
            <strong><?= e(formatCurrency($todaySpent)) ?></strong>
        </div>
        <div class="kpi">
            <span title="<?= e($daysLeftHint?>" aria-label="<?= e($daysLeftHint?>"><?= e($daysLeftLabel?></span>
            <strong><?= e((string) $daysLeft?></strong>
        </div>
    </div>
</article>

<?php if ($flash): ?>
    <div class="notice <?= e($flash['type']) ?>"><?= e($flash['message']) ?></div>
<?php endif; ?>

<article class="card panel">
    <h3>Registrera köp</h3>
    <form method="post" class="stack">
        <input type="hidden" name="csrf_token" value="<?= e(csrfToken()) ?>">
        <input type="hidden" name="action" value="add_spend">

        <label class="field">
            <span>Datum</span>
            <input type="date" name="spent_on" value="<?= e(date('Y-m-d')) ?>" required>
        </label>

        <div>
            <span class="field-label">Snabbval</span>
            <div class="quick-amounts">
                <button type="button" class="chip" data-amount="0">0 kr</button>
                <button type="button" class="chip" data-amount="50">50 kr</button>
                <button type="button" class="chip" data-amount="70">70 kr</button>
                <button type="button" class="chip" data-amount="90">90 kr</button>
            </div>
        </div>

        <label class="field">
            <span>Exakt belopp (max 90 kr)</span>
            <input id="amount-input" type="number" name="amount" min="0" max="90" step="0.01" value="0" required>
        </label>

        <label class="field">
            <span>Välj restaurang/butik (valfritt)</span>
            <select name="place_name">
                <option value="">Välj...</option>
                <?php if ($favoriteNames): ?>
                    <option value="" disabled>----- Favoriter -----</option>
                    <?php foreach ($favoriteNames as $favoriteName): ?>
                        <option value="<?= e($favoriteName?>"><?= e($favoriteName?></option>
                    <?php endforeach; ?>
                    <option value="" disabled>----- Alla restauranger och butiker -----</option>
                <?php endif; ?>
                <?php foreach ($nonFavoriteRestaurantNames as $restaurantName): ?>
                    <option value="<?= e($restaurantName?>"><?= e($restaurantName?></option>
                <?php endforeach; ?>
            </select>
        </label>

        <label class="checkbox-row">
            <input type="checkbox" name="save_favorite" value="1">
            <span>Spara platsen som favorit</span>
        </label>

        <div class="form-actions">
            <button class="btn" type="submit">Spara köp</button>
        </div>
    </form>
</article>

<article class="card panel">
    <h3>Ställ in saldo och slutdatum</h3>
    <form method="post" class="form-grid">
        <input type="hidden" name="csrf_token" value="<?= e(csrfToken()) ?>">
        <input type="hidden" name="action" value="save_budget">

        <label class="field">
            <span>Startsaldo (kr)</span>
            <input type="number" name="starting_balance" min="0" max="10000" step="0.01" required value="<?= e((string) $startingBalance?>">
        </label>

        <label class="field">
            <span>Slutdatum</span>
            <input type="date" name="period_end" required value="<?= e($periodEnd?>">
        </label>

        <div class="form-actions">
            <button class="btn" type="submit">Spara period</button>
        </div>
    </form>
</article>