Files
brightwheel-exporter/dashboard/dashboard.html
T
2026-08-29 22:39:58 -07:00

315 lines
14 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Brightwheel Exporter Dashboard</title>
<link rel="stylesheet" href="dashboard.css">
<script src="../lib/jszip.min.js"></script>
</head>
<body>
<div class="app-layout">
<!-- Navigation Bar -->
<header class="top-nav">
<div class="nav-brand">
<div class="brand-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
<polyline points="7 10 12 15 17 10"></polyline>
<line x1="12" y1="15" x2="12" y2="3"></line>
</svg>
</div>
<div class="brand-text">
<h1>Brightwheel Exporter</h1>
<span>Memories & Reports Archiver</span>
</div>
</div>
<div class="session-badge" id="sessionBadge">
<span class="session-dot" id="sessionDot"></span>
<span id="sessionStatusText">Detecting Brightwheel Session...</span>
<button id="refreshSessionBtn" class="icon-btn" title="Refresh Session">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="23 4 23 10 17 10"></polyline>
<polyline points="1 20 1 14 7 14"></polyline>
<path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path>
</svg>
</button>
</div>
</header>
<!-- Main Content Grid -->
<main class="main-container">
<div class="dashboard-grid">
<!-- Left Panel: Configuration -->
<div class="config-column">
<!-- Card 1: Student Selection -->
<section class="card">
<div class="card-header">
<div class="card-title-group">
<span class="step-num">1</span>
<h2>Select Child / Student</h2>
</div>
</div>
<div class="card-content">
<div class="students-list" id="studentsList">
<div class="loading-placeholder">
<div class="spinner"></div>
<span>Scanning Brightwheel profile...</span>
</div>
</div>
<!-- Manual ID Fallback Accordion -->
<details class="manual-id-details" id="manualDetails">
<summary>Enter Student UUID Manually</summary>
<div class="manual-input-row">
<input type="text" id="manualStudentId" placeholder="Auto-detected from active Brightwheel tab, or enter UUID">
<button id="setManualIdBtn" class="secondary-btn">Use ID</button>
</div>
</details>
</div>
</section>
<!-- Card 2: Date Range -->
<section class="card">
<div class="card-header">
<div class="card-title-group">
<span class="step-num">2</span>
<h2>Date Range Filter</h2>
</div>
</div>
<div class="card-content">
<div class="quick-dates-pills" id="quickDatePills">
<button class="pill-btn active" data-range="all">All Time</button>
<button class="pill-btn" data-range="this-year">This Year</button>
<button class="pill-btn" data-range="last-year">Last Year</button>
<button class="pill-btn" data-range="last-90">Last 90 Days</button>
<button class="pill-btn" data-range="custom">Custom</button>
</div>
<div class="date-inputs-row" id="customDateRow">
<div class="date-field">
<label for="startDate">From</label>
<input type="date" id="startDate">
</div>
<div class="date-field">
<label for="endDate">To</label>
<input type="date" id="endDate">
</div>
</div>
</div>
</section>
<!-- Card 3: Export Categories -->
<section class="card">
<div class="card-header">
<div class="card-title-group">
<span class="step-num">3</span>
<h2>Export Categories</h2>
</div>
</div>
<div class="card-content">
<div class="checkbox-group">
<label class="custom-checkbox">
<input type="checkbox" id="catPhotos" checked>
<span class="checkmark"></span>
<div class="checkbox-label">
<strong>Photos & Videos</strong>
<small>High resolution original media files & captions</small>
</div>
</label>
<label class="custom-checkbox">
<input type="checkbox" id="catCare" checked>
<span class="checkmark"></span>
<div class="checkbox-label">
<strong>Daily Care Logs</strong>
<small>Meals, nap duration, potty checks, medications</small>
</div>
</label>
<label class="custom-checkbox">
<input type="checkbox" id="catMilestones" checked>
<span class="checkmark"></span>
<div class="checkbox-label">
<strong>Learning Milestones & Observations</strong>
<small>Curriculum tags, developmental notes, kudos</small>
</div>
</label>
<label class="custom-checkbox">
<input type="checkbox" id="catAttendance" checked>
<span class="checkmark"></span>
<div class="checkbox-label">
<strong>Attendance & Health Screening</strong>
<small>Check-in/out timestamps, temperature readings</small>
</div>
</label>
<label class="custom-checkbox">
<input type="checkbox" id="catMessages" checked>
<span class="checkmark"></span>
<div class="checkbox-label">
<strong>Staff Messages & Announcements</strong>
<small>Communication history between school & family</small>
</div>
</label>
</div>
</div>
</section>
<!-- Card 4: Destination & Output -->
<section class="card">
<div class="card-header">
<div class="card-title-group">
<span class="step-num">4</span>
<h2>Destination & Output</h2>
</div>
</div>
<div class="card-content">
<!-- Direct Folder Destination Picker (Recommended) -->
<div class="folder-destination-box" style="background: rgba(255, 107, 53, 0.05); border: 1.5px dashed var(--primary); border-radius: var(--radius-md); padding: 14px 16px; margin-bottom: 18px;">
<div style="display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 8px;">
<div style="display: flex; align-items: center; gap: 8px;">
<span style="font-size: 20px;">📁</span>
<div>
<strong style="font-size: 13.5px; color: var(--text);">Direct Local Folder Save</strong>
<span class="badge" style="background: var(--primary); color: #fff; font-size: 10px; padding: 2px 6px; border-radius: 4px; margin-left: 6px;">Fastest & Zero Lag</span>
</div>
</div>
<button type="button" id="chooseFolderBtn" class="secondary-btn" style="padding: 6px 12px; font-size: 12px; white-space: nowrap; border-color: var(--primary); color: var(--primary); font-weight: 600;">
Choose Folder...
</button>
</div>
<div id="folderStatusBox" style="font-size: 12px; color: var(--text-muted);">
<span id="folderPathText">No folder selected (will download as instant ZIP)</span>
<button type="button" id="clearFolderBtn" style="display: none; background: none; border: none; color: var(--error); font-size: 11px; text-decoration: underline; cursor: pointer; margin-left: 8px;">Reset</button>
</div>
<small style="display: block; margin-top: 6px; color: var(--text-muted); font-size: 11px;">
⚡ Streams photos & videos directly to your hard drive in real-time as they download. No zip compression delay!
</small>
</div>
<div class="checkbox-group">
<label class="custom-checkbox">
<input type="checkbox" id="fmtJson" checked>
<span class="checkmark"></span>
<div class="checkbox-label">
<strong>Unified JSON Archive (<code>activities.json</code>)</strong>
<small>Single source of truth containing all structured & raw data</small>
</div>
</label>
<label class="custom-checkbox">
<input type="checkbox" id="fmtCsv" checked>
<span class="checkmark"></span>
<div class="checkbox-label">
<strong>Spreadsheet CSV (<code>activities.csv</code>)</strong>
<small>Open in Excel, Numbers, or Google Sheets</small>
</div>
</label>
<label class="custom-checkbox">
<input type="checkbox" id="fmtViewer" checked>
<span class="checkmark"></span>
<div class="checkbox-label">
<strong>Offline Memories Web Viewer (<code>index.html</code>)</strong>
<small>Standalone interactive browser app with gallery & timeline</small>
</div>
</label>
</div>
</div>
</section>
</div>
<!-- Right Panel: Export Controller & Live Monitor -->
<div class="action-column">
<!-- Primary Action Box -->
<section class="card hero-action-card">
<div class="action-header">
<h3>Export Controller</h3>
<div class="speed-setting">
<label for="concurrencySelect">Pacing / Delay:</label>
<select id="concurrencySelect">
<option value="400">Gentle (400ms delay - Safest)</option>
<option value="200" selected>Standard (200ms delay)</option>
<option value="50">Fast (50ms delay)</option>
</select>
</div>
</div>
<div class="primary-controls">
<button id="startExportBtn" class="primary-action-btn">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
<polyline points="7 10 12 15 17 10"></polyline>
<line x1="12" y1="15" x2="12" y2="3"></line>
</svg>
<span>Start Complete Export</span>
</button>
<div class="secondary-controls-row" id="inProgressControls" style="display: none;">
<button id="pauseExportBtn" class="secondary-btn">Pause</button>
<button id="cancelExportBtn" class="danger-btn">Cancel</button>
</div>
</div>
<!-- Progress Bar Section -->
<div class="progress-section" id="progressSection">
<div class="progress-labels">
<span class="progress-status" id="progressStatusText">Ready to start</span>
<span class="progress-percentage" id="progressPercent">0%</span>
</div>
<div class="progress-bar-track">
<div class="progress-bar-fill" id="progressBarFill" style="width: 0%;"></div>
</div>
</div>
<!-- Live Metrics Grid -->
<div class="metrics-grid">
<div class="metric-card">
<span class="metric-value" id="metricActivitiesCount">0</span>
<span class="metric-label">Activities Found</span>
</div>
<div class="metric-card">
<span class="metric-value" id="metricMediaCount">0 / 0</span>
<span class="metric-label">Media Files</span>
</div>
<div class="metric-card">
<span class="metric-value" id="metricSize">0.0 MB</span>
<span class="metric-label">Downloaded Data</span>
</div>
<div class="metric-card">
<span class="metric-value" id="metricRateLimit">0</span>
<span class="metric-label">Retries / Backoffs</span>
</div>
</div>
</section>
<!-- Live Activity Log Card -->
<section class="card log-card">
<div class="card-header log-header">
<h3>Live Activity Log</h3>
<div class="log-actions">
<button id="inspectFeedBtn" class="link-btn" style="color: var(--primary); font-weight: 600; margin-right: 8px;">🔬 Inspect Live Tab</button>
<button id="clearLogBtn" class="link-btn">Clear</button>
</div>
</div>
<div class="terminal-log-body" id="terminalLog">
<div class="log-line info">[System] Exporter dashboard initialized. Waiting to begin...</div>
</div>
</section>
</div>
</div>
</main>
<footer class="dashboard-footer" style="text-align: center; padding: 24px 16px; color: var(--text-muted); font-size: 12px; border-top: 1px solid var(--border); margin-top: 40px;">
<p><strong>Disclaimer:</strong> This open-source extension is an independent, community-built tool and is not affiliated with, endorsed by, or sponsored by Brightwheel or its parent companies.</p>
<p style="margin-top: 4px; font-size: 11px; opacity: 0.85;">Runs 100% locally on your computer &bull; No personal data is ever collected, transmitted, or stored remotely.</p>
</footer>
</div>
<script src="dashboard.js"></script>
</body>
</html>