ba9cddf9a1
- Stripe: StripeClient.php, checkout/portal/webhook endpoints, idempotent event handling - FreeTier: tier-aware credits (free/light/pro/pro_plus), bonus_balance, hourly caps per tier - pricing.php + billing.php: 4-tier cards, 3 topups, Customer Portal, balance breakdown - Min Sak: CaseStore.php, AzureDocIntelligence.php, AzureSearchAdmin.php — per-user hybrid RAG - api/case/: upload, list, delete, ingest-callback (HMAC-auth'd from n8n) - award-survey-credits: inter-site HMAC endpoint for dobetternorge.no survey bonus - dashboard.php: tier badge, balance breakdown card, Min Sak CTA, survey CTA - KorrespondAgent + all 3 other agents: use_my_case toggle wired to dbnToolsCaseContext() - bootstrap.php: dbnToolsCaseContext(), dbnToolsIntersiteSecret(), dbnToolsCurrentTier() Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
194 lines
10 KiB
PHP
194 lines
10 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/includes/bootstrap.php';
|
|
|
|
if (!dbnToolsIsAuthenticated()) {
|
|
header('Location: /?return=' . urlencode($_SERVER['REQUEST_URI'] ?? '/workbench.php'));
|
|
exit;
|
|
}
|
|
|
|
$uiLang = dbnToolsCurrentLanguage();
|
|
$copy = dbnToolsWorkbenchCopy($uiLang);
|
|
$langPath = '/workbench.php';
|
|
|
|
?>
|
|
<!doctype html>
|
|
<html lang="<?= htmlspecialchars($uiLang) ?>">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title><?= htmlspecialchars($copy['title']) ?> - Do Better Norge</title>
|
|
<meta name="robots" content="noindex, nofollow">
|
|
<meta name="theme-color" content="#00205B">
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Crimson+Pro:wght@400;600;700&family=IBM+Plex+Sans:wght@400;500;600;700&display=swap">
|
|
<link rel="stylesheet" href="assets/css/tools.css">
|
|
</head>
|
|
<body data-authenticated="true" class="lt-app workbench-page">
|
|
<script>
|
|
window.DBN_TOOLS_AUTHENTICATED = true;
|
|
window.DBN_TOOLS_LANG = <?= json_encode($uiLang, JSON_UNESCAPED_UNICODE) ?>;
|
|
</script>
|
|
|
|
<main id="appShell" class="app-shell workbench-shell">
|
|
<header class="topbar">
|
|
<div>
|
|
<p class="eyebrow"><?= htmlspecialchars(dbnToolsT('brand_line', $uiLang)) ?></p>
|
|
<h1><?= htmlspecialchars($copy['title']) ?></h1>
|
|
<div class="case-no">
|
|
<span class="pulse"></span>
|
|
<span>family-legal</span>
|
|
<span class="case-sep">.</span>
|
|
<span><?= htmlspecialchars(dbnToolsT('retention', $uiLang)) ?></span>
|
|
</div>
|
|
</div>
|
|
<div class="topbar-actions">
|
|
<nav class="shell-lang-switcher" aria-label="Language">
|
|
<?php foreach (dbnToolsSupportedLanguages() as $langCode): ?>
|
|
<a href="<?= htmlspecialchars($langPath . '?lang=' . $langCode) ?>" class="<?= $langCode === $uiLang ? 'is-active' : '' ?>"><?= htmlspecialchars(dbnToolsLanguageLabel($langCode)) ?></a>
|
|
<?php endforeach; ?>
|
|
</nav>
|
|
<a class="secondary-button workbench-dashboard-link" href="/dashboard.php"><?= htmlspecialchars($copy['all_tools']) ?></a>
|
|
<span id="healthPill" class="status-pill"><?= htmlspecialchars(dbnToolsT('session_active', $uiLang)) ?></span>
|
|
<button id="healthButton" class="secondary-button" type="button"><?= htmlspecialchars(dbnToolsT('health', $uiLang)) ?></button>
|
|
</div>
|
|
</header>
|
|
|
|
<section class="workbench-hero" aria-labelledby="workbenchHeroTitle">
|
|
<div class="workbench-hero__copy">
|
|
<p class="workbench-kicker"><?= htmlspecialchars($copy['kicker']) ?></p>
|
|
<h2 id="workbenchHeroTitle"><?= htmlspecialchars($copy['hero_title']) ?></h2>
|
|
<p><?= htmlspecialchars($copy['hero_text']) ?></p>
|
|
</div>
|
|
<div class="workbench-hero__panel" aria-label="<?= htmlspecialchars($copy['privacy_title']) ?>">
|
|
<strong><?= htmlspecialchars($copy['privacy_title']) ?></strong>
|
|
<p><?= htmlspecialchars($copy['privacy_text']) ?></p>
|
|
<button id="workbenchClear" class="workbench-clear" type="button"><?= htmlspecialchars($copy['clear_session']) ?></button>
|
|
<p id="workbenchStatus" class="workbench-status" role="status" aria-live="polite"></p>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="disclaimer" role="note"><?= htmlspecialchars(dbnToolsT('disclaimer', $uiLang)) ?></div>
|
|
|
|
<form id="workbenchForm" class="workbench-grid" autocomplete="off">
|
|
<section class="workbench-panel workbench-panel--intake" aria-labelledby="workbenchIntakeTitle">
|
|
<div class="workbench-section-head">
|
|
<p class="workbench-kicker">01</p>
|
|
<h2 id="workbenchIntakeTitle"><?= htmlspecialchars($copy['intake_title']) ?></h2>
|
|
</div>
|
|
<div class="workbench-form-grid">
|
|
<label class="workbench-field" for="wbRole">
|
|
<span><?= htmlspecialchars($copy['role']) ?></span>
|
|
<select id="wbRole" name="role">
|
|
<option value=""><?= htmlspecialchars($copy['choose']) ?></option>
|
|
<option><?= htmlspecialchars($copy['role_parent']) ?></option>
|
|
<option><?= htmlspecialchars($copy['role_family']) ?></option>
|
|
<option><?= htmlspecialchars($copy['role_advocate']) ?></option>
|
|
<option><?= htmlspecialchars($copy['role_supporter']) ?></option>
|
|
</select>
|
|
</label>
|
|
<label class="workbench-field" for="wbCaseType">
|
|
<span><?= htmlspecialchars($copy['case_type']) ?></span>
|
|
<select id="wbCaseType" name="case_type">
|
|
<option value=""><?= htmlspecialchars($copy['choose']) ?></option>
|
|
<option><?= htmlspecialchars($copy['case_barnevernet']) ?></option>
|
|
<option><?= htmlspecialchars($copy['case_custody']) ?></option>
|
|
<option><?= htmlspecialchars($copy['case_access']) ?></option>
|
|
<option><?= htmlspecialchars($copy['case_echr']) ?></option>
|
|
</select>
|
|
</label>
|
|
<label class="workbench-field" for="wbDeadline">
|
|
<span><?= htmlspecialchars($copy['deadline']) ?></span>
|
|
<input id="wbDeadline" name="deadline" type="date">
|
|
</label>
|
|
<label class="workbench-field" for="wbLanguage">
|
|
<span><?= htmlspecialchars($copy['language']) ?></span>
|
|
<select id="wbLanguage" name="language">
|
|
<option>English</option>
|
|
<option>Norwegian</option>
|
|
<option>Ukrainian</option>
|
|
<option>Polish</option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
<label class="workbench-field workbench-field--wide" for="wbConcern">
|
|
<span><?= htmlspecialchars($copy['main_concern']) ?></span>
|
|
<textarea id="wbConcern" name="main_concern" rows="5" placeholder="<?= htmlspecialchars($copy['main_concern_hint']) ?>"></textarea>
|
|
</label>
|
|
</section>
|
|
|
|
<section class="workbench-panel workbench-panel--evidence" aria-labelledby="workbenchEvidenceTitle">
|
|
<div class="workbench-section-head">
|
|
<p class="workbench-kicker">02</p>
|
|
<h2 id="workbenchEvidenceTitle"><?= htmlspecialchars($copy['evidence_title']) ?></h2>
|
|
</div>
|
|
<div class="workbench-evidence-list">
|
|
<?php
|
|
$evidenceFields = [
|
|
['documents', $copy['documents'], $copy['documents_hint']],
|
|
['meetings', $copy['meetings'], $copy['meetings_hint']],
|
|
['dates', $copy['dates'], $copy['dates_hint']],
|
|
['claims', $copy['claims'], $copy['claims_hint']],
|
|
['missing', $copy['missing'], $copy['missing_hint']],
|
|
];
|
|
foreach ($evidenceFields as [$name, $label, $hint]):
|
|
$id = 'wb' . ucfirst($name);
|
|
?>
|
|
<label class="workbench-field" for="<?= htmlspecialchars($id) ?>">
|
|
<span><?= htmlspecialchars($label) ?></span>
|
|
<textarea id="<?= htmlspecialchars($id) ?>" name="<?= htmlspecialchars($name) ?>" rows="4" placeholder="<?= htmlspecialchars($hint) ?>"></textarea>
|
|
</label>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="workbench-panel workbench-panel--outputs" aria-labelledby="workbenchOutputsTitle">
|
|
<div class="workbench-section-head">
|
|
<p class="workbench-kicker">03</p>
|
|
<h2 id="workbenchOutputsTitle"><?= htmlspecialchars($copy['outputs_title']) ?></h2>
|
|
</div>
|
|
<div class="workbench-checklist">
|
|
<?php foreach (['lawyer', 'barnevernet_response', 'meeting_prep', 'strasbourg'] as $outputKey): ?>
|
|
<label class="workbench-check">
|
|
<input type="checkbox" name="outputs[]" value="<?= htmlspecialchars($outputKey) ?>">
|
|
<span><?= htmlspecialchars($copy['output_' . $outputKey]) ?></span>
|
|
</label>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<label class="workbench-field workbench-field--wide" for="wbNextStep">
|
|
<span><?= htmlspecialchars($copy['next_step']) ?></span>
|
|
<textarea id="wbNextStep" name="next_step" rows="4" placeholder="<?= htmlspecialchars($copy['next_step_hint']) ?>"></textarea>
|
|
</label>
|
|
</section>
|
|
</form>
|
|
|
|
<section class="workbench-panel workbench-panel--docs" aria-labelledby="workbenchDocsTitle"
|
|
data-my-docs="true">
|
|
<div class="workbench-section-head">
|
|
<p class="workbench-kicker">04</p>
|
|
<h2 id="workbenchDocsTitle"><?= htmlspecialchars(dbnToolsT('my_docs_title', $uiLang)) ?></h2>
|
|
</div>
|
|
<p class="workbench-docs__desc"><?= htmlspecialchars(dbnToolsT('my_docs_desc', $uiLang)) ?></p>
|
|
<div class="upload-zone" id="wbUploadZone" role="region" aria-label="Upload documents">
|
|
<input type="file" id="wbUploadInput" multiple accept=".pdf,.docx,.txt" aria-label="Choose files">
|
|
<div class="upload-prompt">
|
|
<span class="upload-icon" aria-hidden="true">⇧</span>
|
|
<p>Drop files here or <label for="wbUploadInput" class="upload-browse">browse</label></p>
|
|
<p class="upload-hint"><strong>PDF</strong>, <strong>DOCX</strong>, <strong>TXT</strong> — stored for this case.</p>
|
|
</div>
|
|
</div>
|
|
<p id="wbUploadStatus" class="workbench-status" role="status" aria-live="polite" style="margin:8px 0 4px;"></p>
|
|
<div id="myDocsList" class="workbench-docs__list" role="list" aria-live="polite">
|
|
<p class="workbench-docs__loading"><?= htmlspecialchars(dbnToolsT('loading', $uiLang)) ?></p>
|
|
</div>
|
|
</section>
|
|
|
|
</main>
|
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
|
<script src="assets/js/tools.js" defer></script>
|
|
<script src="assets/js/workbench.js" defer></script>
|
|
</body>
|
|
</html>
|