Lizenzmodell: Plan-Anzeige in Einstellungen, SEPA-Gate für Free-Plan
This commit is contained in:
parent
b8e2a69912
commit
95c2dc0f26
2 changed files with 119 additions and 7 deletions
|
|
@ -20,6 +20,11 @@
|
|||
let saving = $state(false);
|
||||
let formError = $state('');
|
||||
|
||||
// Plan-Check
|
||||
const hatSepa = $derived(
|
||||
verein?.plan && ['starter', 'wachstum', 'verband'].includes(verein.plan)
|
||||
);
|
||||
|
||||
// --- SEPA-Export ---
|
||||
let sepaFor = $state<Beitrag | null>(null);
|
||||
let einzugsdatum = $state(minEinzugsdatum());
|
||||
|
|
@ -189,9 +194,14 @@
|
|||
<button class="btn-primary" onclick={neuerBeitrag}>+ Beitragsart</button>
|
||||
</div>
|
||||
|
||||
{#if sepaFehlt && !loading}
|
||||
{#if !loading && !hatSepa}
|
||||
<div class="plan-hinweis">
|
||||
<strong>SEPA-Export</strong> ist im <strong>Starter-Plan</strong> verfügbar (7 €/Monat).
|
||||
<a href="/einstellungen">Jetzt upgraden →</a>
|
||||
</div>
|
||||
{:else if sepaFehlt && !loading}
|
||||
<div class="hinweis">
|
||||
SEPA-Einzug nicht möglich: Gläubiger-ID, IBAN und BIC des Vereins fehlen noch in den Einstellungen.
|
||||
SEPA-Einzug nicht möglich: Gläubiger-ID, IBAN und BIC des Vereins fehlen noch in den <a href="/einstellungen">Einstellungen</a>.
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
|
@ -214,7 +224,7 @@
|
|||
</span>
|
||||
</div>
|
||||
<div class="karte-aktionen">
|
||||
<button class="btn-sepa" onclick={() => sepaOeffnen(b)} disabled={sepaFehlt}>
|
||||
<button class="btn-sepa" onclick={() => sepaOeffnen(b)} disabled={sepaFehlt || !hatSepa}>
|
||||
SEPA
|
||||
</button>
|
||||
<button class="btn-icon" onclick={() => bearbeiten(b)} title="Bearbeiten">✎</button>
|
||||
|
|
@ -344,6 +354,12 @@
|
|||
}
|
||||
h1 { font-size: 1.4rem; font-weight: 700; color: #1e293b; }
|
||||
|
||||
.plan-hinweis {
|
||||
background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 8px;
|
||||
padding: 0.75rem 1rem; font-size: 0.875rem; color: #1e40af; margin-bottom: 1rem;
|
||||
}
|
||||
.plan-hinweis a { color: #1e40af; font-weight: 700; }
|
||||
|
||||
.hinweis {
|
||||
background: #fef9c3;
|
||||
border: 1px solid #fde047;
|
||||
|
|
@ -353,6 +369,7 @@
|
|||
color: #713f12;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.hinweis a { color: #713f12; }
|
||||
|
||||
.hint { color: #94a3b8; font-size: 0.95rem; text-align: center; margin-top: 3rem; }
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@
|
|||
let iban = $state('');
|
||||
let bic = $state('');
|
||||
|
||||
// Plan
|
||||
let plan = $state<Verein['plan']>('free');
|
||||
let mitgliederAnz = $state(0);
|
||||
|
||||
// Trainer
|
||||
let trainer = $state<any[]>([]);
|
||||
let gruppen = $state<Gruppe[]>([]);
|
||||
|
|
@ -34,6 +38,17 @@
|
|||
|
||||
let vereinId = $state('');
|
||||
|
||||
const planInfo: Record<string, { label: string; farbe: string; features: string[]; limit: number | null }> = {
|
||||
free: { label: 'Kostenlos', farbe: '#64748b', limit: 50, features: ['Bis 50 Mitglieder', 'Termine & Wiederholungen', 'Nachrichten & Push', 'Veranstaltungsorte', 'Durchführende einladen'] },
|
||||
starter: { label: 'Starter', farbe: '#1e40af', limit: 150, features: ['Bis 150 Mitglieder', 'SEPA pain.008-Export', 'iCal-Kalender-Abo', 'Alle Free-Features'] },
|
||||
wachstum:{ label: 'Verband', farbe: '#7c3aed', limit: null, features: ['Unbegrenzte Mitglieder', 'Mehrere Admins', 'Prioritäts-Support', 'Alle Starter-Features'] },
|
||||
verband: { label: 'Verband', farbe: '#7c3aed', limit: null, features: ['Unbegrenzte Mitglieder', 'Mehrere Admins', 'Prioritäts-Support', 'Alle Starter-Features'] },
|
||||
};
|
||||
|
||||
const istFree = $derived(plan === 'free');
|
||||
const istStarter = $derived(plan === 'starter' || plan === 'wachstum' || plan === 'verband');
|
||||
const limitErreicht = $derived(istFree && mitgliederAnz > 50);
|
||||
|
||||
const bundeslaender = [
|
||||
['', '—'],
|
||||
['BW', 'Baden-Württemberg'], ['BY', 'Bayern'], ['BE', 'Berlin'],
|
||||
|
|
@ -46,15 +61,18 @@
|
|||
|
||||
onMount(async () => {
|
||||
vereinId = pb.authStore.record?.verein_id as string;
|
||||
const [v, alleUser, alleGruppen] = await Promise.all([
|
||||
const [v, alleUser, alleGruppen, mitgliederCount] = await Promise.all([
|
||||
pb.collection('vereine').getOne<Verein>(vereinId),
|
||||
isAdmin()
|
||||
? pb.collection('users').getFullList({ filter: `verein_id = "${vereinId}"` })
|
||||
: Promise.resolve([]),
|
||||
pb.collection('gruppen').getFullList<Gruppe>({ sort: 'name' }),
|
||||
pb.collection('mitglieder').getList(1, 1, { filter: `verein_id = "${vereinId}"` }).then(r => r.totalItems),
|
||||
]);
|
||||
trainer = alleUser.filter((u: any) => u.rolle === 'trainer');
|
||||
gruppen = alleGruppen;
|
||||
trainer = alleUser.filter((u: any) => u.rolle === 'trainer');
|
||||
gruppen = alleGruppen;
|
||||
plan = v.plan ?? 'free';
|
||||
mitgliederAnz = mitgliederCount;
|
||||
name = v.name ?? '';
|
||||
adresse = v.adresse ?? '';
|
||||
plz = v.plz ?? '';
|
||||
|
|
@ -129,6 +147,47 @@
|
|||
{#if loading}
|
||||
<p class="hint">Laden…</p>
|
||||
{:else}
|
||||
|
||||
<!-- Plan-Übersicht -->
|
||||
{@const pi = planInfo[plan] ?? planInfo.free}
|
||||
<div class="plan-card">
|
||||
<div class="plan-header">
|
||||
<div>
|
||||
<span class="plan-label" style="color:{pi.farbe}">{pi.label}</span>
|
||||
{#if pi.limit}
|
||||
<span class="plan-limit">bis {pi.limit} Mitglieder</span>
|
||||
{:else}
|
||||
<span class="plan-limit">unbegrenzte Mitglieder</span>
|
||||
{/if}
|
||||
</div>
|
||||
<span class="plan-mitglieder" class:warn={limitErreicht}>
|
||||
{mitgliederAnz} Mitglieder
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{#if limitErreicht}
|
||||
<div class="plan-warn">
|
||||
⚠ Du hast das Limit von 50 Mitgliedern überschritten. Neue Mitglieder können nicht angelegt werden.
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<ul class="plan-features">
|
||||
{#each pi.features as f}
|
||||
<li>✓ {f}</li>
|
||||
{/each}
|
||||
{#if istFree}
|
||||
<li class="gesperrt">✗ SEPA-Export <span class="upgrade-hint">Starter</span></li>
|
||||
<li class="gesperrt">✗ iCal-Kalender-Abo <span class="upgrade-hint">Starter</span></li>
|
||||
{/if}
|
||||
</ul>
|
||||
|
||||
{#if istFree}
|
||||
<a href="mailto:info@vereins.haus?subject=Upgrade%20auf%20Starter&body=Vereins-ID%3A%20{vereinId}" class="btn-upgrade">
|
||||
Auf Starter upgraden – 7 €/Monat →
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<form onsubmit={(e) => { e.preventDefault(); speichern(); }}>
|
||||
|
||||
<section>
|
||||
|
|
@ -275,7 +334,43 @@
|
|||
{/if}
|
||||
|
||||
<style>
|
||||
h1 { font-size: 1.4rem; font-weight: 700; color: #1e293b; margin-bottom: 1.5rem; }
|
||||
h1 { font-size: 1.4rem; font-weight: 700; color: #1e293b; margin-bottom: 1rem; }
|
||||
|
||||
/* Plan */
|
||||
.plan-card {
|
||||
background: #fff; border: 1.5px solid #e2e8f0; border-radius: 12px;
|
||||
padding: 1rem 1.1rem; margin-bottom: 1.5rem;
|
||||
}
|
||||
.plan-header {
|
||||
display: flex; justify-content: space-between; align-items: baseline;
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
.plan-label { font-size: 1rem; font-weight: 700; }
|
||||
.plan-limit { font-size: 0.78rem; color: #94a3b8; margin-left: 0.4rem; }
|
||||
.plan-mitglieder { font-size: 0.82rem; color: #64748b; }
|
||||
.plan-mitglieder.warn { color: #dc2626; font-weight: 700; }
|
||||
.plan-warn {
|
||||
background: #fef2f2; border: 1px solid #fca5a5; border-radius: 8px;
|
||||
padding: 0.6rem 0.8rem; font-size: 0.82rem; color: #dc2626; margin-bottom: 0.75rem;
|
||||
}
|
||||
.plan-features {
|
||||
list-style: none; padding: 0; margin: 0 0 0.85rem;
|
||||
display: flex; flex-direction: column; gap: 0.25rem;
|
||||
}
|
||||
.plan-features li { font-size: 0.85rem; color: #475569; }
|
||||
.plan-features li.gesperrt { color: #94a3b8; }
|
||||
.upgrade-hint {
|
||||
display: inline-block; font-size: 0.7rem; font-weight: 700;
|
||||
background: #e0e7ff; color: #1e40af; border-radius: 4px;
|
||||
padding: 0.05rem 0.35rem; margin-left: 0.3rem;
|
||||
}
|
||||
.btn-upgrade {
|
||||
display: block; width: 100%; padding: 0.65rem;
|
||||
background: #1e40af; color: #fff; border: none; border-radius: 8px;
|
||||
font-size: 0.9rem; font-weight: 600; text-align: center;
|
||||
text-decoration: none; transition: background 0.15s;
|
||||
}
|
||||
.btn-upgrade:hover { background: #1d3a9e; }
|
||||
|
||||
section {
|
||||
margin-bottom: 1.5rem;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue