OpenNIT

Quelltext des aktuellen Standes

Fassung 1.1.1

_contract_file_section.php

7 KB
<?php
/**
 * Wiederverwendbare Datei-Sektion für das Vertrags-Modul (cs- Prefix).
 *
 * Erwartete Variablen:
 *   $files          array   Liste der Dateien (contract_files/company_files)
 *   $title          string  Überschrift
 *   $icon           string  Roh-SVG für die Überschrift
 *   $file_base      string  Basis-URL der Datei-Endpunkte (z. B. '/contracts/files')
 *   $empty_text     string  Text wenn keine Dateien vorhanden
 *   $can_manage     bool    Darf hochladen?
 *   $can_delete     bool    Darf löschen? (Standard: = can_manage)
 *   $section_class  string  optionale Zusatzklasse für <section>
 *   $upload         ?array  Upload-Formular-Konfig oder null (kein Upload):
 *                            [ 'action' => url, 'input_id' => str,
 *                              'label' => str, 'file_type' => ?str ]
 *   $delete_confirm string  Bestätigungstext beim Löschen
 */
$files         = $files ?? [];
$can_delete    = $can_delete ?? ($can_manage ?? false);
$section_class = $section_class ?? '';
$delete_confirm = $delete_confirm ?? 'Datei löschen?';
$upload        = $upload ?? null;
?>
<section class="cs-card <?= $section_class ?>">
    <div class="cs-card-head">
        <h2 class="cs-card-title">
            <?= $icon ?>
            <?= $this->e($title) ?>
            <?php if (!empty($title_sub)): ?><span class="cs-card-title-sub"><?= $this->e($title_sub) ?></span><?php endif; ?>
            <?php if (!empty($files)): ?><span class="cs-count"><?= count($files) ?></span><?php endif; ?>
        </h2>
        <?php if (!empty($head_link)): ?>
        <a href="<?= $this->e($head_link['href']) ?>" class="btn btn-default btn-sm"><?= $this->e($head_link['label']) ?> &rarr;</a>
        <?php endif; ?>
    </div>

    <?php if (($can_manage ?? false) && $upload !== null): ?>
    <form action="<?= $this->e($upload['action']) ?>" method="POST" enctype="multipart/form-data" class="cs-upload-form">
        <input type="hidden" name="_csrf" value="<?= $this->csrf() ?>">
        <?php if (!empty($upload['file_type'])): ?>
        <input type="hidden" name="file_type" value="<?= $this->e($upload['file_type']) ?>">
        <?php endif; ?>
        <label class="cs-upload-drop" for="<?= $this->e($upload['input_id']) ?>">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
            <span data-cs-upload-name><?= $this->e($upload['label']) ?></span>
        </label>
        <input type="file" name="file" id="<?= $this->e($upload['input_id']) ?>" class="cs-upload-hidden"
               accept=".pdf,.doc,.docx,.xls,.xlsx,.odt,.ods,.png,.jpg,.jpeg,.gif,.webp,.tif,.tiff,.txt,.csv,.eml,.msg,.zip" required>
        <button type="submit" class="btn btn-primary btn-sm"><?= $this->te('Hochladen') ?></button>
    </form>
    <script>
    (function () {
        if (!window.cfBindUpload) {
            window.cfBindUpload = function (inputId, defaultText) {
                var input = document.getElementById(inputId);
                if (!input) return;
                var label = input.previousElementSibling;
                var n = label ? label.querySelector('[data-cs-upload-name]') : null;
                function showName() {
                    if (!n) return;
                    n.textContent = input.files[0] ? input.files[0].name : defaultText;
                    n.style.color = input.files[0] ? '#374151' : '';
                    n.style.fontWeight = input.files[0] ? '500' : '';
                }
                input.addEventListener('change', showName);
                if (label) {
                    ['dragenter', 'dragover'].forEach(function (ev) {
                        label.addEventListener(ev, function (e) { e.preventDefault(); label.classList.add('cs-upload-dragging'); });
                    });
                    ['dragleave', 'drop'].forEach(function (ev) {
                        label.addEventListener(ev, function (e) { e.preventDefault(); label.classList.remove('cs-upload-dragging'); });
                    });
                    label.addEventListener('drop', function (e) {
                        if (e.dataTransfer && e.dataTransfer.files.length) { input.files = e.dataTransfer.files; showName(); }
                    });
                }
            };
        }
        window.cfBindUpload(<?= json_encode($upload['input_id']) ?>, <?= json_encode($upload['label']) ?>);
    })();
    </script>
    <?php endif; ?>

    <?php if (empty($files)): ?>
        <p class="cs-empty"><?= $this->e($empty_text ?? 'Noch keine Dokumente hochgeladen.') ?></p>
    <?php else: ?>
    <div class="cs-file-list">
        <?php foreach ($files as $f): ?>
        <?php
        $ext = strtolower(pathinfo($f['original_filename'], PATHINFO_EXTENSION));
        $extColor = match ($ext) {
            'pdf' => '#dc2626', 'doc', 'docx' => '#2563eb',
            'xls', 'xlsx' => '#16a34a', 'jpg', 'jpeg', 'png', 'gif', 'webp' => '#d97706',
            default => '#6b7280'
        };
        ?>
        <div class="cs-file-row">
            <div class="cs-file-icon-wrap">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="20" height="20" style="color:<?= $extColor ?>"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
            </div>
            <div class="cs-file-info">
                <span class="cs-file-name"><?= $this->e($f['original_filename']) ?></span>
                <span class="cs-file-meta"><?= $this->formatFileSize((int)$f['file_size']) ?> &middot; <?= $this->relativeTime($f['created_at']) ?></span>
            </div>
            <?= att_view_link($file_base . '/' . $f['id'] . '/view', $f['original_filename'], $f['mime_type'] ?? '') ?>
            <a href="<?= $this->e($file_base) ?>/<?= $f['id'] ?>/download" class="cs-file-dl" title="<?= $this->te('Herunterladen') ?>">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
            </a>
            <?php if ($can_delete): ?>
            <form action="<?= $this->e($file_base) ?>/<?= $f['id'] ?>" method="POST" onsubmit="return confirm(<?= $this->e(json_encode($delete_confirm)) ?>);" style="margin:0;">
                <input type="hidden" name="_csrf" value="<?= $this->csrf() ?>">
                <input type="hidden" name="_method" value="DELETE">
                <button type="submit" class="cs-file-del" title="<?= $this->te('Löschen') ?>">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="13" height="13"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/></svg>
                </button>
            </form>
            <?php endif; ?>
        </div>
        <?php endforeach; ?>
    </div>
    <?php endif; ?>
</section>