mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-05-19 12:50:11 -05:00
b0dde80ba9
Add a support modal with usage stats, tier and license links, share control, and offline-safe outbound CTAs. Surface support from the header, sidebar, user menu, dashboard card, and settings "Support & Community" section without hiding entry points when a supporter license is active. Introduce UsageStatsService and a persisted users.support_stats_reports_generated counter incremented on key report exports and custom report views. Add SupportPromptService for session-scoped soft toasts (after export, dashboard milestones, long session via POST /donate/request-soft-prompt). Wire consent-aware track_event names support.* and mirror funnel rows in DonationInteraction; fix has_recent_donation_click to treat link_clicked as a recent click. Document events and SUPPORT_* / migration notes in docs. Tests: tests/test_support_services.py for prompt and usage stats behavior.
57 lines
4.7 KiB
HTML
57 lines
4.7 KiB
HTML
{# Support & donation modal — strings use Flask-Babel; stats from support_usage_stats_modal #}
|
|
{% set s = support_usage_stats_modal or {} %}
|
|
<div id="supportModal" class="fixed inset-0 z-[100] hidden" aria-hidden="true" role="dialog" aria-labelledby="supportModalTitle" aria-modal="true">
|
|
<div class="absolute inset-0 bg-black/50" data-support-modal-overlay tabindex="-1"></div>
|
|
<div class="relative max-w-lg mx-auto mt-16 sm:mt-24 mb-8 px-4 max-h-[calc(100vh-4rem)] overflow-y-auto">
|
|
<div class="bg-card-light dark:bg-card-dark text-text-light dark:text-text-dark rounded-xl shadow-xl border border-border-light dark:border-border-dark">
|
|
<div class="flex items-start justify-between gap-3 p-5 border-b border-border-light dark:border-border-dark">
|
|
<div>
|
|
<h2 id="supportModalTitle" class="text-lg font-semibold">{{ _('Support TimeTracker') }}</h2>
|
|
<p class="text-sm text-text-muted-light dark:text-text-muted-dark mt-1">
|
|
{% if is_license_activated %}
|
|
{{ _('Thank you for being a supporter. Sharing the app helps others discover it too.') }}
|
|
{% else %}
|
|
{{ _('TimeTracker is free and built independently. If it helps you, consider supporting its development.') }}
|
|
{% endif %}
|
|
</p>
|
|
</div>
|
|
<button type="button" class="p-2 rounded-lg hover:bg-background-light dark:hover:bg-background-dark text-text-muted-light" data-support-modal-close aria-label="{{ _('Close') }}">
|
|
<i class="fas fa-times" aria-hidden="true"></i>
|
|
</button>
|
|
</div>
|
|
<div class="p-5 space-y-4">
|
|
<div class="grid grid-cols-3 gap-2 text-center text-sm">
|
|
<div class="rounded-lg bg-background-light dark:bg-background-dark p-3">
|
|
<div class="text-xs text-text-muted-light dark:text-text-muted-dark">{{ _('Hours tracked') }}</div>
|
|
<div class="font-semibold tabular-nums" id="supportStatHours">{{ '%.1f'|format(s.get('total_hours', 0)|float) }}</div>
|
|
</div>
|
|
<div class="rounded-lg bg-background-light dark:bg-background-dark p-3">
|
|
<div class="text-xs text-text-muted-light dark:text-text-muted-dark">{{ _('Entries') }}</div>
|
|
<div class="font-semibold tabular-nums" id="supportStatEntries">{{ s.get('time_entries_count', 0)|int }}</div>
|
|
</div>
|
|
<div class="rounded-lg bg-background-light dark:bg-background-dark p-3">
|
|
<div class="text-xs text-text-muted-light dark:text-text-muted-dark">{{ _('Reports') }}</div>
|
|
<div class="font-semibold tabular-nums" id="supportStatReports">{{ s.get('reports_generated_count', 0)|int }}</div>
|
|
</div>
|
|
</div>
|
|
<p id="supportSocialLine" class="text-xs text-text-muted-light dark:text-text-muted-dark text-center">{{ _('Trusted by teams and freelancers who want simple, reliable time tracking.') }}</p>
|
|
<p id="supportModalOffline" class="hidden text-sm text-amber-700 dark:text-amber-300"></p>
|
|
<div class="flex flex-col sm:flex-row gap-2">
|
|
<a href="#" rel="noopener noreferrer" data-support-tier="eur5" class="support-tier-btn btn btn-secondary text-center flex-1">{{ _('Donate') }} (€5)</a>
|
|
<a href="#" rel="noopener noreferrer" data-support-tier="eur10" class="support-tier-btn btn btn-secondary text-center flex-1">{{ _('Donate') }} (€10)</a>
|
|
<a href="#" rel="noopener noreferrer" data-support-tier="eur25" class="support-tier-btn btn btn-secondary text-center flex-1">{{ _('Donate') }} (€25)</a>
|
|
</div>
|
|
<div class="flex flex-col sm:flex-row gap-2">
|
|
<a href="{{ support_purchase_url }}" target="_blank" rel="noopener noreferrer" data-support-tier="license" class="btn btn-primary text-center flex-1">
|
|
{{ _('Buy license (€25)') }} <i class="fas fa-external-link-alt text-xs ml-1" aria-hidden="true"></i>
|
|
</a>
|
|
<button type="button" id="supportShareBtn" class="btn btn-secondary text-center flex-1">{{ _('Love TimeTracker? Share it') }}</button>
|
|
</div>
|
|
<p class="text-xs text-text-muted-light dark:text-text-muted-dark">
|
|
{{ _('A license is a supporter badge — it does not lock features. You keep full access either way.') }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|