started implementing stripe
This commit is contained in:
149
templates/admin/customer_details_modal.html
Normal file
149
templates/admin/customer_details_modal.html
Normal file
@@ -0,0 +1,149 @@
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h6 class="mb-3">Customer Information</h6>
|
||||
<table class="table table-sm">
|
||||
<tr>
|
||||
<td><strong>Name:</strong></td>
|
||||
<td>{{ customer.name or 'N/A' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Email:</strong></td>
|
||||
<td>{{ customer.email }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Phone:</strong></td>
|
||||
<td>{{ customer.phone or 'N/A' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Created:</strong></td>
|
||||
<td>{{ customer.created_at.strftime('%Y-%m-%d %H:%M') if customer.created_at else 'N/A' }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<h6 class="mb-3">Subscription Information</h6>
|
||||
<table class="table table-sm">
|
||||
<tr>
|
||||
<td><strong>Plan:</strong></td>
|
||||
<td>
|
||||
{% if plan %}
|
||||
<span class="badge bg-primary">{{ plan.name }}</span>
|
||||
{% else %}
|
||||
<span class="text-muted">Plan {{ customer.subscription_plan_id or 'N/A' }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Status:</strong></td>
|
||||
<td>
|
||||
{% if customer.subscription_status %}
|
||||
{% if customer.subscription_status == 'active' %}
|
||||
<span class="badge bg-success">Active</span>
|
||||
{% elif customer.subscription_status == 'canceled' %}
|
||||
<span class="badge bg-danger">Canceled</span>
|
||||
{% elif customer.subscription_status == 'past_due' %}
|
||||
<span class="badge bg-warning">Past Due</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">{{ customer.subscription_status }}</span>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="text-muted">No subscription</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Billing Cycle:</strong></td>
|
||||
<td>
|
||||
{% if customer.subscription_billing_cycle %}
|
||||
<span class="badge bg-info">{{ customer.subscription_billing_cycle.title() }}</span>
|
||||
{% else %}
|
||||
<span class="text-muted">N/A</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Current Period:</strong></td>
|
||||
<td>
|
||||
{% if customer.subscription_current_period_start and customer.subscription_current_period_end %}
|
||||
{{ customer.subscription_current_period_start.strftime('%Y-%m-%d') }} to {{ customer.subscription_current_period_end.strftime('%Y-%m-%d') }}
|
||||
{% else %}
|
||||
<span class="text-muted">N/A</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if customer.billing_address_line1 or customer.shipping_address_line1 %}
|
||||
<div class="row mt-4">
|
||||
{% if customer.billing_address_line1 %}
|
||||
<div class="col-md-6">
|
||||
<h6 class="mb-3">Billing Address</h6>
|
||||
<address class="mb-0">
|
||||
{{ customer.billing_address_line1 }}<br>
|
||||
{% if customer.billing_address_line2 %}{{ customer.billing_address_line2 }}<br>{% endif %}
|
||||
{% if customer.billing_city %}{{ customer.billing_city }}{% endif %}
|
||||
{% if customer.billing_state %}, {{ customer.billing_state }}{% endif %}
|
||||
{% if customer.billing_postal_code %} {{ customer.billing_postal_code }}{% endif %}<br>
|
||||
{% if customer.billing_country %}{{ customer.billing_country }}{% endif %}
|
||||
</address>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if customer.shipping_address_line1 %}
|
||||
<div class="col-md-6">
|
||||
<h6 class="mb-3">Shipping Address</h6>
|
||||
<address class="mb-0">
|
||||
{{ customer.shipping_address_line1 }}<br>
|
||||
{% if customer.shipping_address_line2 %}{{ customer.shipping_address_line2 }}<br>{% endif %}
|
||||
{% if customer.shipping_city %}{{ customer.shipping_city }}{% endif %}
|
||||
{% if customer.shipping_state %}, {{ customer.shipping_state }}{% endif %}
|
||||
{% if customer.shipping_postal_code %} {{ customer.shipping_postal_code }}{% endif %}<br>
|
||||
{% if customer.shipping_country %}{{ customer.shipping_country }}{% endif %}
|
||||
</address>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if customer.tax_id_type and customer.tax_id_value %}
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<h6 class="mb-3">Tax Information</h6>
|
||||
<table class="table table-sm">
|
||||
<tr>
|
||||
<td><strong>Tax ID Type:</strong></td>
|
||||
<td>{{ customer.tax_id_type }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Tax ID Value:</strong></td>
|
||||
<td>{{ customer.tax_id_value }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if customer.stripe_customer_id or customer.stripe_subscription_id %}
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<h6 class="mb-3">Stripe Information</h6>
|
||||
<table class="table table-sm">
|
||||
{% if customer.stripe_customer_id %}
|
||||
<tr>
|
||||
<td><strong>Stripe Customer ID:</strong></td>
|
||||
<td><code>{{ customer.stripe_customer_id }}</code></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if customer.stripe_subscription_id %}
|
||||
<tr>
|
||||
<td><strong>Stripe Subscription ID:</strong></td>
|
||||
<td><code>{{ customer.stripe_subscription_id }}</code></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
178
templates/admin/customers.html
Normal file
178
templates/admin/customers.html
Normal file
@@ -0,0 +1,178 @@
|
||||
{% extends "common/base.html" %}
|
||||
{% from "components/header.html" import header %}
|
||||
|
||||
{% block title %}Customers - Admin{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{{ header(
|
||||
title="Customers",
|
||||
description="Manage customer information and subscriptions",
|
||||
icon="fa-users"
|
||||
) }}
|
||||
|
||||
<div class="container-fluid">
|
||||
{% if customers.items %}
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Email</th>
|
||||
<th>Phone</th>
|
||||
<th>Plan</th>
|
||||
<th>Status</th>
|
||||
<th>Billing Cycle</th>
|
||||
<th>Created</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for customer in customers.items %}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="avatar-sm me-3">
|
||||
<div class="avatar-title bg-primary rounded-circle">
|
||||
{{ customer.name[0] if customer.name else customer.email[0] }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="mb-0">{{ customer.name or 'N/A' }}</h6>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{ customer.email }}</td>
|
||||
<td>{{ customer.phone or 'N/A' }}</td>
|
||||
<td>
|
||||
{% if customer.subscription_plan_id %}
|
||||
{% set plan = customer.plan %}
|
||||
{% if plan %}
|
||||
<span class="badge bg-primary">{{ plan.name }}</span>
|
||||
{% else %}
|
||||
<span class="text-muted">Plan {{ customer.subscription_plan_id }}</span>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="text-muted">No plan</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if customer.subscription_status %}
|
||||
{% if customer.subscription_status == 'active' %}
|
||||
<span class="badge bg-success">Active</span>
|
||||
{% elif customer.subscription_status == 'canceled' %}
|
||||
<span class="badge bg-danger">Canceled</span>
|
||||
{% elif customer.subscription_status == 'past_due' %}
|
||||
<span class="badge bg-warning">Past Due</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">{{ customer.subscription_status }}</span>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="text-muted">No subscription</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if customer.subscription_billing_cycle %}
|
||||
<span class="badge bg-info">{{ customer.subscription_billing_cycle.title() }}</span>
|
||||
{% else %}
|
||||
<span class="text-muted">N/A</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ customer.created_at.strftime('%Y-%m-%d') if customer.created_at else 'N/A' }}</td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-outline-primary"
|
||||
onclick="viewCustomerDetails({{ customer.id }})">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
{% if customers.pages > 1 %}
|
||||
<nav aria-label="Customer pagination">
|
||||
<ul class="pagination justify-content-center">
|
||||
{% if customers.has_prev %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="{{ url_for('admin.customers', page=customers.prev_num) }}">Previous</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% for page_num in customers.iter_pages() %}
|
||||
{% if page_num %}
|
||||
{% if page_num != customers.page %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="{{ url_for('admin.customers', page=page_num) }}">{{ page_num }}</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item active">
|
||||
<span class="page-link">{{ page_num }}</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<li class="page-item disabled">
|
||||
<span class="page-link">...</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if customers.has_next %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="{{ url_for('admin.customers', page=customers.next_num) }}">Next</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="card">
|
||||
<div class="card-body text-center py-5">
|
||||
<i class="fas fa-users fa-3x text-muted mb-3"></i>
|
||||
<h5 class="text-muted">No customers found</h5>
|
||||
<p class="text-muted">Customers will appear here once they complete a purchase.</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Customer Details Modal -->
|
||||
<div class="modal fade" id="customerDetailsModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Customer Details</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="customerDetailsContent">
|
||||
<!-- Content will be loaded here -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function viewCustomerDetails(customerId) {
|
||||
// Load customer details via AJAX
|
||||
fetch(`/admin/customers/${customerId}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
document.getElementById('customerDetailsContent').innerHTML = data.html;
|
||||
new bootstrap.Modal(document.getElementById('customerDetailsModal')).show();
|
||||
} else {
|
||||
alert('Failed to load customer details');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Failed to load customer details');
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -1,4 +1,5 @@
|
||||
{% extends "common/base.html" %}
|
||||
{% from "components/header.html" import header %}
|
||||
|
||||
{% block title %}Support Articles - DocuPulse{% endblock %}
|
||||
|
||||
@@ -69,18 +70,24 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{{ header(
|
||||
title="Support Articles",
|
||||
description="Create and manage help articles for users",
|
||||
icon="fa-life-ring",
|
||||
buttons=[
|
||||
{
|
||||
'text': 'Create New Article',
|
||||
'url': '#',
|
||||
'onclick': 'showCreateArticleModal()',
|
||||
'icon': 'fa-plus',
|
||||
'class': 'btn-primary'
|
||||
}
|
||||
]
|
||||
) }}
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1 class="h3 mb-0" style="color: var(--primary-color);">
|
||||
<i class="fas fa-life-ring me-2"></i>Support Articles
|
||||
</h1>
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#createArticleModal">
|
||||
<i class="fas fa-plus me-2"></i>Create New Article
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Articles List -->
|
||||
<div class="row" id="articlesList">
|
||||
<!-- Articles will be loaded here via AJAX -->
|
||||
|
||||
290
templates/checkout_success.html
Normal file
290
templates/checkout_success.html
Normal file
@@ -0,0 +1,290 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Payment Successful - DocuPulse</title>
|
||||
<meta name="description" content="Your DocuPulse subscription has been activated successfully. Welcome to the future of document management.">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/colors.css') }}?v={{ 'css/colors.css'|asset_version }}">
|
||||
<link rel="stylesheet" href="{{ url_for('main.dynamic_colors') }}?v={{ site_settings.updated_at.timestamp() }}" onload="console.log('[CSS] Dynamic colors loaded with version:', '{{ site_settings.updated_at.timestamp() }}')">
|
||||
<style>
|
||||
.hero-section {
|
||||
background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
|
||||
color: white;
|
||||
padding: 120px 0 80px 0;
|
||||
}
|
||||
.success-card {
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
||||
background: var(--white);
|
||||
overflow: hidden;
|
||||
}
|
||||
.success-card .card-header {
|
||||
background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 1.5rem;
|
||||
font-weight: 600;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
.success-card .card-body {
|
||||
padding: 2rem;
|
||||
}
|
||||
.subscription-detail {
|
||||
padding: 0.75rem 0;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
.subscription-detail:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.subscription-detail strong {
|
||||
color: var(--text-dark);
|
||||
font-weight: 600;
|
||||
}
|
||||
.next-step-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.75rem 0;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
.next-step-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.next-step-item i {
|
||||
width: 24px;
|
||||
margin-right: 0.75rem;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
.next-step-item a {
|
||||
color: var(--text-dark);
|
||||
text-decoration: none;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
.next-step-item a:hover {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
.feature-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1.5rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.feature-item {
|
||||
text-align: center;
|
||||
padding: 1.25rem;
|
||||
background: var(--bg-color);
|
||||
border-radius: 12px;
|
||||
}
|
||||
.feature-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
margin: 0 auto 1rem;
|
||||
font-size: 1.25rem;
|
||||
box-shadow: 0 4px 12px rgba(var(--primary-color-rgb), 0.3);
|
||||
}
|
||||
.feature-item h6 {
|
||||
font-weight: 600;
|
||||
color: var(--text-dark);
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
.feature-item p {
|
||||
color: var(--text-muted);
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.4;
|
||||
margin: 0;
|
||||
}
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
|
||||
border: none;
|
||||
border-radius: 25px;
|
||||
padding: 12px 30px;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px var(--primary-opacity-15);
|
||||
filter: brightness(1.1);
|
||||
}
|
||||
.btn-outline-primary {
|
||||
border: 2px solid var(--primary-color);
|
||||
color: var(--primary-color);
|
||||
border-radius: 25px;
|
||||
padding: 12px 30px;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.btn-outline-primary:hover {
|
||||
background: rgba(var(--primary-color-rgb), 0.05);
|
||||
border-color: var(--primary-color);
|
||||
color: var(--primary-color);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(var(--primary-color-rgb), 0.1);
|
||||
}
|
||||
.section-title {
|
||||
color: var(--text-dark);
|
||||
font-weight: 700;
|
||||
margin-bottom: 1.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.section-title i {
|
||||
margin-right: 0.75rem;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
{% include 'components/header_nav.html' %}
|
||||
|
||||
<!-- Hero Section -->
|
||||
<section class="hero-section">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center text-center">
|
||||
<div class="col-lg-8">
|
||||
<div class="mb-4">
|
||||
<i class="fas fa-check-circle" style="font-size: 4rem;"></i>
|
||||
</div>
|
||||
<h1 class="display-4 fw-bold mb-3">Payment Successful!</h1>
|
||||
<p class="lead mb-4">Your subscription has been activated and your DocuPulse instance is being set up.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Success Details Section -->
|
||||
<section class="py-5">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-10">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card success-card h-100">
|
||||
<div class="card-header">
|
||||
<i class="fas fa-check-circle me-2"></i>
|
||||
Payment Confirmation
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if subscription_info %}
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h5 class="section-title">
|
||||
<i class="fas fa-receipt"></i>
|
||||
Subscription Details
|
||||
</h5>
|
||||
<div class="subscription-detail">
|
||||
<strong>Plan:</strong> {{ subscription_info.plan_name }}
|
||||
</div>
|
||||
<div class="subscription-detail">
|
||||
<strong>Billing Cycle:</strong> {{ subscription_info.billing_cycle.title() }}
|
||||
</div>
|
||||
<div class="subscription-detail">
|
||||
<strong>Status:</strong>
|
||||
<span class="badge bg-success">{{ subscription_info.status.title() }}</span>
|
||||
</div>
|
||||
<div class="subscription-detail">
|
||||
<strong>Amount:</strong> ${{ "%.2f"|format(subscription_info.amount) }} {{ subscription_info.currency.upper() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<h5 class="section-title">
|
||||
<i class="fas fa-rocket"></i>
|
||||
Next Steps
|
||||
</h5>
|
||||
<div class="next-step-item">
|
||||
<i class="fas fa-envelope"></i>
|
||||
<span>Check your email for login credentials</span>
|
||||
</div>
|
||||
<div class="next-step-item">
|
||||
<i class="fas fa-book"></i>
|
||||
<a href="{{ url_for('public.help_center') }}">Read our getting started guide</a>
|
||||
</div>
|
||||
{% if stripe_settings and stripe_settings.customer_portal_url %}
|
||||
<div class="next-step-item">
|
||||
<i class="fas fa-credit-card"></i>
|
||||
<a href="{{ stripe_settings.customer_portal_url }}" target="_blank">Manage your subscription & billing</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="next-step-item">
|
||||
<i class="fas fa-headset"></i>
|
||||
<a href="{{ url_for('public.contact') }}">Contact support if you need help</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center">
|
||||
<h5 class="mb-3">Thank you for your purchase!</h5>
|
||||
<p class="text-muted">Your payment has been processed successfully.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card success-card h-100">
|
||||
<div class="card-header">
|
||||
<i class="fas fa-info-circle me-2"></i>
|
||||
What happens next?
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="feature-grid">
|
||||
<div class="feature-item">
|
||||
<div class="feature-icon">
|
||||
<i class="fas fa-rocket"></i>
|
||||
</div>
|
||||
<h6>Instance Setup</h6>
|
||||
<p>Your DocuPulse instance will be automatically provisioned within the next few minutes.</p>
|
||||
</div>
|
||||
<div class="feature-item">
|
||||
<div class="feature-icon">
|
||||
<i class="fas fa-envelope"></i>
|
||||
</div>
|
||||
<h6>Welcome Email</h6>
|
||||
<p>You'll receive an email with your login credentials and setup instructions.</p>
|
||||
</div>
|
||||
<div class="feature-item">
|
||||
<div class="feature-icon">
|
||||
<i class="fas fa-headset"></i>
|
||||
</div>
|
||||
<h6>Support Available</h6>
|
||||
<p>Our support team is ready to help you get started with DocuPulse.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="text-center mt-4">
|
||||
<a href="{{ url_for('public.help_center') }}" class="btn btn-primary btn-lg me-3">
|
||||
<i class="fas fa-question-circle me-2"></i>Get Help
|
||||
</a>
|
||||
<a href="{{ url_for('public.contact') }}" class="btn btn-outline-primary btn-lg">
|
||||
<i class="fas fa-envelope me-2"></i>Contact Support
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% include 'components/footer_nav.html' %}
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -63,11 +63,9 @@
|
||||
<li><a class="dropdown-item" href="{{ url_for('main.settings') }}"><i class="fas fa-cog"></i> Settings</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
{% else %}
|
||||
{% if not is_master %}
|
||||
<li><a class="dropdown-item" href="{{ url_for('main.profile') }}"><i class="fas fa-user"></i> Profile</a></li>
|
||||
{% if current_user.is_admin %}
|
||||
<li><a class="dropdown-item" href="{{ url_for('main.settings') }}"><i class="fas fa-cog"></i> Settings</a></li>
|
||||
{% endif %}
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -105,6 +103,11 @@
|
||||
<i class="fas fa-life-ring"></i> Support Articles
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.endpoint == 'admin.customers' %}active{% endif %}" href="{{ url_for('admin.customers') }}">
|
||||
<i class="fas fa-users"></i> Customers
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.endpoint == 'contacts.contacts_list' %}active{% endif %}" href="{{ url_for('contacts.contacts_list') }}">
|
||||
@@ -153,6 +156,18 @@
|
||||
<i class="fas fa-user"></i> Profile
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="nav-item d-lg-none">
|
||||
<hr class="my-2">
|
||||
<a class="nav-link" href="{{ url_for('main.settings') }}">
|
||||
<i class="fas fa-cog"></i> Settings
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item d-lg-none">
|
||||
<a class="nav-link" href="{{ url_for('main.profile') }}">
|
||||
<i class="fas fa-user"></i> Profile
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="nav-item d-lg-none">
|
||||
<a class="nav-link" href="{{ url_for('auth.logout') }}">
|
||||
|
||||
@@ -8,6 +8,19 @@
|
||||
|
||||
{% set pricing_plans = PricingPlan.get_active_plans() %}
|
||||
{% if pricing_plans %}
|
||||
<!-- Debug info -->
|
||||
<div style="display: none;" id="pricing-debug">
|
||||
<h4>Debug: Pricing Plans Found</h4>
|
||||
{% for plan in pricing_plans %}
|
||||
<div>
|
||||
Plan: {{ plan.name }} (ID: {{ plan.id }})
|
||||
- Monthly Price ID: {{ plan.stripe_monthly_price_id or 'None' }}
|
||||
- Annual Price ID: {{ plan.stripe_annual_price_id or 'None' }}
|
||||
- Is Custom: {{ plan.is_custom }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="row g-4 justify-content-center">
|
||||
{% for plan in pricing_plans %}
|
||||
<div class="col-md-3">
|
||||
@@ -53,15 +66,16 @@
|
||||
{{ plan.button_text }}
|
||||
</a>
|
||||
{% else %}
|
||||
{% if plan.monthly_stripe_link or plan.annual_stripe_link %}
|
||||
<a href="{{ plan.monthly_stripe_link or plan.annual_stripe_link }}"
|
||||
class="btn {% if plan.is_popular %}btn-primary{% else %}btn-outline-primary{% endif %} btn-lg w-100 mt-auto px-4 py-3 payment-button"
|
||||
data-plan-id="{{ plan.id }}"
|
||||
data-monthly-link="{{ plan.monthly_stripe_link or '' }}"
|
||||
data-annual-link="{{ plan.annual_stripe_link or '' }}"
|
||||
target="_blank">
|
||||
{% if plan.stripe_monthly_price_id or plan.stripe_annual_price_id %}
|
||||
<button class="btn {% if plan.is_popular %}btn-primary{% else %}btn-outline-primary{% endif %} btn-lg w-100 mt-auto px-4 py-3 checkout-button"
|
||||
data-plan-id="{{ plan.id }}"
|
||||
data-monthly-product-id="{{ plan.stripe_monthly_price_id or '' }}"
|
||||
data-annual-product-id="{{ plan.stripe_annual_price_id or '' }}"
|
||||
data-plan-name="{{ plan.name }}"
|
||||
data-monthly-price="{{ plan.monthly_price or 0 }}"
|
||||
data-annual-price="{{ plan.annual_price or 0 }}">
|
||||
{{ plan.button_text }}
|
||||
</a>
|
||||
</button>
|
||||
{% else %}
|
||||
<a href="{{ contact_url }}" class="btn {% if plan.is_popular %}btn-primary{% else %}btn-outline-primary{% endif %} btn-lg w-100 mt-auto px-4 py-3">
|
||||
{{ plan.button_text }}
|
||||
@@ -98,7 +112,7 @@
|
||||
<div class="display-4 fw-bold mb-3" style="color: var(--primary-color);">
|
||||
<span class="monthly-price">€29</span>
|
||||
<span class="annual-price" style="display: none;">€23</span>
|
||||
<span class="fs-6 text-muted">/month</span>
|
||||
<span class="fs-6 text-muted price-period">/month</span>
|
||||
</div>
|
||||
<ul class="list-unstyled mb-4">
|
||||
<li class="mb-2"><i class="fas fa-check text-success me-2"></i>Up to 5 rooms</li>
|
||||
@@ -125,7 +139,7 @@
|
||||
<div class="display-4 fw-bold mb-3" style="color: var(--primary-color);">
|
||||
<span class="monthly-price">€99</span>
|
||||
<span class="annual-price" style="display: none;">€79</span>
|
||||
<span class="fs-6 text-muted">/month</span>
|
||||
<span class="fs-6 text-muted price-period">/month</span>
|
||||
</div>
|
||||
<ul class="list-unstyled mb-4">
|
||||
<li class="mb-2"><i class="fas fa-check text-success me-2"></i>Up to 25 rooms</li>
|
||||
@@ -147,7 +161,7 @@
|
||||
<div class="display-4 fw-bold mb-3" style="color: var(--primary-color);">
|
||||
<span class="monthly-price">€299</span>
|
||||
<span class="annual-price" style="display: none;">€239</span>
|
||||
<span class="fs-6 text-muted">/month</span>
|
||||
<span class="fs-6 text-muted price-period">/month</span>
|
||||
</div>
|
||||
<ul class="list-unstyled mb-4">
|
||||
<li class="mb-2"><i class="fas fa-check text-success me-2"></i>Up to 100 rooms</li>
|
||||
@@ -197,11 +211,31 @@
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Debug: Log pricing plans info
|
||||
console.log('=== PRICING DEBUG INFO ===');
|
||||
const checkoutButtons = document.querySelectorAll('.checkout-button');
|
||||
console.log('Found checkout buttons:', checkoutButtons.length);
|
||||
|
||||
checkoutButtons.forEach((button, index) => {
|
||||
console.log(`Button ${index + 1}:`, {
|
||||
planId: button.getAttribute('data-plan-id'),
|
||||
monthlyProductId: button.getAttribute('data-monthly-product-id'),
|
||||
annualProductId: button.getAttribute('data-annual-product-id'),
|
||||
planName: button.getAttribute('data-plan-name'),
|
||||
monthlyPrice: button.getAttribute('data-monthly-price'),
|
||||
annualPrice: button.getAttribute('data-annual-price')
|
||||
});
|
||||
});
|
||||
|
||||
// Show debug info if needed (uncomment to show)
|
||||
// document.getElementById('pricing-debug').style.display = 'block';
|
||||
|
||||
const billingToggle = document.getElementById('annualBilling');
|
||||
if (!billingToggle) return;
|
||||
|
||||
const monthlyPrices = document.querySelectorAll('.monthly-price');
|
||||
const annualPrices = document.querySelectorAll('.annual-price');
|
||||
const pricePeriods = document.querySelectorAll('.price-period');
|
||||
|
||||
// Add CSS for switch styling
|
||||
const style = document.createElement('style');
|
||||
@@ -247,6 +281,89 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
requestAnimationFrame(updateNumber);
|
||||
}
|
||||
|
||||
// Function to handle Stripe checkout
|
||||
async function handleCheckout(planId, billingCycle) {
|
||||
console.log('handleCheckout called with:', { planId, billingCycle });
|
||||
|
||||
try {
|
||||
const requestBody = {
|
||||
plan_id: planId,
|
||||
billing_cycle: billingCycle
|
||||
};
|
||||
console.log('Sending request to /api/create-checkout-session with body:', requestBody);
|
||||
|
||||
const response = await fetch('/api/create-checkout-session', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(requestBody)
|
||||
});
|
||||
|
||||
console.log('Response status:', response.status);
|
||||
console.log('Response ok:', response.ok);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
console.error('Response error text:', errorText);
|
||||
throw new Error(`Failed to create checkout session: ${response.status} ${errorText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log('Response data:', data);
|
||||
|
||||
if (data.checkout_url) {
|
||||
console.log('Redirecting to checkout URL:', data.checkout_url);
|
||||
window.location.href = data.checkout_url;
|
||||
} else {
|
||||
console.error('No checkout URL received in response');
|
||||
alert('Failed to create checkout session. Please try again.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Checkout error:', error);
|
||||
alert('Failed to start checkout. Please try again.');
|
||||
}
|
||||
}
|
||||
|
||||
// Add click handlers for checkout buttons
|
||||
document.querySelectorAll('.checkout-button').forEach(button => {
|
||||
console.log('Adding click handler to checkout button:', button);
|
||||
button.addEventListener('click', function() {
|
||||
console.log('Checkout button clicked!');
|
||||
console.log('Button data attributes:', {
|
||||
planId: this.getAttribute('data-plan-id'),
|
||||
monthlyProductId: this.getAttribute('data-monthly-product-id'),
|
||||
annualProductId: this.getAttribute('data-annual-product-id'),
|
||||
planName: this.getAttribute('data-plan-name'),
|
||||
monthlyPrice: this.getAttribute('data-monthly-price'),
|
||||
annualPrice: this.getAttribute('data-annual-price')
|
||||
});
|
||||
|
||||
const planId = this.getAttribute('data-plan-id');
|
||||
const monthlyProductId = this.getAttribute('data-monthly-product-id');
|
||||
const annualProductId = this.getAttribute('data-annual-product-id');
|
||||
const planName = this.getAttribute('data-plan-name');
|
||||
const monthlyPrice = parseFloat(this.getAttribute('data-monthly-price'));
|
||||
const annualPrice = parseFloat(this.getAttribute('data-annual-price'));
|
||||
|
||||
// Determine which billing cycle to use based on billing toggle
|
||||
const isAnnual = billingToggle.checked;
|
||||
const billingCycle = isAnnual ? 'annual' : 'monthly';
|
||||
|
||||
console.log('Billing toggle state:', { isAnnual, billingCycle });
|
||||
console.log('Plan ID:', planId);
|
||||
|
||||
if (planId) {
|
||||
console.log('Calling handleCheckout with planId and billingCycle');
|
||||
handleCheckout(planId, billingCycle);
|
||||
} else {
|
||||
console.log('No plan ID found, redirecting to contact form');
|
||||
// Fallback to contact form if no plan configured
|
||||
window.location.href = '{{ contact_url }}';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
billingToggle.addEventListener('change', function() {
|
||||
if (this.checked) {
|
||||
// Switch to annual prices with animation
|
||||
@@ -261,11 +378,10 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
animateNumber(price, monthlyValue, annualValue);
|
||||
});
|
||||
|
||||
// Update payment links to annual
|
||||
document.querySelectorAll('.payment-button').forEach(button => {
|
||||
const annualLink = button.getAttribute('data-annual-link');
|
||||
if (annualLink) {
|
||||
button.href = annualLink;
|
||||
// Update price periods to show "/year"
|
||||
document.querySelectorAll('.fs-6.text-muted, .price-period').forEach(period => {
|
||||
if (period.textContent.includes('/month')) {
|
||||
period.textContent = '/year';
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -278,15 +394,13 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
animateNumber(price, currentValue, originalMonthlyValue);
|
||||
});
|
||||
|
||||
// Update payment links to monthly
|
||||
document.querySelectorAll('.payment-button').forEach(button => {
|
||||
const monthlyLink = button.getAttribute('data-monthly-link');
|
||||
if (monthlyLink) {
|
||||
button.href = monthlyLink;
|
||||
// Update price periods to show "/month"
|
||||
document.querySelectorAll('.fs-6.text-muted, .price-period').forEach(period => {
|
||||
if (period.textContent.includes('/year')) {
|
||||
period.textContent = '/month';
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
@@ -140,7 +140,7 @@
|
||||
{% if is_master %}
|
||||
<!-- Connections Tab -->
|
||||
<div class="tab-pane fade {% if active_tab == 'connections' %}show active{% endif %}" id="connections" role="tabpanel" aria-labelledby="connections-tab">
|
||||
{{ connections_tab(portainer_settings, nginx_settings, site_settings, git_settings, cloudflare_settings) }}
|
||||
{{ connections_tab(portainer_settings, nginx_settings, site_settings, git_settings, cloudflare_settings, stripe_settings) }}
|
||||
</div>
|
||||
|
||||
<!-- Pricing Tab -->
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{% from "settings/components/connection_modals.html" import connection_modals %}
|
||||
|
||||
{% macro connections_tab(portainer_settings, nginx_settings, site_settings, git_settings, cloudflare_settings) %}
|
||||
{% macro connections_tab(portainer_settings, nginx_settings, site_settings, git_settings, cloudflare_settings, stripe_settings) %}
|
||||
<!-- Meta tags for JavaScript -->
|
||||
<meta name="management-api-key" content="{{ site_settings.management_api_key }}">
|
||||
<meta name="git-settings" content="{{ git_settings|tojson|safe }}">
|
||||
@@ -212,6 +212,67 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stripe Connection Card -->
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0">
|
||||
<i class="fab fa-stripe me-2"></i>Stripe Connection
|
||||
</h5>
|
||||
<button class="btn btn-sm btn-outline-primary" onclick="testStripeConnection()">
|
||||
<i class="fas fa-plug me-1"></i>Test Connection
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="stripeForm" onsubmit="saveStripeConnection(event)">
|
||||
<div class="mb-3">
|
||||
<label for="stripePublishableKey" class="form-label">Publishable Key</label>
|
||||
<input type="text" class="form-control" id="stripePublishableKey" name="stripePublishableKey"
|
||||
placeholder="pk_test_..." required
|
||||
value="{{ stripe_settings.publishable_key if stripe_settings and stripe_settings.publishable_key else '' }}">
|
||||
<div class="form-text">Your Stripe publishable key (starts with pk_test_ or pk_live_)</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="stripeSecretKey" class="form-label">Secret Key</label>
|
||||
<input type="password" class="form-control" id="stripeSecretKey" name="stripeSecretKey"
|
||||
placeholder="sk_test_..." required
|
||||
value="{{ stripe_settings.secret_key if stripe_settings and stripe_settings.secret_key else '' }}">
|
||||
<div class="form-text">Your Stripe secret key (starts with sk_test_ or sk_live_)</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="stripeWebhookSecret" class="form-label">Webhook Secret (Optional)</label>
|
||||
<input type="password" class="form-control" id="stripeWebhookSecret" name="stripeWebhookSecret"
|
||||
placeholder="whsec_..."
|
||||
value="{{ stripe_settings.webhook_secret if stripe_settings and stripe_settings.webhook_secret else '' }}">
|
||||
<div class="form-text">Webhook endpoint secret for secure event handling</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="stripeCustomerPortalUrl" class="form-label">Customer Portal URL</label>
|
||||
<input type="url" class="form-control" id="stripeCustomerPortalUrl" name="stripeCustomerPortalUrl"
|
||||
placeholder="https://billing.stripe.com/p/login/..."
|
||||
value="{{ stripe_settings.customer_portal_url if stripe_settings and stripe_settings.customer_portal_url else '' }}">
|
||||
<div class="form-text">URL for customers to manage their subscriptions and billing</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="stripeTestMode" name="stripeTestMode"
|
||||
{% if stripe_settings and stripe_settings.test_mode %}checked{% endif %}>
|
||||
<label class="form-check-label" for="stripeTestMode">
|
||||
Test Mode (Use test keys)
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-text">Enable this to use Stripe test mode for development</div>
|
||||
</div>
|
||||
<div class="d-flex justify-content-end">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fas fa-save me-1"></i>Save Stripe Settings
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Save Connection Modal -->
|
||||
|
||||
@@ -53,28 +53,32 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stripe Payment Links -->
|
||||
{% if plan.monthly_stripe_link or plan.annual_stripe_link %}
|
||||
<!-- Stripe Integration Info -->
|
||||
{% if plan.stripe_product_id or plan.stripe_monthly_price_id or plan.stripe_annual_price_id %}
|
||||
<div class="mb-3">
|
||||
<strong>Payment Links:</strong>
|
||||
<strong>Stripe Integration:</strong>
|
||||
<div class="mt-2">
|
||||
{% if plan.monthly_stripe_link %}
|
||||
{% if plan.stripe_product_id %}
|
||||
<div class="mb-1">
|
||||
<small class="text-muted">
|
||||
<i class="fas fa-credit-card me-1"></i>Monthly:
|
||||
<a href="{{ plan.monthly_stripe_link }}" target="_blank" class="text-primary">
|
||||
Stripe Payment Link
|
||||
</a>
|
||||
<i class="fas fa-tag me-1"></i>Product ID:
|
||||
<code class="text-primary">{{ plan.stripe_product_id }}</code>
|
||||
</small>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if plan.annual_stripe_link %}
|
||||
{% if plan.stripe_monthly_price_id %}
|
||||
<div class="mb-1">
|
||||
<small class="text-muted">
|
||||
<i class="fas fa-credit-card me-1"></i>Annual:
|
||||
<a href="{{ plan.annual_stripe_link }}" target="_blank" class="text-primary">
|
||||
Stripe Payment Link
|
||||
</a>
|
||||
<i class="fas fa-credit-card me-1"></i>Monthly Price ID:
|
||||
<code class="text-primary">{{ plan.stripe_monthly_price_id }}</code>
|
||||
</small>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if plan.stripe_annual_price_id %}
|
||||
<div class="mb-1">
|
||||
<small class="text-muted">
|
||||
<i class="fas fa-credit-card me-1"></i>Annual Price ID:
|
||||
<code class="text-primary">{{ plan.stripe_annual_price_id }}</code>
|
||||
</small>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -91,10 +95,6 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<strong>Button:</strong> {{ plan.button_text }} → {{ plan.button_url }}
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input plan-popular-toggle" type="checkbox"
|
||||
@@ -251,22 +251,27 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stripe Payment Links Section -->
|
||||
<!-- Stripe Product/Price IDs Section -->
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-4">
|
||||
<div class="mb-3">
|
||||
<label for="monthlyStripeLink" class="form-label">Monthly Stripe Payment Link</label>
|
||||
<input type="url" class="form-control" id="monthlyStripeLink" name="monthly_stripe_link"
|
||||
placeholder="https://buy.stripe.com/...">
|
||||
<small class="text-muted">Stripe payment link for monthly billing</small>
|
||||
<label for="stripeProductId" class="form-label">Stripe Product ID</label>
|
||||
<input type="text" class="form-control" id="stripeProductId" name="stripe_product_id" placeholder="prod_xxx">
|
||||
<small class="text-muted">The Stripe Product ID for this plan</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-4">
|
||||
<div class="mb-3">
|
||||
<label for="annualStripeLink" class="form-label">Annual Stripe Payment Link</label>
|
||||
<input type="url" class="form-control" id="annualStripeLink" name="annual_stripe_link"
|
||||
placeholder="https://buy.stripe.com/...">
|
||||
<small class="text-muted">Stripe payment link for annual billing</small>
|
||||
<label for="stripeMonthlyPriceId" class="form-label">Stripe Monthly Price ID</label>
|
||||
<input type="text" class="form-control" id="stripeMonthlyPriceId" name="stripe_monthly_price_id" placeholder="price_xxx">
|
||||
<small class="text-muted">The Stripe Price ID for monthly billing</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="mb-3">
|
||||
<label for="stripeAnnualPriceId" class="form-label">Stripe Annual Price ID</label>
|
||||
<input type="text" class="form-control" id="stripeAnnualPriceId" name="stripe_annual_price_id" placeholder="price_xxx">
|
||||
<small class="text-muted">The Stripe Price ID for annual billing</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -411,22 +416,27 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stripe Payment Links Section -->
|
||||
<!-- Stripe Product/Price IDs Section -->
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-4">
|
||||
<div class="mb-3">
|
||||
<label for="editMonthlyStripeLink" class="form-label">Monthly Stripe Payment Link</label>
|
||||
<input type="url" class="form-control" id="editMonthlyStripeLink" name="monthly_stripe_link"
|
||||
placeholder="https://buy.stripe.com/...">
|
||||
<small class="text-muted">Stripe payment link for monthly billing</small>
|
||||
<label for="stripeProductId" class="form-label">Stripe Product ID</label>
|
||||
<input type="text" class="form-control" id="stripeProductId" name="stripe_product_id" placeholder="prod_xxx">
|
||||
<small class="text-muted">The Stripe Product ID for this plan</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-4">
|
||||
<div class="mb-3">
|
||||
<label for="editAnnualStripeLink" class="form-label">Annual Stripe Payment Link</label>
|
||||
<input type="url" class="form-control" id="editAnnualStripeLink" name="annual_stripe_link"
|
||||
placeholder="https://buy.stripe.com/...">
|
||||
<small class="text-muted">Stripe payment link for annual billing</small>
|
||||
<label for="stripeMonthlyPriceId" class="form-label">Stripe Monthly Price ID</label>
|
||||
<input type="text" class="form-control" id="stripeMonthlyPriceId" name="stripe_monthly_price_id" placeholder="price_xxx">
|
||||
<small class="text-muted">The Stripe Price ID for monthly billing</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="mb-3">
|
||||
<label for="stripeAnnualPriceId" class="form-label">Stripe Annual Price ID</label>
|
||||
<input type="text" class="form-control" id="stripeAnnualPriceId" name="stripe_annual_price_id" placeholder="price_xxx">
|
||||
<small class="text-muted">The Stripe Price ID for annual billing</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user