345 lines
18 KiB
PHP
345 lines
18 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/includes/bootstrap.php';
|
|
require_once __DIR__ . '/includes/FreeTier.php';
|
|
|
|
$uiLang = dbnToolsCurrentLanguage();
|
|
$isAuthed = dbnToolsIsAuthenticated();
|
|
$currentTier = $isAuthed ? dbnToolsCurrentTier() : 'free';
|
|
$surveyDone = false;
|
|
if ($isAuthed && dbnToolsIsFreeTier()) {
|
|
$surveyDone = FreeTier::hasCompletedSurvey((int)$_SESSION['dbn_tools_sso_uid']);
|
|
}
|
|
|
|
$status = (string)($_GET['status'] ?? '');
|
|
$loginUrl = 'https://dobetternorge.no/tools-login.php?return=' . urlencode('/pricing.php');
|
|
$surveyUrl = 'https://dobetternorge.no/survey.php';
|
|
|
|
function pt(string $key, string $lang): string {
|
|
return htmlspecialchars(dbnToolsT($key, $lang));
|
|
}
|
|
|
|
// New 3-tier NOK ladder. Plus carries a 14-day trial (card required, no charge for 14 days).
|
|
$tierNames = [
|
|
'free' => $uiLang === 'no' ? 'Gratis' : ($uiLang === 'uk' ? 'Безкоштовно' : ($uiLang === 'pl' ? 'Bezpłatnie' : 'Free')),
|
|
'plus' => 'Plus',
|
|
'pro' => $uiLang === 'no' ? 'Pro Familie' : ($uiLang === 'uk' ? 'Pro Сім\'я' : ($uiLang === 'pl' ? 'Pro Rodzina' : 'Pro Family')),
|
|
];
|
|
|
|
$creditsPerMonth = $uiLang === 'no' ? 'kreditter / mnd' : ($uiLang === 'uk' ? 'кредитів / міс' : ($uiLang === 'pl' ? 'kredytów / mies' : 'credits / mo'));
|
|
$perMonth = $uiLang === 'no' ? '/ måned' : ($uiLang === 'uk' ? '/ міс' : ($uiLang === 'pl' ? '/ mies' : '/ month'));
|
|
$capSuffix = $uiLang === 'no' ? '/ time' : ($uiLang === 'uk' ? '/ год' : ($uiLang === 'pl' ? '/ godz' : '/ hour'));
|
|
|
|
$tiers = [
|
|
[
|
|
'sku' => 'free',
|
|
'name' => $tierNames['free'],
|
|
'price' => 'NOK 0',
|
|
'period' => $uiLang === 'no' ? 'alltid' : 'always',
|
|
'credits' => '30 ' . $creditsPerMonth,
|
|
'storage' => $uiLang === 'no' ? 'Ingen saksoppbevaring' : 'No case storage',
|
|
'seats' => $uiLang === 'no' ? '1 bruker' : '1 user',
|
|
'cap' => '10 ' . $capSuffix,
|
|
'features' => $uiLang === 'no' ? [
|
|
'Alle 11 verktøy på innlimt tekst',
|
|
'Norsk juridisk korpus (~220K passasjer)',
|
|
'EU-vert (Tyskland / Finland / Norge)',
|
|
] : [
|
|
'All 11 tools on pasted text',
|
|
'Norwegian legal corpus (~220K passages)',
|
|
'EU-hosted (Germany / Finland / Norway)',
|
|
],
|
|
'cta' => $isAuthed ? null : dbnToolsT('pricing_cta_login', $uiLang),
|
|
'highlight' => false,
|
|
],
|
|
[
|
|
'sku' => 'plus',
|
|
'name' => $tierNames['plus'],
|
|
'price' => 'NOK 129',
|
|
'period' => $perMonth,
|
|
'credits' => '250 ' . $creditsPerMonth,
|
|
'storage' => '500 MB',
|
|
'seats' => $uiLang === 'no' ? '1 bruker' : '1 user',
|
|
'cap' => '20 ' . $capSuffix,
|
|
'features' => $uiLang === 'no' ? [
|
|
'Min Sak — last opp dokumenter med OCR',
|
|
'Bruk min sak som kontekst i alle verktøy',
|
|
'Lagrede analyser — alle resultater samlet',
|
|
'14 dagers gratis prøveperiode (kort kreves)',
|
|
] : [
|
|
'My Case — upload documents with OCR',
|
|
'Use my case as context in every tool',
|
|
'Saved analyses — every run kept and searchable',
|
|
'14-day free trial (card required)',
|
|
],
|
|
'highlight' => true,
|
|
'badge' => $uiLang === 'no' ? 'Mest populær' : 'Most popular',
|
|
],
|
|
[
|
|
'sku' => 'pro',
|
|
'name' => $tierNames['pro'],
|
|
'price' => 'NOK 299',
|
|
'period' => $perMonth,
|
|
'credits' => '1000 ' . $creditsPerMonth,
|
|
'storage' => '5 GB',
|
|
'seats' => $uiLang === 'no' ? '3 brukere · delt sak' : '3 users · shared case',
|
|
'cap' => '40 ' . $capSuffix,
|
|
'features' => $uiLang === 'no' ? [
|
|
'Alt i Plus, med mer plass og raskere modeller',
|
|
'Familie-sete: 3 innlogginger på samme sak',
|
|
'Prioritert GPT-4o for kompleks analyse',
|
|
'Audit-logg for hvem som kjørte hva',
|
|
] : [
|
|
'Everything in Plus, with more space and faster models',
|
|
'Family seats: 3 logins sharing one case',
|
|
'Priority GPT-4o for complex analysis',
|
|
'Audit log of who ran what',
|
|
],
|
|
'highlight' => false,
|
|
'badge' => $uiLang === 'no' ? 'For familier' : 'For families',
|
|
],
|
|
];
|
|
|
|
$topupNotes = [
|
|
'topup_s' => dbnToolsT('pricing_topup_s_note', $uiLang),
|
|
'topup_m' => dbnToolsT('pricing_topup_m_note', $uiLang),
|
|
'topup_l' => dbnToolsT('pricing_topup_l_note', $uiLang),
|
|
];
|
|
$topups = [
|
|
['sku' => 'topup_s', 'price' => 'NOK 49', 'credits' => 30, 'note' => $topupNotes['topup_s']],
|
|
['sku' => 'topup_m', 'price' => 'NOK 149', 'credits' => 100, 'note' => $topupNotes['topup_m']],
|
|
['sku' => 'topup_l', 'price' => 'NOK 399', 'credits' => 300, 'note' => $topupNotes['topup_l']],
|
|
];
|
|
?>
|
|
<!doctype html>
|
|
<html lang="<?= htmlspecialchars($uiLang) ?>">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title><?= pt('pricing_title_meta', $uiLang) ?></title>
|
|
<meta name="description" content="<?= pt('pricing_desc_meta', $uiLang) ?>">
|
|
<link rel="canonical" href="https://tools.dobetternorge.no/pricing.php">
|
|
<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">
|
|
<style>
|
|
.pricing-shell { max-width: 1200px; margin: 0 auto; padding: 2rem 1.5rem 4rem; }
|
|
.pricing-hero { text-align: center; margin-bottom: 3rem; }
|
|
.pricing-hero h1 { font-family: 'Crimson Pro', serif; font-size: 2.5rem; margin: 0 0 0.75rem; }
|
|
.pricing-hero p { color: #4b5563; font-size: 1.1rem; max-width: 640px; margin: 0 auto; }
|
|
.pricing-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1.25rem; margin-bottom: 3rem; }
|
|
.pricing-card { background: #fff; border: 1px solid #e5e7eb; border-radius: 12px; padding: 1.75rem 1.5rem; display: flex; flex-direction: column; position: relative; }
|
|
.pricing-card.is-highlight { border-color: #00205B; border-width: 2px; box-shadow: 0 8px 24px rgba(0,32,91,0.08); }
|
|
.pricing-card .pricing-badge { position: absolute; top: -10px; right: 14px; background: #00205B; color: #fff; padding: 4px 10px; font-size: 0.72rem; border-radius: 999px; letter-spacing: 0.04em; text-transform: uppercase; font-weight: 600; }
|
|
.pricing-card h2 { margin: 0 0 0.25rem; font-size: 1.4rem; font-family: 'Crimson Pro', serif; }
|
|
.pricing-price { display: flex; align-items: baseline; gap: 0.4rem; margin: 0.5rem 0 1rem; }
|
|
.pricing-price .amount { font-size: 2.2rem; font-weight: 700; color: #00205B; }
|
|
.pricing-price .period { color: #6b7280; font-size: 0.95rem; }
|
|
.pricing-meta { margin: 0 0 1.25rem; padding: 0; list-style: none; font-size: 0.92rem; color: #374151; }
|
|
.pricing-meta li { padding: 6px 0; border-bottom: 1px dashed #f3f4f6; }
|
|
.pricing-meta li:last-child { border-bottom: none; }
|
|
.pricing-features { list-style: none; padding: 0; margin: 0 0 1.5rem; flex: 1; }
|
|
.pricing-features li { padding: 5px 0 5px 1.4rem; position: relative; font-size: 0.92rem; color: #1f2937; }
|
|
.pricing-features li::before { content: "✓"; position: absolute; left: 0; color: #059669; font-weight: 700; }
|
|
.pricing-cta { display: block; text-align: center; padding: 0.75rem 1rem; border-radius: 8px; font-weight: 600; text-decoration: none; transition: all 0.15s; cursor: pointer; border: none; font-size: 0.95rem; }
|
|
.pricing-cta.primary { background: #00205B; color: #fff; }
|
|
.pricing-cta.primary:hover { background: #001740; }
|
|
.pricing-cta.secondary { background: #f3f4f6; color: #1f2937; }
|
|
.pricing-cta.secondary:hover { background: #e5e7eb; }
|
|
.pricing-cta.current { background: #d1fae5; color: #065f46; cursor: default; }
|
|
.pricing-topups { margin-top: 2rem; padding: 2rem 1.5rem; background: #f9fafb; border-radius: 12px; }
|
|
.pricing-topups h2 { font-family: 'Crimson Pro', serif; margin: 0 0 0.5rem; font-size: 1.6rem; }
|
|
.pricing-topups p.lead { color: #6b7280; margin: 0 0 1.5rem; }
|
|
.topup-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; }
|
|
.topup-card { background: #fff; border: 1px solid #e5e7eb; border-radius: 10px; padding: 1.25rem; text-align: center; }
|
|
.topup-card .price { font-size: 1.6rem; font-weight: 700; color: #00205B; }
|
|
.topup-card .credits { color: #374151; font-size: 0.95rem; margin: 0.25rem 0 0.5rem; }
|
|
.topup-card .note { color: #6b7280; font-size: 0.82rem; margin-bottom: 0.75rem; }
|
|
.survey-banner { background: linear-gradient(135deg, #00205B, #003478); color: #fff; padding: 1.75rem 1.5rem; border-radius: 12px; margin-bottom: 2rem; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem; }
|
|
.survey-banner .copy { flex: 1; min-width: 260px; }
|
|
.survey-banner h3 { margin: 0 0 0.35rem; font-size: 1.3rem; font-family: 'Crimson Pro', serif; }
|
|
.survey-banner p { margin: 0; opacity: 0.9; font-size: 0.95rem; }
|
|
.survey-banner a { background: #ffd166; color: #00205B; padding: 0.7rem 1.4rem; border-radius: 8px; font-weight: 700; text-decoration: none; white-space: nowrap; }
|
|
.pricing-faq { margin-top: 3rem; }
|
|
.pricing-faq details { background: #fff; border: 1px solid #e5e7eb; border-radius: 8px; padding: 1rem 1.25rem; margin-bottom: 0.6rem; }
|
|
.pricing-faq summary { font-weight: 600; cursor: pointer; }
|
|
.pricing-faq p { color: #4b5563; margin: 0.75rem 0 0; font-size: 0.92rem; }
|
|
.status-pill-info { display: inline-block; margin-bottom: 1.5rem; padding: 6px 12px; background: #fef3c7; color: #92400e; border-radius: 6px; font-size: 0.9rem; }
|
|
.status-pill-success { background: #d1fae5; color: #065f46; }
|
|
.status-pill-error { background: #fee2e2; color: #991b1b; }
|
|
.lang-bar { text-align: right; margin-bottom: 1rem; font-size: 0.85rem; }
|
|
.lang-bar a { margin-left: 0.5rem; color: #6b7280; text-decoration: none; padding: 2px 6px; border-radius: 4px; }
|
|
.lang-bar a.is-active { background: #00205B; color: #fff; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<main class="pricing-shell">
|
|
<div class="lang-bar">
|
|
<?php foreach (['no', 'en', 'uk', 'pl'] as $lc): ?>
|
|
<a href="?lang=<?= $lc ?>" class="<?= $lc === $uiLang ? 'is-active' : '' ?>"><?= htmlspecialchars(dbnToolsLanguageLabel($lc)) ?></a>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
|
|
<header class="pricing-hero">
|
|
<p style="margin:0 0 0.5rem; text-transform:uppercase; letter-spacing:0.08em; color:#6b7280; font-size:0.85rem;"><?= pt('pricing_eyebrow', $uiLang) ?></p>
|
|
<h1><?= pt('pricing_hero_title', $uiLang) ?></h1>
|
|
<p><?= pt('pricing_hero_sub', $uiLang) ?></p>
|
|
</header>
|
|
|
|
<?php if ($status === 'success'): ?>
|
|
<p class="status-pill-info status-pill-success"><?= pt('pricing_status_success', $uiLang) ?></p>
|
|
<?php elseif ($status === 'canceled'): ?>
|
|
<p class="status-pill-info"><?= pt('pricing_status_canceled', $uiLang) ?></p>
|
|
<?php endif; ?>
|
|
|
|
<div style="background:linear-gradient(135deg,#fef3c7,#fcd34d);color:#78350f;padding:1rem 1.5rem;border-radius:10px;margin-bottom:2rem;text-align:center;font-weight:600;">
|
|
<?= $uiLang === 'no'
|
|
? '🎉 Prøv Plus gratis i 14 dager — kort kreves, kanseller når som helst, ingen belastning før dag 15.'
|
|
: '🎉 Try Plus free for 14 days — card required, cancel anytime, no charge until day 15.' ?>
|
|
</div>
|
|
|
|
<?php if ($isAuthed && !$surveyDone): ?>
|
|
<div class="survey-banner">
|
|
<div class="copy">
|
|
<h3><?= pt('pricing_survey_title', $uiLang) ?></h3>
|
|
<p><?= pt('pricing_survey_text', $uiLang) ?></p>
|
|
</div>
|
|
<a href="<?= htmlspecialchars($surveyUrl) ?>"><?= pt('pricing_survey_cta', $uiLang) ?></a>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<section class="pricing-grid" aria-label="<?= pt('pricing_faq_title', $uiLang) ?>">
|
|
<?php foreach ($tiers as $tier): ?>
|
|
<article class="pricing-card<?= !empty($tier['highlight']) ? ' is-highlight' : '' ?>">
|
|
<?php if (!empty($tier['badge'])): ?>
|
|
<span class="pricing-badge"><?= htmlspecialchars($tier['badge']) ?></span>
|
|
<?php endif; ?>
|
|
<h2><?= htmlspecialchars($tier['name']) ?></h2>
|
|
<div class="pricing-price">
|
|
<span class="amount"><?= htmlspecialchars($tier['price']) ?></span>
|
|
<span class="period"><?= htmlspecialchars($tier['period']) ?></span>
|
|
</div>
|
|
<ul class="pricing-meta">
|
|
<li><?= htmlspecialchars($tier['credits']) ?></li>
|
|
<li><?= htmlspecialchars($tier['storage']) ?></li>
|
|
<li><?= htmlspecialchars($tier['seats']) ?></li>
|
|
<li><?= htmlspecialchars($tier['cap']) ?></li>
|
|
</ul>
|
|
<ul class="pricing-features">
|
|
<?php foreach ($tier['features'] as $feature): ?>
|
|
<li><?= htmlspecialchars($feature) ?></li>
|
|
<?php endforeach; ?>
|
|
</ul>
|
|
<?php if ($tier['sku'] === 'free'): ?>
|
|
<?php if (!$isAuthed): ?>
|
|
<a class="pricing-cta primary" href="<?= htmlspecialchars($loginUrl) ?>"><?= htmlspecialchars($tier['cta'] ?? dbnToolsT('pricing_cta_login', $uiLang)) ?></a>
|
|
<?php elseif ($currentTier === 'free'): ?>
|
|
<span class="pricing-cta current"><?= pt('pricing_cta_current', $uiLang) ?></span>
|
|
<?php else: ?>
|
|
<span class="pricing-cta secondary"><?= pt('pricing_cta_available', $uiLang) ?></span>
|
|
<?php endif; ?>
|
|
<?php else: ?>
|
|
<?php if (!$isAuthed): ?>
|
|
<a class="pricing-cta primary" href="<?= htmlspecialchars($loginUrl) ?>"><?= pt('pricing_cta_subscribe', $uiLang) ?></a>
|
|
<?php elseif ($currentTier === $tier['sku']): ?>
|
|
<span class="pricing-cta current"><?= pt('pricing_cta_current', $uiLang) ?></span>
|
|
<?php else: ?>
|
|
<button type="button" class="pricing-cta primary" data-sku="<?= htmlspecialchars($tier['sku']) ?>" data-checkout="subscription">
|
|
<?= pt('pricing_cta_choose', $uiLang) ?> <?= htmlspecialchars($tier['name']) ?>
|
|
</button>
|
|
<?php endif; ?>
|
|
<?php endif; ?>
|
|
</article>
|
|
<?php endforeach; ?>
|
|
</section>
|
|
|
|
<section class="pricing-topups" aria-label="<?= pt('pricing_topup_title', $uiLang) ?>">
|
|
<h2><?= pt('pricing_topup_title', $uiLang) ?></h2>
|
|
<p class="lead"><?= pt('pricing_topup_lead', $uiLang) ?></p>
|
|
<div class="topup-grid">
|
|
<?php foreach ($topups as $topup): ?>
|
|
<div class="topup-card">
|
|
<div class="price"><?= htmlspecialchars($topup['price']) ?></div>
|
|
<div class="credits"><?= (int)$topup['credits'] ?> <?= pt('pricing_credits_label', $uiLang) ?></div>
|
|
<div class="note"><?= htmlspecialchars($topup['note']) ?></div>
|
|
<?php if ($isAuthed): ?>
|
|
<button type="button" class="pricing-cta primary" data-sku="<?= htmlspecialchars($topup['sku']) ?>" data-checkout="topup"><?= pt('pricing_topup_buy', $uiLang) ?></button>
|
|
<?php else: ?>
|
|
<a class="pricing-cta primary" href="<?= htmlspecialchars($loginUrl) ?>"><?= pt('pricing_login_first', $uiLang) ?></a>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="pricing-faq" aria-label="<?= pt('pricing_faq_title', $uiLang) ?>">
|
|
<h2 style="font-family:'Crimson Pro', serif; margin-bottom:1rem;"><?= pt('pricing_faq_title', $uiLang) ?></h2>
|
|
<details>
|
|
<summary><?= pt('pricing_faq1_q', $uiLang) ?></summary>
|
|
<p><?= pt('pricing_faq1_a', $uiLang) ?></p>
|
|
</details>
|
|
<details>
|
|
<summary><?= pt('pricing_faq2_q', $uiLang) ?></summary>
|
|
<p><?= pt('pricing_faq2_a', $uiLang) ?></p>
|
|
</details>
|
|
<details>
|
|
<summary><?= pt('pricing_faq3_q', $uiLang) ?></summary>
|
|
<p><?= pt('pricing_faq3_a', $uiLang) ?></p>
|
|
</details>
|
|
<details>
|
|
<summary><?= pt('pricing_faq4_q', $uiLang) ?></summary>
|
|
<p><?= pt('pricing_faq4_a', $uiLang) ?></p>
|
|
</details>
|
|
<details>
|
|
<summary><?= pt('pricing_faq5_q', $uiLang) ?></summary>
|
|
<p><?= pt('pricing_faq5_a', $uiLang) ?></p>
|
|
</details>
|
|
<details>
|
|
<summary><?= pt('pricing_faq6_q', $uiLang) ?></summary>
|
|
<p><?= pt('pricing_faq6_a', $uiLang) ?></p>
|
|
</details>
|
|
</section>
|
|
</main>
|
|
|
|
<script>
|
|
(function() {
|
|
const connecting = <?= json_encode(dbnToolsT('pricing_connecting', $uiLang)) ?>;
|
|
const errorRetry = <?= json_encode(dbnToolsT('pricing_error_retry', $uiLang)) ?>;
|
|
const errorMsg = <?= json_encode(dbnToolsT('pricing_error_checkout', $uiLang)) ?>;
|
|
|
|
const buttons = document.querySelectorAll('button[data-checkout]');
|
|
buttons.forEach(btn => {
|
|
btn.addEventListener('click', async () => {
|
|
const sku = btn.getAttribute('data-sku');
|
|
btn.disabled = true;
|
|
const original = btn.textContent;
|
|
btn.textContent = connecting;
|
|
try {
|
|
const res = await fetch('/api/stripe-checkout.php', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ sku })
|
|
});
|
|
const data = await res.json();
|
|
if (data.ok && data.url) {
|
|
window.location.href = data.url;
|
|
} else {
|
|
btn.textContent = errorRetry;
|
|
alert(data.error?.message || errorMsg);
|
|
}
|
|
} catch (e) {
|
|
btn.textContent = original;
|
|
alert(e.message);
|
|
} finally {
|
|
setTimeout(() => { btn.disabled = false; btn.textContent = original; }, 1500);
|
|
}
|
|
});
|
|
});
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|