//! Templates for creator dashboards, admin panels, and account management. use askama::Template; use crate::auth::SessionUser; use crate::types::{ AdminAppealRow, AdminAuditLogRow, AdminCompCodeRow, AdminHeldUploadRow, AdminMailCapRow, AdminReportRow, AdminSignupRow, AdminUserRow, AdminWaitlistRow, Item, OnboardingChecklist, Project, ReportStats, ScanHistoryDisplay, User, WaitlistStats, }; use super::CsrfTokenOption; // Dashboard Pages /// Main user dashboard page with tabbed navigation. #[derive(Template)] #[template(path = "dashboards/dashboard-user.html")] #[allow(dead_code)] // Fields used by Askama template pub struct DashboardUserTemplate { pub csrf_token: CsrfTokenOption, pub session_user: Option, pub user: User, /// The tab strip and its panels, described rather than written out here. /// /// `6b24f2df` step 5. Built by `crate::quasi::user_tabs`, which needs the /// shown panel's markup and the two membership tests. Four fields left with /// the strip: `transactions` and `projects` fed panels the strip's own /// builders now render, and `has_mt_memberships` and `git_enabled` gated /// sections of the settings sub-nav that step 4 already took. pub tabs: String, /// Onboarding checklist for new creators (None once all steps complete). pub onboarding: Option, /// Show "Show setup checklist" link when checklist was dismissed but steps remain. pub show_checklist_recovery: bool, // Suspension context (for banner) pub suspended: bool, pub suspension_reason: Option, pub has_pending_appeal: bool, pub appeal_decision: Option, pub appeal_response: Option, /// One-time warning when a breached password is detected (cleared after display). pub password_warning: Option, /// Whether the user has self-deactivated their account (limbo state). pub deactivated: bool, /// Whether this creator has voluntarily paused their account. pub creator_paused: bool, } /// Project dashboard page with stats, content list, and management tabs. #[derive(Template)] #[template(path = "dashboards/dashboard-project.html")] #[allow(dead_code)] // Fields used by Askama template pub struct DashboardProjectTemplate { pub csrf_token: CsrfTokenOption, pub session_user: Option, pub project: Project, /// The tab strip and its panels, described rather than written out here. /// /// `6b24f2df`. Built by `crate::quasi::project_tabs`, which needs the shown /// panel's markup and the two feature tests. Six fields left with the strip: /// `creator_username`, `stats`, `items`, `stripe_connected`, `has_blog` and /// the two gates. The template read none of them -- the gates decided which /// buttons it wrote, and the rest were built per request for nothing. pub tabs: String, } /// Item management dashboard shell with tabbed navigation. #[derive(Template)] #[template(path = "dashboards/dashboard-item.html")] pub struct DashboardItemTemplate { pub csrf_token: CsrfTokenOption, pub session_user: Option, pub item: Item, pub project_title: String, pub project_slug: String, /// The tab strip and its panels, described rather than written out here. /// /// `6b24f2df`. Built by `crate::quasi::item_tabs`, which needs the shown /// panel's markup and whether the item is a bundle, so the handler /// assembles it and this carries the answer. pub tabs: String, } // Admin /// Admin waitlist management page with filtering and invite controls. #[derive(Template)] #[template(path = "dashboards/admin-waitlist.html")] pub struct AdminWaitlistTemplate { pub csrf_token: CsrfTokenOption, pub session_user: Option, pub stats: WaitlistStats, pub entries: Vec, pub current_filter: String, pub admin_active_page: &'static str, } /// Admin user management page. #[derive(Template)] #[template(path = "dashboards/admin-users.html")] pub struct AdminUsersTemplate { pub csrf_token: CsrfTokenOption, pub session_user: Option, pub users: Vec, pub total_users: usize, pub total_suspended: usize, pub current_filter: String, pub current_page: i64, pub total_pages: i64, pub admin_active_page: &'static str, } /// Per-layer health stat displayed in the dashboard's top panel. #[derive(Clone)] pub struct LayerHealthCard { pub layer: String, pub total: i64, pub success_rate_pct: i32, pub error_rate_pct: i32, pub fail_count: i64, pub status_badge: &'static str, pub last_seen: String, } /// Admin upload review queue page. #[derive(Template)] #[template(path = "dashboards/admin-uploads.html")] pub struct AdminUploadsTemplate { pub csrf_token: CsrfTokenOption, pub session_user: Option, pub held_uploads: Vec, pub total_held: usize, pub admin_active_page: &'static str, pub layer_health: Vec, pub queue_pending: i64, pub queue_running: i64, pub recent_history: Vec, pub history_total: usize, } /// Full audit log for the scan pipeline (Phase 2b). #[derive(Template)] #[template(path = "dashboards/admin-scan-audit.html")] pub struct AdminScanAuditTemplate { pub csrf_token: CsrfTokenOption, pub session_user: Option, pub admin_active_page: &'static str, pub entries: Vec, pub filter_action: String, pub filter_admin: String, pub filter_since_days: String, } /// Admin appeals queue page. #[derive(Template)] #[template(path = "dashboards/admin-appeals.html")] pub struct AdminAppealsTemplate { pub csrf_token: CsrfTokenOption, pub session_user: Option, pub appeals: Vec, pub admin_active_page: &'static str, } /// Admin reports queue page. #[derive(Template)] #[template(path = "dashboards/admin-reports.html")] pub struct AdminReportsTemplate { pub csrf_token: CsrfTokenOption, pub session_user: Option, pub reports: Vec, pub stats: ReportStats, pub current_filter: String, pub admin_active_page: &'static str, } /// Admin page: the monthly mail allowance request queue. #[derive(Template)] #[template(path = "dashboards/admin-mail-caps.html")] pub struct AdminMailCapsTemplate { pub csrf_token: CsrfTokenOption, pub session_user: Option, pub entries: Vec, pub admin_active_page: &'static str, } /// Admin HTMX partial: the mail allowance queue table on its own, for the /// grant/deny actions to swap back in. #[derive(Template)] #[template(path = "partials/admin_mail_cap_entries.html")] pub struct AdminMailCapEntriesTemplate { pub csrf_token: CsrfTokenOption, pub entries: Vec, } /// Admin email signups page. #[derive(Template)] #[template(path = "dashboards/admin-signups.html")] pub struct AdminSignupsTemplate { pub csrf_token: CsrfTokenOption, pub session_user: Option, pub signups: Vec, pub total: i64, pub admin_active_page: &'static str, } /// Admin metrics dashboard page. #[derive(Template)] #[template(path = "dashboards/admin-metrics.html")] pub struct AdminMetricsTemplate { pub csrf_token: CsrfTokenOption, pub session_user: Option, pub admin_active_page: &'static str, pub uptime: String, pub total_requests: u64, pub error_rate: f64, pub total_errors: u64, pub pool_max: u32, pub pool_active: u32, pub pool_idle: u32, pub top_routes: Vec, pub error_breakdown: Vec, } /// Admin comp-codes dashboard page (mint form + status list). #[derive(Template)] #[template(path = "dashboards/admin-comp-codes.html")] pub struct AdminCompCodesTemplate { pub csrf_token: CsrfTokenOption, pub session_user: Option, pub admin_active_page: &'static str, pub comp_codes: Vec, } /// The comp-codes table body, re-rendered after a mint to refresh the list. #[derive(Template)] #[template(path = "partials/admin_comp_codes_entries.html")] pub struct AdminCompCodesEntriesTemplate { pub comp_codes: Vec, } /// A row in the top routes table. pub struct RouteMetric { pub method: String, pub path: String, pub status: String, pub count: u64, } /// A row in the error breakdown table. pub struct ErrorMetric { pub kind: String, pub count: u64, } // Export & Account Management /// Data export portal for the no-lock-in guarantee. #[derive(Template)] #[template(path = "dashboards/dashboard-export.html")] pub struct ExportPortalTemplate { pub csrf_token: CsrfTokenOption, pub session_user: Option, /// Whether the user has any exportable content (projects, items, files). pub has_content: bool, /// Human-readable total size of exportable data (e.g. "12.3 MB"). pub content_size: String, } /// Data import portal for migrating from other platforms. #[derive(Template)] #[template(path = "dashboards/dashboard-import.html")] pub struct ImportPortalTemplate { pub csrf_token: CsrfTokenOption, pub session_user: Option, pub projects: Vec, pub jobs: Vec, } /// Minimal project info for the import page project selector. pub struct ImportProjectOption { pub id: String, pub title: String, } /// A row in the import history table. pub struct ImportJobRow { pub source: String, pub status: String, /// Badge class for `status`, from `ImportJobStatus::badge_status`. pub status_tone: &'static str, pub total_rows: i32, pub created_rows: i32, pub created_at: chrono::DateTime, } /// Account deletion confirmation page with username verification. #[derive(Template)] #[template(path = "dashboards/dashboard-delete-account.html")] pub struct DeleteAccountTemplate { pub csrf_token: CsrfTokenOption, pub session_user: Option, pub username: String, } /// Blog post editor page (create/edit). #[derive(Template)] #[template(path = "dashboards/dashboard-blog-editor.html")] pub struct BlogEditorTemplate { pub csrf_token: CsrfTokenOption, pub session_user: Option, pub project_id: String, pub project_slug: String, pub editing: bool, pub post_id: String, pub post_title: String, pub post_slug: String, pub post_body: String, pub post_is_published: bool, /// Whether this editor is for the platform changelog project. Gates the /// owner-only "Show on landing" control so it never appears on a regular /// creator's blog, where the flag would be inert. pub is_changelog_project: bool, /// Current value of the post's landing flag (false for new posts). pub post_show_on_landing: bool, } /// HTMX partial: onboarding checklist (returned by the restore handler). #[derive(Template)] #[template(path = "partials/onboarding_checklist.html")] pub struct OnboardingChecklistPartialTemplate { pub checklist: OnboardingChecklist, } // License key and promo code view types live in crate::types (LicenseKeyRow, PromoCodeRow). // Creation Wizards /// Step navigation item for the wizard sidebar. pub struct StepNavItem { pub name: &'static str, pub label: &'static str, pub state: &'static str, // "completed", "active", "pending" } /// A subscription tier row for the wizard monetization/preview steps. pub struct WizardTierRow { pub id: String, pub name: String, pub price_display: String, pub price_dollars: String, pub description: String, } /// Full page: project creation wizard. #[derive(Template)] #[template(path = "wizards/wizard_project.html")] pub struct WizardProjectTemplate { pub csrf_token: CsrfTokenOption, pub session_user: Option, pub nav: Vec, pub project_features: &'static [(&'static str, &'static str, &'static str)], } /// Full page: item creation wizard. #[derive(Template)] #[template(path = "wizards/wizard_item.html")] pub struct WizardItemTemplate { pub csrf_token: CsrfTokenOption, pub session_user: Option, pub nav: Vec, pub project_slug: String, pub item_type_cards: Vec<(&'static str, &'static str, &'static str)>, } // --- Project step partials --- /// Wizard step partial: project basics (title, slug, features, category). #[derive(Template)] #[template(path = "wizards/steps/project/basics.html")] pub struct WizardProjectBasicsTemplate { pub nav: Vec, pub slug: String, pub project_features: &'static [(&'static str, &'static str, &'static str)], pub title: String, pub features: Vec, pub description: String, pub category_name: String, pub ai_tier: String, pub ai_disclosure: String, } /// Wizard step partial: project appearance (cover image upload). #[derive(Template)] #[template(path = "wizards/steps/project/appearance.html")] pub struct WizardProjectAppearanceTemplate { pub nav: Vec, pub slug: String, pub project_id: String, pub cover_image_url: Option, pub project_title: String, } /// Wizard step partial: project monetization (pricing model, tiers, Stripe). #[derive(Template)] #[template(path = "wizards/steps/project/monetization.html")] pub struct WizardProjectMonetizationTemplate { pub nav: Vec, pub slug: String, pub tiers: Vec, pub stripe_connected: bool, /// Current pricing model string value (free, buy_once, pwyw, subscription). pub pricing_model: String, /// Current fixed price in dollars (for buy_once). pub price_dollars: String, /// Current PWYW minimum in dollars. pub pwyw_min_dollars: String, } /// Wizard step partial: project first content prompt (item count gate). #[derive(Template)] #[template(path = "wizards/steps/project/first_content.html")] pub struct WizardProjectFirstContentTemplate { pub nav: Vec, pub slug: String, pub item_count: u32, } /// Wizard step partial: project preview and publish confirmation. #[derive(Template)] #[template(path = "wizards/steps/project/preview.html")] #[allow(dead_code)] pub struct WizardProjectPreviewTemplate { pub csrf_token: CsrfTokenOption, pub nav: Vec, pub slug: String, pub title: String, pub features: Vec, pub description: String, pub cover_image_url: Option, pub category_name: Option, pub tier_count: u32, pub item_count: u32, pub tiers: Vec, pub is_public: bool, /// Human-readable pricing display (e.g. "Free", "$9.99", "PWYW"). pub pricing_display: String, } // --- Item step partials --- /// Wizard step partial: item type selection (text, audio, video, software, bundle). #[derive(Template)] #[template(path = "wizards/steps/item/type.html")] pub struct WizardItemTypeTemplate { pub nav: Vec, pub project_slug: String, pub item_id: String, pub item_type_cards: Vec<(&'static str, &'static str, &'static str)>, pub selected_type: String, } /// Wizard step partial: item basics (title, description, cover image). #[derive(Template)] #[template(path = "wizards/steps/item/basics.html")] pub struct WizardItemBasicsTemplate { pub nav: Vec, pub project_slug: String, pub item_id: String, pub title: String, pub description: String, pub cover_image_url: Option, } /// Wizard step partial: item content (body editor, bundle picker). #[derive(Template)] #[template(path = "wizards/steps/item/content.html")] pub struct WizardItemContentTemplate { pub nav: Vec, pub project_slug: String, pub project_id: String, pub item_id: String, pub item_type: String, pub body: String, /// Non-bundle items in the project available for inclusion. pub bundleable_items: Vec, /// IDs of items already selected for this bundle. pub selected_bundle_ids: Vec, /// IDs of items currently marked unlisted. pub unlisted_ids: Vec, } /// Lightweight item info for the bundle item picker. pub struct BundleableItem { pub id: String, pub title: String, pub item_type: String, } /// Wizard step partial: item sections (reorderable content sections). #[derive(Template)] #[template(path = "wizards/steps/item/sections.html")] pub struct WizardItemSectionsTemplate { pub nav: Vec, pub project_slug: String, pub item_id: String, pub sections: Vec, } /// Wizard step partial: item pricing (model selection, price entry). #[derive(Template)] #[template(path = "wizards/steps/item/pricing.html")] pub struct WizardItemPricingTemplate { pub nav: Vec, pub project_slug: String, pub item_id: String, pub pricing_model: String, pub price_dollars: String, pub pwyw_suggested_dollars: String, pub pwyw_min_dollars: String, } /// Wizard step partial: item preview and publish confirmation. #[derive(Template)] #[template(path = "wizards/steps/item/preview.html")] pub struct WizardItemPreviewTemplate { pub csrf_token: CsrfTokenOption, pub nav: Vec, pub project_slug: String, pub item_id: String, pub title: String, pub item_type: String, pub description: String, pub price_display: String, pub tag_names: Vec, pub has_content: bool, pub is_public: bool, }